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:

ANSI escape codes in action.

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:

colors.cpp:

#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_n
picks from the 8 bit color table.
color_rgb
let'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_rgb
does not appear to work on Mac OS terminal. So far all the codes work only on Linux; haven't tested on Windows 🙂

ansi_escape_code.hpp:

#pragma once

#include 

namespace 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; }

}

5 Replies to “ANSI escape codes”

  1. 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?

    1. 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 🙂

Leave a Reply to naCancel reply