From 8d6b468cdc0ab758b38cdf736e2764e2fa82871c Mon Sep 17 00:00:00 2001 From: Brad Town Date: Sun, 14 Nov 2021 10:04:51 -0800 Subject: [PATCH] rcfile: support #rgb format for specifying colors in 256-color terminals Most terminal emulators support a palette of 216 indexed colors: the 6x6x6 color cube pioneered by Xterm. But as an index gives little indication about what kind of color it produces, allow the user to specify the color with three hex digits instead, one for the level of red, green, and blue each, in the format #rgb. One hex digit allows for sixteen values, but as there are only six levels available, only 0, 4, 8, a, c, and e are significant -- other values get reduced to the nearest lower one. This fulfills https://savannah.gnu.org/bugs/?56445. Requested-by: Peter Liscovius, Erik Lundin, Owen Maresh, Dave Lemonby Signed-off-by: Brad Town --- src/rcfile.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/rcfile.c b/src/rcfile.c index 174716bf..0d967155 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -990,6 +990,19 @@ void parse_includes(char *ptr) free(expanded); } +/* Return the index of the color that is closest to the given RGB levels, + * assuming that the terminal uses the 6x6x6 color cube of xterm-256color. */ +short closest_index_color(short r, short g, short b) +{ + if (COLORS != 256) + return THE_DEFAULT; + + /* Translation table, from 16 intended levels to 6 available levels. */ + static const short level[] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 }; + + return (36 * level[r] + 6 * level[g] + level[b] + 16); +} + #define COLORCOUNT 20 const char hues[COLORCOUNT][8] = { "red", "green", "blue", @@ -1024,6 +1037,18 @@ short color_to_short(const char *colorname, bool *vivid, bool *thick) *thick = FALSE; } + if (colorname[0] == '#' && strlen(colorname) == 4) { + unsigned short r, g, b; + + if (*vivid) { + jot_error(N_("Color '%s' takes no prefix"), colorname); + return BAD_COLOR; + } + + if (sscanf(colorname, "#%1hX%1hX%1hX", &r, &g, &b) == 3) + return closest_index_color(r, g, b); + } + for (int index = 0; index < COLORCOUNT; index++) if (strcmp(colorname, hues[index]) == 0) { if (index > 7 && *vivid) {