static void outputSetColor()

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');
}