11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
20PROMEKI_NAMESPACE_BEGIN
69 BlinkingUnderline = 3,
89 enum AnsiColor : uint8_t {
126 DeepSkyBlue4_23 = 23,
127 DeepSkyBlue4_24 = 24,
128 DeepSkyBlue4_25 = 25,
134 DeepSkyBlue3_31 = 31,
135 DeepSkyBlue3_32 = 32,
138 SpringGreen3_35 = 35,
144 SpringGreen3_41 = 41,
145 SpringGreen2_42 = 42,
150 SpringGreen2_47 = 47,
152 MediumSpringGreen = 49,
168 DarkSeaGreen4_65 = 65,
174 DarkSeaGreen4_71 = 71,
183 MediumTurquoise = 80,
200 MediumPurple3_97 = 97,
201 MediumPurple3_98 = 98,
206 LightSlateGrey = 103,
208 LightSlateBlue = 105,
210 DarkOliveGreen3_107 = 107,
212 LightSkyBlue3_109 = 109,
213 LightSkyBlue3_110 = 110,
215 Chartreuse2_112 = 112,
216 DarkOliveGreen3_113 = 113,
217 PaleGreen3_114 = 114,
218 DarkSeaGreen3_115 = 115,
219 DarkSlateGray3 = 116,
222 LightGreen_119 = 119,
223 LightGreen_120 = 120,
224 PaleGreen1_121 = 121,
225 Aquamarine1_122 = 122,
226 DarkSlateGray1 = 123,
229 MediumVioletRed = 126,
231 DarkViolet_128 = 128,
233 DarkOrange3_130 = 130,
238 MediumPurple2_135 = 135,
240 LightSalmon3_137 = 137,
243 MediumPurple2_140 = 140,
249 LightSteelBlue3 = 146,
250 LightSteelBlue = 147,
252 DarkOliveGreen3_149 = 149,
253 DarkSeaGreen3_150 = 150,
254 DarkSeaGreen2_151 = 151,
258 DarkOliveGreen2 = 155,
259 PaleGreen1_156 = 156,
260 DarkSeaGreen2_157 = 157,
261 DarkSeaGreen1_158 = 158,
262 PaleTurquoise1 = 159,
269 DarkOrange3_166 = 166,
274 MediumOrchid1_171 = 171,
276 LightSalmon3_173 = 173,
282 LightGoldenrod3 = 179,
289 LightGoldenrod2_186 = 186,
292 LightSteelBlue1 = 189,
294 DarkOliveGreen1_191 = 191,
295 DarkOliveGreen1_192 = 192,
296 DarkSeaGreen1_193 = 193,
306 IndianRed1_203 = 203,
307 IndianRed1_204 = 204,
310 MediumOrchid1_207 = 207,
314 PaleVioletRed1 = 211,
324 LightGoldenrod2_221 = 221,
325 LightGoldenrod2_222 = 222,
330 LightGoldenrod1 = 227,
368 static Color ansiColor(
int index);
375 static Color ansiColor(AnsiColor color) {
return ansiColor(
static_cast<int>(color)); }
389 static AnsiColor findClosestAnsiColor(
const Color &color,
int maxIndex = 255);
406 static String resetSeq();
415 static String styleSeq(TextStyle style,
bool enable =
true);
418 static String foregroundSeq(AnsiColor color);
420 static String backgroundSeq(AnsiColor color);
422 static String foreground256Seq(uint8_t index);
424 static String background256Seq(uint8_t index);
426 static String foregroundRGBSeq(uint8_t r, uint8_t g, uint8_t b);
428 static String backgroundRGBSeq(uint8_t r, uint8_t g, uint8_t b);
444 static String foregroundSeq(
const Color &color, Terminal::ColorSupport support);
446 static String backgroundSeq(
const Color &color, Terminal::ColorSupport support);
454 static String hyperlinkSeq(
const String &url,
const String &text);
462 static bool stdoutWindowSize(
int &rows,
int &cols);
468 static bool stdoutSupportsANSI();
474 static bool stderrSupportsANSI();
480 AnsiStream(IODevice *device) : _device(device), _enabled(true) {}
488 void setAnsiEnabled(
bool val) {
497 IODevice *device()
const {
return _device; }
504 AnsiStream &write(
const String &text);
511 AnsiStream &write(
const char *text);
518 AnsiStream &write(
char ch);
525 AnsiStream &write(
int val);
532 AnsiStream &write(int64_t val);
542 AnsiStream &write(uint64_t val);
549 AnsiStream &write(
double val);
557 AnsiStream &operator<<(
const String &text) {
return write(text); }
559 AnsiStream &operator<<(
const char *text) {
return write(text); }
561 AnsiStream &operator<<(
char ch) {
return write(ch); }
563 AnsiStream &operator<<(
int val) {
return write(val); }
565 AnsiStream &operator<<(int64_t val) {
return write(val); }
567 AnsiStream &operator<<(uint64_t val) {
return write(val); }
569 AnsiStream &operator<<(
double val) {
return write(val); }
581 AnsiStream &setForeground(AnsiColor color);
593 AnsiStream &setBackground(AnsiColor color);
601 AnsiStream &setForeground(
const Color &color,
int maxIndex);
609 AnsiStream &setBackground(
const Color &color,
int maxIndex);
624 AnsiStream &setForeground(
const Color &color, Terminal::ColorSupport support);
627 AnsiStream &setBackground(
const Color &color, Terminal::ColorSupport support);
636 AnsiStream &setForeground(
const Color &color) {
637 return setForeground(color, Terminal::colorSupport());
647 AnsiStream &setBackground(
const Color &color) {
648 return setBackground(color, Terminal::colorSupport());
658 AnsiStream &setStyle(TextStyle style,
bool enable =
true) {
659 if (!_enabled)
return *
this;
660 return write(styleSeq(style, enable));
668 AnsiStream &cursorUp(
int n) {
669 if (!_enabled)
return *
this;
670 *
this <<
"\033[" << n <<
"A";
679 AnsiStream &cursorDown(
int n) {
680 if (!_enabled)
return *
this;
681 *
this <<
"\033[" << n <<
"B";
690 AnsiStream &cursorRight(
int n) {
691 if (!_enabled)
return *
this;
692 *
this <<
"\033[" << n <<
"C";
701 AnsiStream &cursorLeft(
int n) {
702 if (!_enabled)
return *
this;
703 *
this <<
"\033[" << n <<
"D";
712 AnsiStream &cursorNextLine(
int n) {
713 if (!_enabled)
return *
this;
714 *
this <<
"\033[" << n <<
"E";
723 AnsiStream &cursorPrevLine(
int n) {
724 if (!_enabled)
return *
this;
725 *
this <<
"\033[" << n <<
"F";
734 AnsiStream &setCursorColumn(
int c) {
735 if (!_enabled)
return *
this;
736 *
this <<
"\033[" << c <<
"G";
744 AnsiStream &cursorHome() {
745 if (!_enabled)
return *
this;
755 AnsiStream &setCursorStyle(CursorStyle style) {
756 if (!_enabled)
return *
this;
757 *
this <<
"\033[" <<
static_cast<int>(style) <<
" q";
767 AnsiStream &setCursorPosition(
int r,
int c) {
768 if (!_enabled)
return *
this;
769 *
this <<
"\033[" << r <<
";" << c <<
"H";
777 AnsiStream &clearScreen() {
778 if (!_enabled)
return *
this;
787 AnsiStream &clearScreenAndHome() {
788 if (!_enabled)
return *
this;
789 *
this <<
"\033[2J\033[H";
797 AnsiStream &clearScreenBeforeCursor() {
798 if (!_enabled)
return *
this;
807 AnsiStream &clearScreenAfterCursor() {
808 if (!_enabled)
return *
this;
817 AnsiStream &clearScrollback() {
818 if (!_enabled)
return *
this;
828 AnsiStream &insertLines(
int n) {
829 if (!_enabled)
return *
this;
830 *
this <<
"\033[" << n <<
"L";
839 AnsiStream &deleteLines(
int n) {
840 if (!_enabled)
return *
this;
841 *
this <<
"\033[" << n <<
"M";
850 AnsiStream &insertCharacters(
int n) {
851 if (!_enabled)
return *
this;
852 *
this <<
"\033[" << n <<
"@";
861 AnsiStream &deleteCharacters(
int n) {
862 if (!_enabled)
return *
this;
863 *
this <<
"\033[" << n <<
"P";
871 AnsiStream &moveToStartOfLine() {
872 if (!_enabled)
return *
this;
881 AnsiStream &moveToEndOfLine() {
882 if (!_enabled)
return *
this;
883 *
this <<
"\033[999G";
891 AnsiStream &clearLine() {
892 if (!_enabled)
return *
this;
901 AnsiStream &clearLineBeforeCursor() {
902 if (!_enabled)
return *
this;
911 AnsiStream &clearLineAfterCursor() {
912 if (!_enabled)
return *
this;
921 AnsiStream &reset() {
922 if (!_enabled)
return *
this;
931 AnsiStream &resetForeground() {
932 if (!_enabled)
return *
this;
941 AnsiStream &resetBackground() {
942 if (!_enabled)
return *
this;
951 AnsiStream &showCursor() {
952 if (!_enabled)
return *
this;
953 *
this <<
"\033[?25h";
961 AnsiStream &hideCursor() {
962 if (!_enabled)
return *
this;
963 *
this <<
"\033[?25l";
971 AnsiStream &saveCursorPosition() {
972 if (!_enabled)
return *
this;
982 AnsiStream &restoreCursorPosition() {
983 if (!_enabled)
return *
this;
994 AnsiStream &enableScrollingRegion(
int startRow,
int endRow) {
995 if (!_enabled)
return *
this;
996 *
this <<
"\033[" << startRow <<
";" << endRow <<
"r";
1004 AnsiStream &resetScrollingRegion() {
1005 if (!_enabled)
return *
this;
1015 AnsiStream &scrollUp(
int n) {
1016 if (!_enabled)
return *
this;
1017 *
this <<
"\033[" << n <<
"S";
1026 AnsiStream &scrollDown(
int n) {
1027 if (!_enabled)
return *
this;
1028 *
this <<
"\033[" << n <<
"T";
1037 AnsiStream &eraseCharacters(
int n) {
1038 if (!_enabled)
return *
this;
1039 *
this <<
"\033[" << n <<
"X";
1053 AnsiStream &setForeground256(uint8_t index) {
1054 if (!_enabled)
return *
this;
1055 return write(foreground256Seq(index));
1068 AnsiStream &setBackground256(uint8_t index) {
1069 if (!_enabled)
return *
this;
1070 return write(background256Seq(index));
1080 AnsiStream &setForegroundRGB(uint8_t r, uint8_t g, uint8_t b) {
1081 if (!_enabled)
return *
this;
1082 return write(foregroundRGBSeq(r, g, b));
1092 AnsiStream &setBackgroundRGB(uint8_t r, uint8_t g, uint8_t b) {
1093 if (!_enabled)
return *
this;
1094 return write(backgroundRGBSeq(r, g, b));
1107 AnsiStream &hyperlink(
const String &url,
const String &text);
1114 AnsiStream &setWindowTitle(
const String &title);
1125 AnsiStream ©ToClipboard(
const String &text);
1136 AnsiStream &enableMouseTracking(MouseTracking mode = MouseDrag) {
1137 if (!_enabled)
return *
this;
1138 *
this <<
"\033[?1000h";
1139 if (mode == MouseDrag) *
this <<
"\033[?1002h";
1140 if (mode == MouseAny) *
this <<
"\033[?1003h";
1141 *
this <<
"\033[?1006h";
1153 AnsiStream &disableMouseTracking() {
1154 if (!_enabled)
return *
this;
1155 *
this <<
"\033[?1006l\033[?1003l\033[?1002l\033[?1000l";
1170 AnsiStream &beginSynchronizedUpdate() {
1171 if (!_enabled)
return *
this;
1172 *
this <<
"\033[?2026h";
1181 AnsiStream &endSynchronizedUpdate() {
1182 if (!_enabled)
return *
this;
1183 *
this <<
"\033[?2026l";
1191 AnsiStream &enableBracketedPaste() {
1192 if (!_enabled)
return *
this;
1193 *
this <<
"\033[?2004h";
1201 AnsiStream &disableBracketedPaste() {
1202 if (!_enabled)
return *
this;
1203 *
this <<
"\033[?2004l";
1217 AnsiStream &enableFocusReporting() {
1218 if (!_enabled)
return *
this;
1219 *
this <<
"\033[?1004h";
1227 AnsiStream &disableFocusReporting() {
1228 if (!_enabled)
return *
this;
1229 *
this <<
"\033[?1004l";
1241 AnsiStream &bell() {
1250 AnsiStream &softReset() {
1251 if (!_enabled)
return *
this;
1260 AnsiStream &hardReset() {
1261 if (!_enabled)
return *
this;
1270 AnsiStream &useAlternateScreenBuffer() {
1271 if (!_enabled)
return *
this;
1272 *
this <<
"\033[?1049h";
1280 AnsiStream &useMainScreenBuffer() {
1281 if (!_enabled)
return *
this;
1282 *
this <<
"\033[?1049l";
1293 bool getCursorPosition(IODevice *input,
int &row,
int &col);
1313 explicit StyleScope(AnsiStream &stream) : _stream(stream) {}
1315 ~StyleScope() { _stream.reset(); }
1316 StyleScope(
const StyleScope &) =
delete;
1317 StyleScope &operator=(
const StyleScope &) =
delete;
1320 AnsiStream &_stream;
1328PROMEKI_NAMESPACE_END