in src/agent/Terminal.cc [105:212]
static void outputSetColor(std::string &out, int color)
{
int fore = 0;
int back = 0;
if (color & FOREGROUND_RED) fore |= FLAG_RED;
if (color & FOREGROUND_GREEN) fore |= FLAG_GREEN;
if (color & FOREGROUND_BLUE) fore |= FLAG_BLUE;
if (color & FOREGROUND_INTENSITY) fore |= FLAG_BRIGHT;
if (color & BACKGROUND_RED) back |= FLAG_RED;
if (color & BACKGROUND_GREEN) back |= FLAG_GREEN;
if (color & BACKGROUND_BLUE) back |= FLAG_BLUE;
if (color & BACKGROUND_INTENSITY) back |= FLAG_BRIGHT;
if (color & WINPTY_COMMON_LVB_REVERSE_VIDEO) {
// n.b.: The COMMON_LVB_REVERSE_VIDEO flag also swaps
// FOREGROUND_INTENSITY and BACKGROUND_INTENSITY. Tested on
// Windows 10 v14393.
std::swap(fore, back);
}
// Translate the fore/back colors into terminal escape codes using
// a heuristic that works OK with common white-on-black or
// black-on-white color schemes. We don't know which color scheme
// the terminal is using. It is ugly to force white-on-black text
// on a black-on-white terminal, and it's even ugly to force the
// matching scheme. It's probably relevant that the default
// fore/back terminal colors frequently do not match any of the 16
// palette colors.
// Typical default terminal color schemes (according to palette,
// when possible):
// - mintty: LtGray-on-Black(A)
// - putty: LtGray-on-Black(A)
// - xterm: LtGray-on-Black(A)
// - Konsole: LtGray-on-Black(A)
// - JediTerm/JetBrains: Black-on-White(B)
// - rxvt: Black-on-White(B)
// If the background is the default color (black), then it will
// map to Black(A) or White(B). If we translate White to White,
// then a Black background and a White background in the console
// are both White with (B). Therefore, we should translate White
// using SGR 7 (Invert). The typical finished mapping table for
// background grayscale colors is:
//
// (A) White => LtGray(fore)
// (A) Black => Black(back)
// (A) LtGray => LtGray
// (A) DkGray => DkGray
//
// (B) White => Black(fore)
// (B) Black => White(back)
// (B) LtGray => LtGray
// (B) DkGray => DkGray
//
out.append(CSI "0");
if (back == BLACK) {
if (fore == LTGRAY) {
// The "default" foreground color. Use the terminal's
// default colors.
} else if (fore == WHITE) {
// Sending the literal color white would behave poorly if
// the terminal were black-on-white. Sending Bold is not
// guaranteed to alter the color, but it will make the text
// visually distinct, so do that instead.
out.append(";1");
} else if (fore == DKGRAY) {
// Set the foreground color to DkGray(90) with a fallback
// of LtGray(37) for terminals that don't handle the 9X SGR
// parameters (e.g. Eclipse's TM Terminal as of this
// writing).
out.append(";37;90");
} else {
outputSetColorSgrParams(out, true, fore);
}
} else if (back == WHITE) {
// Set the background color using Invert on the default
// foreground color, and set the foreground color by setting a
// background color.
// Use the terminal's inverted colors.
out.append(";7");
if (fore == LTGRAY || fore == BLACK) {
// We're likely mapping Console White to terminal LtGray or
// Black. If they are the Console foreground color, then
// don't set a terminal foreground color to avoid creating
// invisible text.
} else {
outputSetColorSgrParams(out, false, fore);
}
} else {
// Set the foreground and background to match exactly that in
// the Windows console.
outputSetColorSgrParams(out, true, fore);
outputSetColorSgrParams(out, false, back);
}
if (fore == back) {
// The foreground and background colors are exactly equal, so
// attempt to hide the text using the Conceal SGR parameter,
// which some terminals support.
out.append(";8");
}
if (color & WINPTY_COMMON_LVB_UNDERSCORE) {
out.append(";4");
}
out.push_back('m');
}