diff --git a/builtin_set_color.cpp b/builtin_set_color.cpp index 1cce8097b..b3757e1c3 100644 --- a/builtin_set_color.cpp +++ b/builtin_set_color.cpp @@ -132,37 +132,31 @@ static int builtin_set_color(parser_t &parser, wchar_t **argv) } } - /* Remaining argument is foreground color */ - const wchar_t *fgcolor = NULL; - if (woptind < argc) + /* Remaining arguments are foreground color */ + std::vector fgcolors; + for (; woptind < argc; woptind++) { - if (woptind + 1 == argc) + rgb_color_t fg = rgb_color_t(argv[woptind]); + if (fg.is_none() || fg.is_ignore()) { - fgcolor = argv[woptind]; - } - else - { - append_format(stderr_buffer, - _(L"%ls: Too many arguments\n"), - argv[0]); + append_format(stderr_buffer, _(L"%ls: Unknown color '%ls'\n"), argv[0], argv[woptind]); return STATUS_BUILTIN_ERROR; } + fgcolors.push_back(fg); } - if (fgcolor == NULL && bgcolor == NULL && !bold && !underline) + if (fgcolors.empty() && bgcolor == NULL && !bold && !underline) { append_format(stderr_buffer, _(L"%ls: Expected an argument\n"), argv[0]); return STATUS_BUILTIN_ERROR; } - - const rgb_color_t fg = rgb_color_t(fgcolor ? fgcolor : L""); - if (fgcolor && (fg.is_none() || fg.is_ignore())) - { - append_format(stderr_buffer, _(L"%ls: Unknown color '%ls'\n"), argv[0], fgcolor); - return STATUS_BUILTIN_ERROR; - } + + // #1323: We may have multiple foreground colors. Choose the best one. + // If we had no foreground coor, we'll get none(); if we have at least one we expect not-none + const rgb_color_t fg = best_color(fgcolors, output_get_color_support()); + assert(fgcolors.empty() || !(fg.is_none() || fg.is_ignore())); const rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : L""); if (bgcolor && (bg.is_none() || bg.is_ignore())) @@ -187,7 +181,6 @@ static int builtin_set_color(parser_t &parser, wchar_t **argv) return STATUS_BUILTIN_ERROR; } - /* Save old output function so we can restore it */ int (* const saved_writer_func)(char) = output_get_writer(); @@ -216,7 +209,7 @@ static int builtin_set_color(parser_t &parser, wchar_t **argv) } } - if (fgcolor != NULL) + if (! fg.is_none()) { if (fg.is_normal() || fg.is_reset()) { diff --git a/output.cpp b/output.cpp index f6fb9fa96..6144746ab 100644 --- a/output.cpp +++ b/output.cpp @@ -488,6 +488,45 @@ void writestr(const wchar_t *str) delete[] buffer; } +rgb_color_t best_color(const std::vector &candidates, color_support_t support) +{ + if (candidates.empty()) + { + return rgb_color_t::none(); + } + + rgb_color_t first_rgb = rgb_color_t::none(), first_named = rgb_color_t::none(); + for (size_t i=0; i < candidates.size(); i++) + { + const rgb_color_t &color = candidates.at(i); + if (first_rgb.is_none() && color.is_rgb()) + { + first_rgb = color; + } + if (first_named.is_none() && color.is_named()) + { + first_named = color; + } + } + // If we have both RGB and named colors, then prefer rgb if term256 is supported + rgb_color_t result = rgb_color_t::none(); + bool has_term256 = !! (support & color_support_term256); + if ((!first_rgb.is_none() && has_term256) || first_named.is_none()) + { + result = first_rgb; + } + else + { + result = first_named; + } + if (result.is_none()) + { + result = candidates.at(0); + } + return result; +} + +/* This code should be refactored to enable sharing with builtin_set_color */ rgb_color_t parse_color(const wcstring &val, bool is_background) { int is_bold=0; @@ -530,30 +569,8 @@ rgb_color_t parse_color(const wcstring &val, bool is_background) } } } - - // Pick the best candidate - rgb_color_t first_rgb = rgb_color_t::none(), first_named = rgb_color_t::none(); - for (size_t i=0; i < candidates.size(); i++) - { - const rgb_color_t &color = candidates.at(i); - if (color.is_rgb() && first_rgb.is_none()) - first_rgb = color; - if (color.is_named() && first_named.is_none()) - first_named = color; - } - - // If we have both RGB and named colors, then prefer rgb if term256 is supported - rgb_color_t result; - bool has_term256 = !! (output_get_color_support() & color_support_term256); - if ((!first_rgb.is_none() && has_term256) || first_named.is_none()) - { - result = first_rgb; - } - else - { - result = first_named; - } - + rgb_color_t result = best_color(candidates, output_get_color_support()); + if (result.is_none()) result = rgb_color_t::normal(); diff --git a/output.h b/output.h index ccd94645a..6d1b4a010 100644 --- a/output.h +++ b/output.h @@ -132,6 +132,9 @@ typedef unsigned int color_support_t; color_support_t output_get_color_support(); void output_set_color_support(color_support_t support); +/** Given a list of rgb_color_t, pick the "best" one, as determined by the color support. Returns rgb_color_t::none() if empty */ +rgb_color_t best_color(const std::vector &colors, color_support_t support); + /* Exported for builtin_set_color's usage only */ void write_color(rgb_color_t color, bool is_fg); unsigned char index_for_color(rgb_color_t c);