36 #if defined(__unix__) || defined(__APPLE__)
39 #include <sys/ioctl.h>
42 static struct termios stored_settings;
44 static void setConsoleSettingsForAnsiRequest(
void) {
45 struct termios new_settings;
46 tcgetattr(0, &stored_settings);
47 new_settings = stored_settings;
48 new_settings.c_lflag &= ~ICANON;
49 new_settings.c_lflag &= ~ECHO;
50 tcsetattr(0, TCSANOW, &new_settings);
53 static void resetConsoleSettings(
void) {
54 tcsetattr(0, TCSANOW, &stored_settings);
57 static bool processInForeground(
void) {
58 pid_t fg = tcgetpgrp(STDIN_FILENO);
59 return fg == getpgrp();
63 static std::pair<int, int> getConsoleCursorPosition() {
66 if (isatty(fileno(stdin)) && processInForeground()) {
67 setConsoleSettingsForAnsiRequest();
68 fprintf(stdout,
"\x1b[6n");
70 if (fscanf(stdin,
"\x1b[%d;%dR", &row, &col)) {}
72 resetConsoleSettings();
75 return std::make_pair(row, col);
78 static std::pair<int, int> getConsoleSize() {
82 if (ioctl(0,TIOCGWINSZ,&ws)==0) {
87 return std::make_pair(rows, cols);
92 inline std::pair<int, int> getConsoleCursorPosition() {
94 CONSOLE_SCREEN_BUFFER_INFO SBInfo;
96 if(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &SBInfo)) {
97 row = SBInfo.dwCursorPosition.Y;
98 col = SBInfo.dwCursorPosition.X;
101 return std::make_pair(row, col);
104 inline std::pair<int, int> getConsoleSize() {
105 int rows=200, cols=200;
106 CONSOLE_SCREEN_BUFFER_INFO SBInfo;
108 if(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &SBInfo)) {
109 rows = SBInfo.dwSize.Y;
110 cols = SBInfo.dwSize.X-1;
113 return std::make_pair(rows, cols);
118 enum TextEffect {NORMAL=1, BOLD=2, UNDERLINED=4, BLINK=8};
120 enum TextColor {BLACK, RED, GREEN, YELLOW, BLUE,
121 MAGENTA, CYAN, LIGHT_GRAY, DARK_GRAY,
122 LIGHT_RED, LIGHT_GREEN, LIGHT_YELLOW,
123 LIGHT_BLUE, LIGHT_MAGENTA, LIGHT_CYAN, WHITE
126 class TextFgColorSetup {
130 TextFgColorSetup(TextColor color) :
136 class TextBgColorSetup {
140 TextBgColorSetup(TextColor color) :
146 class TextEffectSetup {
150 TextEffectSetup(
int effect) :
158 static std::map<TextColor, std::string> initAnsiFgColors() {
159 const char *colorterm = getenv(
"COLORTERM");
160 bool rxvt = colorterm && std::string(colorterm).find(
"rxvt") != std::string::npos;
161 std::map<TextColor, std::string> ret;
169 ret[LIGHT_GRAY] =
"37";
170 ret[DARK_GRAY] = rxvt ? ret[BLACK] :
"90";
171 ret[LIGHT_RED] = rxvt ? ret[RED] :
"91";
172 ret[LIGHT_GREEN] = rxvt ? ret[GREEN] :
"92";
173 ret[LIGHT_YELLOW] = rxvt ? ret[YELLOW] :
"93";
174 ret[LIGHT_BLUE] = rxvt ? ret[BLUE] :
"94";
175 ret[LIGHT_MAGENTA] = rxvt ? ret[MAGENTA] :
"95";
176 ret[LIGHT_CYAN] = rxvt ? ret[CYAN] :
"96";
177 ret[WHITE] = rxvt ? ret[LIGHT_GRAY] :
"97";
181 static std::map<TextColor, std::string> initAnsiBgColors() {
182 const char *colorterm = getenv(
"COLORTERM");
183 bool rxvt = colorterm && std::string(colorterm).find(
"rxvt") != std::string::npos;
184 std::map<TextColor, std::string> ret;
192 ret[LIGHT_GRAY] =
"47";
193 ret[DARK_GRAY] = rxvt ? ret[BLACK] :
"100";
194 ret[LIGHT_RED] = rxvt ? ret[RED] :
"101";
195 ret[LIGHT_GREEN] = rxvt ? ret[GREEN] :
"102";
196 ret[LIGHT_YELLOW] = rxvt ? ret[YELLOW] :
"103";
197 ret[LIGHT_BLUE] = rxvt ? ret[BLUE] :
"104";
198 ret[LIGHT_MAGENTA] = rxvt ? ret[MAGENTA] :
"105";
199 ret[LIGHT_CYAN] = rxvt ? ret[CYAN] :
"106";
200 ret[WHITE] = rxvt ? ret[LIGHT_GRAY] :
"107";
204 static std::map<TextColor, std::string> ansiFgColors = initAnsiFgColors();
205 static std::map<TextColor, std::string> ansiBgColors = initAnsiBgColors();
208 static std::map<TextColor, int> initCrtFgColors() {
209 std::map<TextColor, int> ret;
211 ret[RED] = FOREGROUND_RED;
212 ret[GREEN] = FOREGROUND_GREEN;
213 ret[YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN;
214 ret[BLUE] = FOREGROUND_BLUE;
215 ret[MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED;
216 ret[CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE;
217 ret[LIGHT_GRAY]= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
218 ret[DARK_GRAY] = FOREGROUND_INTENSITY;
219 ret[LIGHT_RED] = FOREGROUND_RED | FOREGROUND_INTENSITY;
220 ret[LIGHT_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
221 ret[LIGHT_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
222 ret[LIGHT_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
223 ret[LIGHT_MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
224 ret[LIGHT_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
225 ret[WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
229 static std::map<TextColor, int> initCrtBgColors() {
230 std::map<TextColor, int> ret;
232 ret[RED] = BACKGROUND_RED;
233 ret[GREEN] = BACKGROUND_GREEN;
234 ret[YELLOW] = BACKGROUND_RED | BACKGROUND_GREEN;
235 ret[BLUE] = BACKGROUND_BLUE;
236 ret[MAGENTA] = BACKGROUND_BLUE | BACKGROUND_RED;
237 ret[CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE;
238 ret[LIGHT_GRAY]= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
239 ret[DARK_GRAY] = BACKGROUND_INTENSITY;
240 ret[LIGHT_RED] = BACKGROUND_RED | BACKGROUND_INTENSITY;
241 ret[LIGHT_GREEN] = BACKGROUND_GREEN | BACKGROUND_INTENSITY;
242 ret[LIGHT_YELLOW] = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
243 ret[LIGHT_BLUE] = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
244 ret[LIGHT_MAGENTA] = BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
245 ret[LIGHT_CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
246 ret[WHITE] = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
250 static WORD getCurrentBgColor() {
251 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
252 CONSOLE_SCREEN_BUFFER_INFO info;
253 GetConsoleScreenBufferInfo(hStdout, &info);
254 return info.wAttributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
257 static WORD getCurrentFgColor() {
258 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
259 CONSOLE_SCREEN_BUFFER_INFO info;
260 GetConsoleScreenBufferInfo(hStdout, &info);
261 return info.wAttributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
263 static std::map<TextColor, int> crtFgColors = initCrtFgColors();
264 static std::map<TextColor, int> crtBgColors = initCrtBgColors();
267 static void escapeAnsiCode(std::ostream &os,
const std::string &ansiCode,
const std::string &endEscape =
"m") {
268 static const char *stdOutNoAnsiEscapes = getenv(
"STDOUT_NO_ANSI_ESCAPES");
269 static const char *stdErrNoAnsiEscapes = getenv(
"STDERR_NO_ANSI_ESCAPES");
272 if ((&os == &std::cout && !stdOutNoAnsiEscapes && isatty(fileno(stdout))) ||
273 (&os == &std::cerr && !stdErrNoAnsiEscapes && isatty(fileno(stderr))))
275 if ((&os == &std::cout && !stdOutNoAnsiEscapes) ||
276 (&os == &std::cerr && !stdErrNoAnsiEscapes))
278 os <<
"\x1b[" << ansiCode << endEscape;
303 inline std::ostream& defaultTextColor(std::ostream &s) {
304 if (&s == &std::cout || &s == &std::cerr) {
306 escapeAnsiCode(s,
"0");
307 escapeAnsiCode(s,
"39");
308 escapeAnsiCode(s,
"49");
312 static const char *term = getenv(
"TERM");
314 if (term && std::string(term) !=
"cygwin") {
315 escapeAnsiCode(s,
"0");
316 escapeAnsiCode(s,
"39");
317 escapeAnsiCode(s,
"49");
320 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
321 SetConsoleTextAttribute(hStdout, crtBgColors[BLACK] | crtFgColors[WHITE]);
330 inline std::ostream& operator<<(std::ostream &s,
const TextFgColorSetup &tgfcs) {
331 if (&s == &std::cout || &s == &std::cerr) {
333 escapeAnsiCode(s, ansiFgColors[tgfcs.color]);
337 static const char *term = getenv(
"TERM");
339 if (term && std::string(term) !=
"cygwin") {
340 escapeAnsiCode(s, ansiFgColors[tgfcs.color]);
343 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
344 SetConsoleTextAttribute(hStdout, crtFgColors[tgfcs.color] | getCurrentBgColor());
353 inline std::ostream& operator<<(std::ostream &s,
const TextBgColorSetup &tbgcs) {
354 if (&s == &std::cout || &s == &std::cerr) {
356 escapeAnsiCode(s, ansiBgColors[tbgcs.color]);
360 static const char *term = getenv(
"TERM");
362 if (term && std::string(term) !=
"cygwin") {
363 escapeAnsiCode(s, ansiBgColors[tbgcs.color]);
366 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
367 SetConsoleTextAttribute(hStdout, getCurrentFgColor() | crtBgColors[tbgcs.color]);
376 inline void setEffects(std::ostream &s,
const int &effect) {
378 escapeAnsiCode(s,
"0");
381 escapeAnsiCode(s,
"1");
383 if (effect & UNDERLINED)
384 escapeAnsiCode(s,
"4");
387 escapeAnsiCode(s,
"5");
390 inline std::ostream& operator<<(std::ostream &s,
const TextEffectSetup &tes) {
391 if (&s == &std::cout || &s == &std::cerr) {
393 setEffects(s, tes.effect);
395 static const char *term = getenv(
"TERM");
397 if (term && std::string(term) !=
"cygwin") {
398 setEffects(s, tes.effect);
407 inline TextBgColorSetup setTextBackgroundColor(TextColor color) {
408 return TextBgColorSetup(color);
411 inline TextFgColorSetup setTextColor(TextColor color) {
412 return TextFgColorSetup(color);
415 inline TextEffectSetup setTextEffect(
int effect) {
416 return TextEffectSetup(effect);
419 inline std::ostream& bold(std::ostream& s) {
420 return s << setTextEffect(BOLD);
423 inline std::ostream& underlined(std::ostream& s) {
424 return s << setTextEffect(UNDERLINED);
427 inline std::ostream& red(std::ostream& s) {
428 return s << setTextColor(RED);
431 inline std::ostream& green(std::ostream& s) {
432 return s << setTextColor(GREEN);
435 inline std::ostream& blue(std::ostream& s) {
436 return s << setTextColor(BLUE);
439 inline std::ostream& yellow(std::ostream& s) {
440 return s << setTextColor(YELLOW);
443 inline std::ostream& white(std::ostream& s) {
444 return s << setTextColor(WHITE);
447 inline std::ostream& black(std::ostream& s) {
448 return s << setTextColor(BLACK);
451 inline std::ostream& magenta(std::ostream& s) {
452 return s << setTextColor(MAGENTA);
455 inline std::ostream& cyan(std::ostream& s) {
456 return s << setTextColor(CYAN);
459 inline std::ostream& lightRed(std::ostream& s) {
460 return s << setTextColor(LIGHT_RED);
463 inline std::ostream& lightGreen(std::ostream& s) {
464 return s << setTextColor(LIGHT_GREEN);
467 inline std::ostream& lightBlue(std::ostream& s) {
468 return s << setTextColor(LIGHT_BLUE);
471 inline std::ostream& lightYellow(std::ostream& s) {
472 return s << setTextColor(LIGHT_YELLOW);
475 inline std::ostream& lightGray(std::ostream& s) {
476 return s << setTextColor(LIGHT_GRAY);
479 inline std::ostream& darkGray(std::ostream& s) {
480 return s << setTextColor(DARK_GRAY);
483 inline std::ostream& lightMagenta(std::ostream& s) {
484 return s << setTextColor(LIGHT_MAGENTA);
487 inline std::ostream& lightCyan(std::ostream& s) {
488 return s << setTextColor(LIGHT_CYAN);
494 inline std::ostream& fillToEndOfLine(std::ostream& s) {
497 if (processInForeground() && ((&s == &std::cout && isatty(fileno(stdout))) || (&s == &std::cerr && isatty(fileno(stderr))))) {
499 std::pair<int, int> cursorPos = getConsoleCursorPosition();
500 std::pair<int, int> consoleSize = getConsoleSize();
502 if ((cursorPos.second + consoleSize.second) != 0) {
503 for (
int i = cursorPos.second ; i <= consoleSize.second ; ++i) {
516 if ((&s == &std::cout && !isatty(fileno(stdout))) || (&s == &std::cerr && !isatty(fileno(stderr)))) {
522 if (!processInForeground()) {
523 s << defaultTextColor << std::endl;