Skip to content

Commit f37399e

Browse files
tihirvonJunio C Hamano
authored andcommitted
diff: Support both attributes and colors
Make it possible to set both colors and a attribute for diff colors. Background colors are supported too. Syntax is now: [attr] [fg [bg]] [fg [bg]] [attr] Empty value is same as "normal normal", ie use default colors. The new syntax is backwards compatible. Signed-off-by: Timo Hirvonen <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ff4d780 commit f37399e

File tree

1 file changed

+107
-57
lines changed

1 file changed

+107
-57
lines changed

diff.c

Lines changed: 107 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,14 @@ enum color_diff {
2626
DIFF_FILE_NEW = 5,
2727
};
2828

29-
#define COLOR_NORMAL ""
30-
#define COLOR_BOLD "\033[1m"
31-
#define COLOR_DIM "\033[2m"
32-
#define COLOR_UL "\033[4m"
33-
#define COLOR_BLINK "\033[5m"
34-
#define COLOR_REVERSE "\033[7m"
35-
#define COLOR_RESET "\033[m"
36-
37-
#define COLOR_BLACK "\033[30m"
38-
#define COLOR_RED "\033[31m"
39-
#define COLOR_GREEN "\033[32m"
40-
#define COLOR_YELLOW "\033[33m"
41-
#define COLOR_BLUE "\033[34m"
42-
#define COLOR_MAGENTA "\033[35m"
43-
#define COLOR_CYAN "\033[36m"
44-
#define COLOR_WHITE "\033[37m"
45-
46-
static const char *diff_colors[] = {
47-
COLOR_RESET,
48-
COLOR_NORMAL,
49-
COLOR_BOLD,
50-
COLOR_CYAN,
51-
COLOR_RED,
52-
COLOR_GREEN
29+
/* "\033[1;30;47m\0" is 11 bytes */
30+
static char diff_colors[][16] = {
31+
"\033[m", /* reset */
32+
"", /* normal */
33+
"\033[1m", /* bold */
34+
"\033[36m", /* cyan */
35+
"\033[31m", /* red */
36+
"\033[32m" /* green */
5337
};
5438

5539
static int parse_diff_color_slot(const char *var, int ofs)
@@ -67,38 +51,104 @@ static int parse_diff_color_slot(const char *var, int ofs)
6751
die("bad config variable '%s'", var);
6852
}
6953

70-
static const char *parse_diff_color_value(const char *value, const char *var)
71-
{
72-
if (!strcasecmp(value, "normal"))
73-
return COLOR_NORMAL;
74-
if (!strcasecmp(value, "bold"))
75-
return COLOR_BOLD;
76-
if (!strcasecmp(value, "dim"))
77-
return COLOR_DIM;
78-
if (!strcasecmp(value, "ul"))
79-
return COLOR_UL;
80-
if (!strcasecmp(value, "blink"))
81-
return COLOR_BLINK;
82-
if (!strcasecmp(value, "reverse"))
83-
return COLOR_REVERSE;
84-
if (!strcasecmp(value, "reset"))
85-
return COLOR_RESET;
86-
if (!strcasecmp(value, "black"))
87-
return COLOR_BLACK;
88-
if (!strcasecmp(value, "red"))
89-
return COLOR_RED;
90-
if (!strcasecmp(value, "green"))
91-
return COLOR_GREEN;
92-
if (!strcasecmp(value, "yellow"))
93-
return COLOR_YELLOW;
94-
if (!strcasecmp(value, "blue"))
95-
return COLOR_BLUE;
96-
if (!strcasecmp(value, "magenta"))
97-
return COLOR_MAGENTA;
98-
if (!strcasecmp(value, "cyan"))
99-
return COLOR_CYAN;
100-
if (!strcasecmp(value, "white"))
101-
return COLOR_WHITE;
54+
static int parse_color(const char *name, int len)
55+
{
56+
static const char * const color_names[] = {
57+
"normal", "black", "red", "green", "yellow",
58+
"blue", "magenta", "cyan", "white"
59+
};
60+
int i;
61+
for (i = 0; i < ARRAY_SIZE(color_names); i++) {
62+
const char *str = color_names[i];
63+
if (!strncasecmp(name, str, len) && !str[len])
64+
return i - 1;
65+
}
66+
return -2;
67+
}
68+
69+
static int parse_attr(const char *name, int len)
70+
{
71+
static const int attr_values[] = { 1, 2, 4, 5, 7 };
72+
static const char * const attr_names[] = {
73+
"bold", "dim", "ul", "blink", "reverse"
74+
};
75+
int i;
76+
for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
77+
const char *str = attr_names[i];
78+
if (!strncasecmp(name, str, len) && !str[len])
79+
return attr_values[i];
80+
}
81+
return -1;
82+
}
83+
84+
static void parse_diff_color_value(const char *value, const char *var, char *dst)
85+
{
86+
const char *ptr = value;
87+
int attr = -1;
88+
int fg = -2;
89+
int bg = -2;
90+
91+
if (!strcasecmp(value, "reset")) {
92+
strcpy(dst, "\033[m");
93+
return;
94+
}
95+
96+
/* [fg [bg]] [attr] */
97+
while (*ptr) {
98+
const char *word = ptr;
99+
int val, len = 0;
100+
101+
while (word[len] && !isspace(word[len]))
102+
len++;
103+
104+
ptr = word + len;
105+
while (*ptr && isspace(*ptr))
106+
ptr++;
107+
108+
val = parse_color(word, len);
109+
if (val >= -1) {
110+
if (fg == -2) {
111+
fg = val;
112+
continue;
113+
}
114+
if (bg == -2) {
115+
bg = val;
116+
continue;
117+
}
118+
goto bad;
119+
}
120+
val = parse_attr(word, len);
121+
if (val < 0 || attr != -1)
122+
goto bad;
123+
attr = val;
124+
}
125+
126+
if (attr >= 0 || fg >= 0 || bg >= 0) {
127+
int sep = 0;
128+
129+
*dst++ = '\033';
130+
*dst++ = '[';
131+
if (attr >= 0) {
132+
*dst++ = '0' + attr;
133+
sep++;
134+
}
135+
if (fg >= 0) {
136+
if (sep++)
137+
*dst++ = ';';
138+
*dst++ = '3';
139+
*dst++ = '0' + fg;
140+
}
141+
if (bg >= 0) {
142+
if (sep++)
143+
*dst++ = ';';
144+
*dst++ = '4';
145+
*dst++ = '0' + bg;
146+
}
147+
*dst++ = 'm';
148+
}
149+
*dst = 0;
150+
return;
151+
bad:
102152
die("bad config value '%s' for variable '%s'", value, var);
103153
}
104154

@@ -145,7 +195,7 @@ int git_diff_ui_config(const char *var, const char *value)
145195
}
146196
if (!strncmp(var, "diff.color.", 11)) {
147197
int slot = parse_diff_color_slot(var, 11);
148-
diff_colors[slot] = parse_diff_color_value(value, var);
198+
parse_diff_color_value(value, var, diff_colors[slot]);
149199
return 0;
150200
}
151201
return git_default_config(var, value);

0 commit comments

Comments
 (0)