diff --git a/src/builtin_set_color.cpp b/src/builtin_set_color.cpp index 22c9d9d2e..576013136 100644 --- a/src/builtin_set_color.cpp +++ b/src/builtin_set_color.cpp @@ -33,15 +33,53 @@ class parser_t; -static void print_colors(io_streams_t &streams) { - outputter_t outp; +static void print_modifiers(outputter_t &outp, bool bold, bool underline, bool italics, bool dim, bool reverse, rgb_color_t bg) { + if (bold && enter_bold_mode) { + // These casts are needed to work with different curses implementations. + writembs_nofail(outp, tparm(const_cast<char *>(enter_bold_mode))); + } + if (underline && enter_underline_mode) { + writembs_nofail(outp, enter_underline_mode); + } + + if (italics && enter_italics_mode) { + writembs_nofail(outp, enter_italics_mode); + } + + if (dim && enter_dim_mode) { + writembs_nofail(outp, enter_dim_mode); + } + + if (reverse && enter_reverse_mode) { + writembs_nofail(outp, enter_reverse_mode); + } else if (reverse && enter_standout_mode) { + writembs_nofail(outp, enter_standout_mode); + } + if (!bg.is_none() && bg.is_normal()) { + writembs_nofail(outp, tparm(const_cast<char *>(exit_attribute_mode))); + } + +} + + +static void print_colors(io_streams_t &streams, bool bold, bool underline, bool italics, bool dim, bool reverse, rgb_color_t bg) { + outputter_t outp; for (const auto &color_name : rgb_color_t::named_color_names()) { if (!streams.out_is_redirected && isatty(STDOUT_FILENO)) { + print_modifiers(outp, bold, underline, italics, dim, reverse, bg); rgb_color_t color = rgb_color_t(color_name); outp.set_color(color, rgb_color_t::none()); + if (!bg.is_none()) { + outp.write_color(bg, false /* not is_fg */); + } } outp.writestr(color_name); + if (!bg.is_none()) { + // If we have a background, stop it after the color + // or it goes to the end of the line and looks ugly. + writembs_nofail(outp, tparm(const_cast<char *>(exit_attribute_mode))); + } outp.writech(L'\n'); } // conveniently, 'normal' is always the last color so we don't need to reset here @@ -96,7 +134,7 @@ maybe_t<int> builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t } const wchar_t *bgcolor = nullptr; - bool bold = false, underline = false, italics = false, dim = false, reverse = false; + bool bold = false, underline = false, italics = false, dim = false, reverse = false, print = false; // Parse options to obtain the requested operation and the modifiers. int opt; @@ -132,8 +170,8 @@ maybe_t<int> builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t break; } case 'c': { - print_colors(streams); - return STATUS_CMD_OK; + print = true; + break; } case ':': { // We don't error here because "-b" is the only option that requires an argument, @@ -149,6 +187,17 @@ maybe_t<int> builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t } } + const rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : L""); + if (bgcolor && bg.is_none()) { + streams.err.append_format(_(L"%ls: Unknown color '%ls'\n"), argv[0], bgcolor); + return STATUS_INVALID_ARGS; + } + + if (print) { + print_colors(streams, bold, underline, italics, dim, reverse, bg); + return STATUS_CMD_OK; + } + // Remaining arguments are foreground color. std::vector<rgb_color_t> fgcolors; for (; w.woptind < argc; w.woptind++) { @@ -165,12 +214,6 @@ maybe_t<int> builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t const rgb_color_t fg = best_color(fgcolors, output_get_color_support()); assert(fgcolors.empty() || !fg.is_none()); - const rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : L""); - if (bgcolor && bg.is_none()) { - streams.err.append_format(_(L"%ls: Unknown color '%ls'\n"), argv[0], bgcolor); - return STATUS_INVALID_ARGS; - } - // Test if we have at least basic support for setting fonts, colors and related bits - otherwise // just give up... if (cur_term == nullptr || !exit_attribute_mode) { @@ -178,28 +221,7 @@ maybe_t<int> builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t } outputter_t outp; - if (bold && enter_bold_mode) { - // These casts are needed to work with different curses implementations. - writembs_nofail(outp, tparm(const_cast<char *>(enter_bold_mode))); - } - - if (underline && enter_underline_mode) { - writembs_nofail(outp, enter_underline_mode); - } - - if (italics && enter_italics_mode) { - writembs_nofail(outp, enter_italics_mode); - } - - if (dim && enter_dim_mode) { - writembs_nofail(outp, enter_dim_mode); - } - - if (reverse && enter_reverse_mode) { - writembs_nofail(outp, enter_reverse_mode); - } else if (reverse && enter_standout_mode) { - writembs_nofail(outp, enter_standout_mode); - } + print_modifiers(outp, bold, underline, italics, dim, reverse, bg); if (bgcolor != nullptr && bg.is_normal()) { writembs_nofail(outp, tparm(const_cast<char *>(exit_attribute_mode))); diff --git a/tests/pexpects/set_color.py b/tests/pexpects/set_color.py new file mode 100644 index 000000000..0d8d091b4 --- /dev/null +++ b/tests/pexpects/set_color.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +from pexpect_helper import SpawnedProc +import subprocess +import sys +import time +import os + +env = os.environ.copy() +env["TERM"] = "xterm" + +sp = SpawnedProc(env=env) +send, sendline, sleep, expect_prompt, expect_re, expect_str = ( + sp.send, + sp.sendline, + sp.sleep, + sp.expect_prompt, + sp.expect_re, + sp.expect_str, +) +expect_prompt() + +# See that --print-colors prints the colors colored. +# Note that we don't check *all* of them, just a few. +sendline("set_color --print-colors") +expect_str("black") +expect_str("blue") +expect_str("brblack") +expect_str("brblue") +expect_str("brcyan") +expect_str("brgreen") +expect_str("brmagenta") +expect_str("brred") +expect_str("brwhite") +expect_str("bryellow") +expect_str("cyan") +expect_str("green") +expect_str("magenta") +expect_str("\x1b[31mred") +expect_str("\x1b[37mwhite") +expect_str("\x1b[33myellow") +expect_str("normal") +expect_prompt() + +sendline ("set_color --background blue --print-colors") +expect_str("black") +expect_str("blue") +expect_str("brblack") +expect_str("brblue") +expect_str("brcyan") +expect_str("brgreen") +expect_str("brmagenta") +expect_str("brred") +expect_str("brwhite") +expect_str("bryellow") +expect_str("cyan") +expect_str("green") +expect_str("magenta") +expect_str("\x1b[31m\x1b[44mred") +expect_str("white") +expect_str("yellow") +expect_str("normal") +expect_prompt() +