ANSI escape codes are a way to do more than just plain text in the terminal (be it Windows cmd.exe or UNIX xterm). A picture is worth a thousand words so here’s what I was able to do with them:

All of the text appearance manipulation and coloring was done using a tiny library I wrote yesterday and a very intuitive C++ syntax. Here’s the code responsible for the screenshot above:
#include#include "ansi_escape_codes.hpp" using namespace std; using namespace ansi_escape_codes; int main(int argc, char** argv) { cout << bold << "BOLD" << reset << endl; cout << faint << "FAINT" << reset << endl; cout << italic << "ITALIC" << reset << endl; cout << underline << "UNDERLINE" << reset << endl; cout << slow_blink << "SLOW BLINK" << reset << endl; cout << inverse << "REVERSE" << reset << endl; cout << endl; for(int n = 0; n <= 255; ++n) cout << color_n(n) << "X"; cout << reset << endl << endl; for(int n = 0; n <= 255; ++n) cout << color_bg_n(n) << "X"; cout << reset << endl << endl; for(int r = 0; r <= 255; r+=32) for(int g = 0; g <= 255; g+=32) for(int b = 0; b <= 255; b+=32) cout << color_rgb(r, g, b) << "X"; cout << reset < Pretty easy to follow I hope :) The library defines a bunch of stream manipulators that inject the appropriate escape sequences. For example,
cout << bold << "BOLD";will print out, you guessed it, bolded text.color_npicks from the 8 bit color table.color_rgblet's you define a 24 bit truecolor. The_bg_version is for selecting the background color. Here's the complete source code for the library, hope you will find it useful!P.S. The
color_rgbdoes not appear to work on Mac OS terminal. So far all the codes work only on Linux; haven't tested on Windows 🙂#pragma once #includenamespace ansi_escape_codes { #define ENTRY(name, code) \ static inline struct name##_opcode {} name; \ inline std::ostream& operator << (std::ostream& os, const name##_opcode&) \ { os << "\x1b[" #code "m"; return os; } ENTRY(reset, 0) ENTRY(bold, 1) ENTRY(faint, 2) ENTRY(italic, 3) ENTRY(underline, 4) ENTRY(slow_blink, 5) ENTRY(rapid_blink, 6) ENTRY(inverse, 7) ENTRY(conceal, 8) ENTRY(crossed_out, 9) ENTRY(default_font, 10) ENTRY(alt_font_1, 11) ENTRY(alt_font_2, 12) ENTRY(alt_font_3, 13) ENTRY(alt_font_4, 14) ENTRY(alt_font_5, 15) ENTRY(alt_font_6, 16) ENTRY(alt_font_7, 17) ENTRY(alt_font_8, 18) ENTRY(alt_font_9, 19) ENTRY(fraktur, 20) ENTRY(doubly_underline, 21) ENTRY(normal, 22) ENTRY(not_italic_not_raktur, 23) ENTRY(underline_off, 24) ENTRY(blink_off, 25) ENTRY(inverse_off, 27) ENTRY(reveal, 28) ENTRY(not_crossed_out, 29) ENTRY(default_foreground_color, 39) ENTRY(default_background_color, 49) ENTRY(framed, 51) ENTRY(encircled, 52) ENTRY(overlined, 53) ENTRY(not_framed_or_encircled, 54) ENTRY(not_overlined, 55) #define COLOR_ENTRY(name, code) \ static inline struct name##_color {} name; \ inline std::ostream& operator << (std::ostream& os, const name##_color&) \ { os << "\x1b[" #code "m"; return os; } COLOR_ENTRY(black, 30) COLOR_ENTRY(red, 31) COLOR_ENTRY(green, 32) COLOR_ENTRY(yellow, 33) COLOR_ENTRY(blue, 34) COLOR_ENTRY(magenta, 35) COLOR_ENTRY(cyan, 36) COLOR_ENTRY(white, 37) COLOR_ENTRY(black_bg, 40) COLOR_ENTRY(red_bg, 41) COLOR_ENTRY(green_bg, 42) COLOR_ENTRY(yellow_bg, 43) COLOR_ENTRY(blue_bg, 44) COLOR_ENTRY(magenta_bg, 45) COLOR_ENTRY(cyan_bg, 46) COLOR_ENTRY(white_bg, 47) COLOR_ENTRY(bright_black, 90) COLOR_ENTRY(bright_red, 91) COLOR_ENTRY(bright_green, 92) COLOR_ENTRY(bright_yellow, 93) COLOR_ENTRY(bright_blue, 94) COLOR_ENTRY(bright_magenta, 95) COLOR_ENTRY(bright_cyan, 96) COLOR_ENTRY(bright_white, 97) COLOR_ENTRY(bright_black_bg, 100) COLOR_ENTRY(bright_red_bg, 101) COLOR_ENTRY(bright_green_bg, 102) COLOR_ENTRY(bright_yellow_bg, 103) COLOR_ENTRY(bright_blue_bg, 104) COLOR_ENTRY(bright_magenta_bg, 105) COLOR_ENTRY(bright_cyan_bg, 106) COLOR_ENTRY(bright_white_bg, 107) struct color_n { color_n(unsigned char n) : m_n(n) {} friend std::ostream& operator << (std::ostream& os, const color_n& n); private: unsigned char m_n; }; struct color_bg_n { color_bg_n(unsigned char n) : m_n(n) {} friend std::ostream& operator << (std::ostream& os, const color_bg_n& n); private: unsigned char m_n; }; inline std::ostream& operator << (std::ostream& os, const color_n& n) { os << "\x1b[38;5;" << (int)n.m_n << "m"; return os; } inline std::ostream& operator << (std::ostream& os, const color_bg_n& n) { os << "\x1b[48;5;" << (int)n.m_n << "m"; return os; } struct color_rgb { color_rgb(unsigned char r, unsigned char g, unsigned char b) : m_r(r), m_g(g), m_b(b) {} friend std::ostream& operator << (std::ostream& os, const color_rgb& c); private: unsigned char m_r, m_g, m_b; }; struct color_bg_rgb { color_bg_rgb(unsigned char r, unsigned char g, unsigned char b) : m_r(r), m_g(g), m_b(b) {} friend std::ostream& operator << (std::ostream& os, const color_bg_rgb& c); private: unsigned char m_r, m_g, m_b; }; inline std::ostream& operator << (std::ostream& os, const color_rgb& c) { os << "\x1b[38;2;" << (int)c.m_r << ";" << (int)c.m_g << ";" << (int)c.m_b << "m"; return os; } inline std::ostream& operator << (std::ostream& os, const color_bg_rgb& c) { os << "\x1b[48;2;" << (int)c.m_r << ";" << (int)c.m_g << ";" << (int)c.m_b << "m"; return os; } }
Cool! I get errors like this with gcc5.4:
../src/ascii_escape_codes.hpp:13:7: error: ‘ascii_escape_codes::reset’ declared as an ‘inline’ variable
ENTRY(reset, 0)
^
../src/ascii_escape_codes.hpp:9:40: note: in definition of macro ‘ENTRY’
static inline struct name##_opcode {} name; \
^
If I remove the “inline” I now get warnings such as:
../src/ascii_escape_codes.hpp:19:7: warning: ‘ascii_escape_codes::rapid_blink’ defined but not used [-Wunused-variable]
ENTRY(rapid_blink, 6)
^
../src/ascii_escape_codes.hpp:9:33: note: in definition of macro ‘ENTRY’
static struct name##_opcode {} name; \
^
It works if I ignore these warnings, but your example makes my terminal super laggy. Do you know how I can get rid of the warnings?
Compile like this: g++ -std=c++17 colors.cpp -o colors
Linux?
My output looks different? https://pasteimg.com/image/image.wu7AC
Looks similar enough to what I see on my Mac. What OS did you use?
Not every terminal (Windows CMD, Linux) supports RGB/24bit colors.
It’s probably best to use the few colors spelled out by name if one wants to be consistent across many platforms.
P.S. Thanks for reading my blog 🙂