35 #if defined(__unix__) || defined(__APPLE__) 38 #include <sys/ioctl.h> 41 static struct termios stored_settings;
43 static void setConsoleSettingsForAnsiRequest(
void) {
44 struct termios new_settings;
45 tcgetattr(0, &stored_settings);
46 new_settings = stored_settings;
47 new_settings.c_lflag &= ~ICANON;
48 new_settings.c_lflag &= ~ECHO;
49 tcsetattr(0, TCSANOW, &new_settings);
52 static void resetConsoleSettings(
void) {
53 tcsetattr(0, TCSANOW, &stored_settings);
56 static bool processInForeground(
void) {
57 pid_t fg = tcgetpgrp(STDIN_FILENO);
58 return fg == getpgrp();
61 static std::pair<int, int> getConsoleCursorPosition() {
64 if (isatty(fileno(stdin)) && processInForeground()) {
65 setConsoleSettingsForAnsiRequest();
66 fprintf(stdout,
"\x1b[6n");
68 if (fscanf(stdin,
"\x1b[%d;%dR", &row, &col)) {
71 resetConsoleSettings();
74 return std::make_pair(row, col);
77 static std::pair<int, int> getConsoleSize() {
78 int rows = -1, cols = -1;
81 if (ioctl(0, TIOCGWINSZ, &ws) == 0) {
86 return std::make_pair(rows, cols);
91 inline std::pair<int, int> getConsoleCursorPosition() {
93 CONSOLE_SCREEN_BUFFER_INFO SBInfo;
95 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &SBInfo)) {
96 row = SBInfo.dwCursorPosition.Y;
97 col = SBInfo.dwCursorPosition.X;
100 return std::make_pair(row, col);
103 inline std::pair<int, int> getConsoleSize() {
104 int rows = 200, cols = 200;
105 CONSOLE_SCREEN_BUFFER_INFO SBInfo;
107 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &SBInfo)) {
108 rows = SBInfo.dwSize.Y;
109 cols = SBInfo.dwSize.X - 1;
112 return std::make_pair(rows, cols);
117 enum TextEffect { NORMAL = 1, BOLD = 2, UNDERLINED = 4, BLINK = 8 };
138 class TextFgColorSetup {
141 TextFgColorSetup(TextColor color) : color(color) {}
146 class TextBgColorSetup {
149 TextBgColorSetup(TextColor color) : color(color) {}
154 class TextEffectSetup {
157 TextEffectSetup(
int effect) : effect(effect) {}
162 static std::map<TextColor, std::string> initAnsiFgColors() {
163 const char *colorterm = getenv(
"COLORTERM");
164 bool rxvt = colorterm && std::string(colorterm).find(
"rxvt") != std::string::npos;
165 std::map<TextColor, std::string> ret;
173 ret[LIGHT_GRAY] =
"37";
174 ret[DARK_GRAY] = rxvt ? ret[BLACK] :
"90";
175 ret[LIGHT_RED] = rxvt ? ret[RED] :
"91";
176 ret[LIGHT_GREEN] = rxvt ? ret[GREEN] :
"92";
177 ret[LIGHT_YELLOW] = rxvt ? ret[YELLOW] :
"93";
178 ret[LIGHT_BLUE] = rxvt ? ret[BLUE] :
"94";
179 ret[LIGHT_MAGENTA] = rxvt ? ret[MAGENTA] :
"95";
180 ret[LIGHT_CYAN] = rxvt ? ret[CYAN] :
"96";
181 ret[WHITE] = rxvt ? ret[LIGHT_GRAY] :
"97";
185 static std::map<TextColor, std::string> initAnsiBgColors() {
186 const char *colorterm = getenv(
"COLORTERM");
187 bool rxvt = colorterm && std::string(colorterm).find(
"rxvt") != std::string::npos;
188 std::map<TextColor, std::string> ret;
196 ret[LIGHT_GRAY] =
"47";
197 ret[DARK_GRAY] = rxvt ? ret[BLACK] :
"100";
198 ret[LIGHT_RED] = rxvt ? ret[RED] :
"101";
199 ret[LIGHT_GREEN] = rxvt ? ret[GREEN] :
"102";
200 ret[LIGHT_YELLOW] = rxvt ? ret[YELLOW] :
"103";
201 ret[LIGHT_BLUE] = rxvt ? ret[BLUE] :
"104";
202 ret[LIGHT_MAGENTA] = rxvt ? ret[MAGENTA] :
"105";
203 ret[LIGHT_CYAN] = rxvt ? ret[CYAN] :
"106";
204 ret[WHITE] = rxvt ? ret[LIGHT_GRAY] :
"107";
208 static std::map<TextColor, std::string> ansiFgColors = initAnsiFgColors();
209 static std::map<TextColor, std::string> ansiBgColors = initAnsiBgColors();
212 static std::map<TextColor, int> initCrtFgColors() {
213 std::map<TextColor, int> ret;
215 ret[RED] = FOREGROUND_RED;
216 ret[GREEN] = FOREGROUND_GREEN;
217 ret[YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN;
218 ret[BLUE] = FOREGROUND_BLUE;
219 ret[MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED;
220 ret[CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE;
221 ret[LIGHT_GRAY] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
222 ret[DARK_GRAY] = FOREGROUND_INTENSITY;
223 ret[LIGHT_RED] = FOREGROUND_RED | FOREGROUND_INTENSITY;
224 ret[LIGHT_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
225 ret[LIGHT_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
226 ret[LIGHT_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
227 ret[LIGHT_MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
228 ret[LIGHT_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
229 ret[WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
233 static std::map<TextColor, int> initCrtBgColors() {
234 std::map<TextColor, int> ret;
236 ret[RED] = BACKGROUND_RED;
237 ret[GREEN] = BACKGROUND_GREEN;
238 ret[YELLOW] = BACKGROUND_RED | BACKGROUND_GREEN;
239 ret[BLUE] = BACKGROUND_BLUE;
240 ret[MAGENTA] = BACKGROUND_BLUE | BACKGROUND_RED;
241 ret[CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE;
242 ret[LIGHT_GRAY] = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
243 ret[DARK_GRAY] = BACKGROUND_INTENSITY;
244 ret[LIGHT_RED] = BACKGROUND_RED | BACKGROUND_INTENSITY;
245 ret[LIGHT_GREEN] = BACKGROUND_GREEN | BACKGROUND_INTENSITY;
246 ret[LIGHT_YELLOW] = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
247 ret[LIGHT_BLUE] = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
248 ret[LIGHT_MAGENTA] = BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
249 ret[LIGHT_CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
250 ret[WHITE] = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
254 static WORD getCurrentBgColor() {
255 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
256 CONSOLE_SCREEN_BUFFER_INFO info;
257 GetConsoleScreenBufferInfo(hStdout, &info);
258 return info.wAttributes &
259 (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
262 static WORD getCurrentFgColor() {
263 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
264 CONSOLE_SCREEN_BUFFER_INFO info;
265 GetConsoleScreenBufferInfo(hStdout, &info);
266 return info.wAttributes &
267 (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
269 static std::map<TextColor, int> crtFgColors = initCrtFgColors();
270 static std::map<TextColor, int> crtBgColors = initCrtBgColors();
273 static void escapeAnsiCode(std::ostream &os,
const std::string &ansiCode,
274 const std::string &endEscape =
"m") {
275 static const char *stdOutNoAnsiEscapes = getenv(
"STDOUT_NO_ANSI_ESCAPES");
276 static const char *stdErrNoAnsiEscapes = getenv(
"STDERR_NO_ANSI_ESCAPES");
279 if ((&os == &std::cout && !stdOutNoAnsiEscapes && isatty(fileno(stdout))) ||
280 (&os == &std::cerr && !stdErrNoAnsiEscapes && isatty(fileno(stderr))))
282 if ((&os == &std::cout && !stdOutNoAnsiEscapes) || (&os == &std::cerr && !stdErrNoAnsiEscapes))
284 os <<
"\x1b[" << ansiCode << endEscape;
311 inline std::ostream &defaultTextColor(std::ostream &s) {
312 if (&s == &std::cout || &s == &std::cerr) {
314 escapeAnsiCode(s,
"0");
315 escapeAnsiCode(s,
"39");
316 escapeAnsiCode(s,
"49");
320 static const char *term = getenv(
"TERM");
322 if (term && std::string(term) !=
"cygwin") {
323 escapeAnsiCode(s,
"0");
324 escapeAnsiCode(s,
"39");
325 escapeAnsiCode(s,
"49");
327 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
328 SetConsoleTextAttribute(hStdout, crtBgColors[BLACK] | crtFgColors[WHITE]);
337 inline std::ostream &
operator<<(std::ostream &s,
const TextFgColorSetup &tgfcs) {
338 if (&s == &std::cout || &s == &std::cerr) {
340 escapeAnsiCode(s, ansiFgColors[tgfcs.color]);
344 static const char *term = getenv(
"TERM");
346 if (term && std::string(term) !=
"cygwin") {
347 escapeAnsiCode(s, ansiFgColors[tgfcs.color]);
349 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
350 SetConsoleTextAttribute(hStdout, crtFgColors[tgfcs.color] | getCurrentBgColor());
359 inline std::ostream &
operator<<(std::ostream &s,
const TextBgColorSetup &tbgcs) {
360 if (&s == &std::cout || &s == &std::cerr) {
362 escapeAnsiCode(s, ansiBgColors[tbgcs.color]);
366 static const char *term = getenv(
"TERM");
368 if (term && std::string(term) !=
"cygwin") {
369 escapeAnsiCode(s, ansiBgColors[tbgcs.color]);
371 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
372 SetConsoleTextAttribute(hStdout, getCurrentFgColor() | crtBgColors[tbgcs.color]);
381 inline void setEffects(std::ostream &s,
const int &effect) {
383 escapeAnsiCode(s,
"0");
386 escapeAnsiCode(s,
"1");
388 if (effect & UNDERLINED)
389 escapeAnsiCode(s,
"4");
392 escapeAnsiCode(s,
"5");
395 inline std::ostream &
operator<<(std::ostream &s,
const TextEffectSetup &tes) {
396 if (&s == &std::cout || &s == &std::cerr) {
398 setEffects(s, tes.effect);
400 static const char *term = getenv(
"TERM");
402 if (term && std::string(term) !=
"cygwin") {
403 setEffects(s, tes.effect);
412 inline TextBgColorSetup setTextBackgroundColor(TextColor color) {
413 return TextBgColorSetup(color);
416 inline TextFgColorSetup setTextColor(TextColor color) {
417 return TextFgColorSetup(color);
420 inline TextEffectSetup setTextEffect(
int effect) {
421 return TextEffectSetup(effect);
424 inline std::ostream &bold(std::ostream &s) {
425 return s << setTextEffect(BOLD);
428 inline std::ostream &underlined(std::ostream &s) {
429 return s << setTextEffect(UNDERLINED);
432 inline std::ostream &red(std::ostream &s) {
433 return s << setTextColor(RED);
436 inline std::ostream &green(std::ostream &s) {
437 return s << setTextColor(GREEN);
440 inline std::ostream &blue(std::ostream &s) {
441 return s << setTextColor(BLUE);
444 inline std::ostream &yellow(std::ostream &s) {
445 return s << setTextColor(YELLOW);
448 inline std::ostream &white(std::ostream &s) {
449 return s << setTextColor(WHITE);
452 inline std::ostream &black(std::ostream &s) {
453 return s << setTextColor(BLACK);
456 inline std::ostream &magenta(std::ostream &s) {
457 return s << setTextColor(MAGENTA);
460 inline std::ostream &cyan(std::ostream &s) {
461 return s << setTextColor(CYAN);
464 inline std::ostream &lightRed(std::ostream &s) {
465 return s << setTextColor(LIGHT_RED);
468 inline std::ostream &lightGreen(std::ostream &s) {
469 return s << setTextColor(LIGHT_GREEN);
472 inline std::ostream &lightBlue(std::ostream &s) {
473 return s << setTextColor(LIGHT_BLUE);
476 inline std::ostream &lightYellow(std::ostream &s) {
477 return s << setTextColor(LIGHT_YELLOW);
480 inline std::ostream &lightGray(std::ostream &s) {
481 return s << setTextColor(LIGHT_GRAY);
484 inline std::ostream &darkGray(std::ostream &s) {
485 return s << setTextColor(DARK_GRAY);
488 inline std::ostream &lightMagenta(std::ostream &s) {
489 return s << setTextColor(LIGHT_MAGENTA);
492 inline std::ostream &lightCyan(std::ostream &s) {
493 return s << setTextColor(LIGHT_CYAN);
499 inline std::ostream &fillToEndOfLine(std::ostream &s) {
502 if (processInForeground() && ((&s == &std::cout && isatty(fileno(stdout))) ||
503 (&s == &std::cerr && isatty(fileno(stderr))))) {
505 std::pair<int, int> cursorPos = getConsoleCursorPosition();
506 std::pair<int, int> consoleSize = getConsoleSize();
508 if ((cursorPos.second + consoleSize.second) != 0) {
509 for (
int i = cursorPos.second; i <= consoleSize.second; ++i) {
521 if ((&s == &std::cout && !isatty(fileno(stdout))) ||
522 (&s == &std::cerr && !isatty(fileno(stderr)))) {
528 if (!processInForeground()) {
529 s << defaultTextColor << std::endl;
std::ostream & operator<<(std::ostream &os, const Array< T, N > &array)
operator << stream operator to easily print an array, or save it to a file.