Skip to content

Commit 17a4be2

Browse files
peffgitster
authored andcommitted
parse_color: support 24-bit RGB values
Some terminals (like XTerm) allow full 24-bit RGB color specifications using an extension to the regular ANSI color scheme. Let's allow users to specify hex RGB colors, enabling the all-important feature of hot pink ref decorations: git log --format="%h%C(#ff69b4)%d%C(reset) %s" Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 695d95d commit 17a4be2

File tree

4 files changed

+37
-5
lines changed

4 files changed

+37
-5
lines changed

Documentation/config.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,8 @@ doesn't matter.
828828
+
829829
Colors (foreground and background) may also be given as numbers between
830830
0 and 255; these use ANSI 256-color mode (but note that not all
831-
terminals may support this).
831+
terminals may support this). If your terminal supports it, you may also
832+
specify 24-bit RGB values as hex, like `#ff0ab3`.
832833

833834
color.diff::
834835
Whether to use ANSI escape sequences to add color to patches.

color.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,13 @@ struct color {
3232
COLOR_UNSPECIFIED = 0,
3333
COLOR_NORMAL,
3434
COLOR_ANSI, /* basic 0-7 ANSI colors */
35-
COLOR_256
35+
COLOR_256,
36+
COLOR_RGB
3637
} type;
3738
/* The numeric value for ANSI and 256-color modes */
3839
unsigned char value;
40+
/* 24-bit RGB color values */
41+
unsigned char red, green, blue;
3942
};
4043

4144
/*
@@ -47,6 +50,16 @@ static int match_word(const char *word, int len, const char *match)
4750
return !strncasecmp(word, match, len) && !match[len];
4851
}
4952

53+
static int get_hex_color(const char *in, unsigned char *out)
54+
{
55+
unsigned int val;
56+
val = (hexval(in[0]) << 4) | hexval(in[1]);
57+
if (val & ~0xff)
58+
return -1;
59+
*out = val;
60+
return 0;
61+
}
62+
5063
static int parse_color(struct color *out, const char *name, int len)
5164
{
5265
/* Positions in array must match ANSI color codes */
@@ -64,6 +77,16 @@ static int parse_color(struct color *out, const char *name, int len)
6477
return 0;
6578
}
6679

80+
/* Try a 24-bit RGB value */
81+
if (len == 7 && name[0] == '#') {
82+
if (!get_hex_color(name + 1, &out->red) &&
83+
!get_hex_color(name + 3, &out->green) &&
84+
!get_hex_color(name + 5, &out->blue)) {
85+
out->type = COLOR_RGB;
86+
return 0;
87+
}
88+
}
89+
6790
/* Then pick from our human-readable color names... */
6891
for (i = 0; i < ARRAY_SIZE(color_names); i++) {
6992
if (match_word(name, len, color_names[i])) {
@@ -140,6 +163,10 @@ static char *color_output(char *out, const struct color *c, char type)
140163
case COLOR_256:
141164
out += sprintf(out, "%c8;5;%d", type, c->value);
142165
break;
166+
case COLOR_RGB:
167+
out += sprintf(out, "%c8;2;%d;%d;%d", type,
168+
c->red, c->green, c->blue);
169+
break;
143170
}
144171
return out;
145172
}

color.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ struct strbuf;
99
* The maximum length of ANSI color sequence we would generate:
1010
* - leading ESC '[' 2
1111
* - attr + ';' 2 * 8 (e.g. "1;")
12-
* - fg color + ';' 9 (e.g. "38;5;2xx;")
13-
* - fg color + ';' 9 (e.g. "48;5;2xx;")
12+
* - fg color + ';' 17 (e.g. "38;2;255;255;255;")
13+
* - bg color + ';' 17 (e.g. "48;2;255;255;255;")
1414
* - terminating 'm' NUL 2
1515
*
1616
* The above overcounts attr (we only use 5 not 8) and one semicolon
1717
* but it is close enough.
1818
*/
19-
#define COLOR_MAXLEN 40
19+
#define COLOR_MAXLEN 56
2020

2121
/*
2222
* IMPORTANT: Due to the way these color codes are emulated on Windows,

t/t4026-color.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ test_expect_success '256 colors' '
5353
color "254 bold 255" "[1;38;5;254;48;5;255m"
5454
'
5555

56+
test_expect_success '24-bit colors' '
57+
color "#ff00ff black" "[38;2;255;0;255;40m"
58+
'
59+
5660
test_expect_success '"normal" yields no color at all"' '
5761
color "normal black" "[40m"
5862
'

0 commit comments

Comments
 (0)