color: add support for 12-bit RGB colors
RGB color parsing currently supports 24-bit values in the form #RRGGBB. As in Cascading Style Sheets (CSS [1]), also allow to specify an RGB color using only three digits with #RGB. In this shortened form, each of the digits is – again, as in CSS – duplicated to convert the color to 24 bits, e.g. #f1b specifies the same color as #ff11bb. In color.h, remove the '0x' prefix in the example to match the actual syntax. [1] https://developer.mozilla.org/en-US/docs/Web/CSS/hex-color Signed-off-by: Beat Bolli <dev+git@drbeat.li> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Beat Bolli committed
May 2, 2024 at 13:03 UTC
7b97dfe47ba3a61f09cc26154540d74afdd3283d
4 files changed
+24
-13
Documentation/config.txt
+2
-1
@@ -316,7 +316,8 @@ terminals, this is usually not the same as setting to "white black".
316
Colors may also be given as numbers between 0 and 255; these use ANSI
317
256-color mode (but note that not all terminals may support this). If
318
your terminal supports it, you may also specify 24-bit RGB values as
319
-hex, like `#ff0ab3`.
319
+hex, like `#ff0ab3`, or 12-bit RGB values like `#f1b`, which is
320
+equivalent to the 24-bit color `#ff11bb`.
321
+
322
The accepted attributes are `bold`, `dim`, `ul`, `blink`, `reverse`,
323
`italic`, and `strike` (for crossed-out or "strikethrough" letters).
color.c
+14
-7
@@ -64,12 +64,16 @@ static int match_word(const char *word, int len, const char *match)
64
return !strncasecmp(word, match, len) && !match[len];
65
}
66
67
-static int get_hex_color(const char *in, unsigned char *out)
67
+static int get_hex_color(const char **inp, int width, unsigned char *out)
68
{
69
+ const char *in = *inp;
70
unsigned int val;
70
- val = (hexval(in[0]) << 4) | hexval(in[1]);
71
+
72
+ assert(width == 1 || width == 2);
73
+ val = (hexval(in[0]) << 4) | hexval(in[width - 1]);
74
if (val & ~0xff)
75
return -1;
76
+ *inp += width;
77
*out = val;
78
return 0;
79
}
@@ -135,11 +139,14 @@ static int parse_color(struct color *out, const char *name, int len)
139
return 0;
140
}
141
138
- /* Try a 24-bit RGB value */
139
- if (len == 7 && name[0] == '#') {
140
- if (!get_hex_color(name + 1, &out->red) &&
141
- !get_hex_color(name + 3, &out->green) &&
142
- !get_hex_color(name + 5, &out->blue)) {
142
+ /* Try a 24- or 12-bit RGB value prefixed with '#' */
143
+ if ((len == 7 || len == 4) && name[0] == '#') {
144
+ int width_per_color = (len == 7) ? 2 : 1;
145
+ const char *color = name + 1;
146
+
147
+ if (!get_hex_color(&color, width_per_color, &out->red) &&
148
+ !get_hex_color(&color, width_per_color, &out->green) &&
149
+ !get_hex_color(&color, width_per_color, &out->blue)) {
150
out->type = COLOR_RGB;
151
return 0;
152
}
color.h
+2
-1
@@ -112,7 +112,8 @@ int want_color_fd(int fd, int var);
112
* Translate a Git color from 'value' into a string that the terminal can
113
* interpret and store it into 'dst'. The Git color values are of the form
114
* "foreground [background] [attr]" where fore- and background can be a color
115
- * name ("red"), a RGB code (#0xFF0000) or a 256-color-mode from the terminal.
115
+ * name ("red"), a RGB code (#FF0000 or #F00) or a 256-color-mode from the
116
+ * terminal.
117
*/
118
int color_parse(const char *value, char *dst);
119
int color_parse_mem(const char *value, int len, char *dst);
t/t4026-color.sh
+6
-4
@@ -96,8 +96,8 @@ test_expect_success '256 colors' '
96
color "254 bold 255" "[1;38;5;254;48;5;255m"
97
'
98
99
-test_expect_success '24-bit colors' '
100
- color "#ff00ff black" "[38;2;255;0;255;40m"
99
+test_expect_success 'RGB colors' '
100
+ color "#ff00ff #0f0" "[38;2;255;0;255;48;2;0;255;0m"
101
'
102
103
test_expect_success '"default" foreground' '
@@ -146,13 +146,15 @@ test_expect_success 'non-hex character in RGB color' '
146
invalid_color "#12x456" &&
147
invalid_color "#123x56" &&
148
invalid_color "#1234x6" &&
149
- invalid_color "#12345x"
149
+ invalid_color "#12345x" &&
150
+ invalid_color "#x23" &&
151
+ invalid_color "#1x3" &&
152
+ invalid_color "#12x"
153
'
154
155
test_expect_success 'wrong number of letters in RGB color' '
156
invalid_color "#1" &&
157
invalid_color "#23" &&
155
- invalid_color "#456" &&
158
invalid_color "#789a" &&
159
invalid_color "#bcdef" &&
160
invalid_color "#1234567"