Make set_color take multiple colors, and choose the best supported one

As suggested in #1323
This commit is contained in:
ridiculousfish 2014-11-09 16:42:35 -08:00
parent 43d23ee56e
commit e83441395e
3 changed files with 58 additions and 45 deletions

View File

@ -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<rgb_color_t> 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())
{

View File

@ -488,6 +488,45 @@ void writestr(const wchar_t *str)
delete[] buffer;
}
rgb_color_t best_color(const std::vector<rgb_color_t> &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();

View File

@ -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<rgb_color_t> &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);