color: support strike-through attribute
[git/git.git] / color.c
CommitLineData
7c92fe0e 1#include "cache.h"
85023577 2#include "color.h"
7c92fe0e 3
4c7f1819 4static int git_use_color_default = GIT_COLOR_AUTO;
e269eb79 5int color_stdout_is_tty = -1;
6b2f2d98 6
7cd52b5b
DM
7/*
8 * The list of available column colors.
9 */
10const char *column_colors_ansi[] = {
11 GIT_COLOR_RED,
12 GIT_COLOR_GREEN,
13 GIT_COLOR_YELLOW,
14 GIT_COLOR_BLUE,
15 GIT_COLOR_MAGENTA,
16 GIT_COLOR_CYAN,
17 GIT_COLOR_BOLD_RED,
18 GIT_COLOR_BOLD_GREEN,
19 GIT_COLOR_BOLD_YELLOW,
20 GIT_COLOR_BOLD_BLUE,
21 GIT_COLOR_BOLD_MAGENTA,
22 GIT_COLOR_BOLD_CYAN,
23 GIT_COLOR_RESET,
24};
25
26/* Ignore the RESET at the end when giving the size */
27const int column_colors_ansi_max = ARRAY_SIZE(column_colors_ansi) - 1;
28
695d95df
JK
29/* An individual foreground or background color. */
30struct color {
31 enum {
32 COLOR_UNSPECIFIED = 0,
33 COLOR_NORMAL,
34 COLOR_ANSI, /* basic 0-7 ANSI colors */
17a4be26
JK
35 COLOR_256,
36 COLOR_RGB
695d95df
JK
37 } type;
38 /* The numeric value for ANSI and 256-color modes */
39 unsigned char value;
17a4be26
JK
40 /* 24-bit RGB color values */
41 unsigned char red, green, blue;
695d95df
JK
42};
43
44/*
45 * "word" is a buffer of length "len"; does it match the NUL-terminated
46 * "match" exactly?
47 */
48static int match_word(const char *word, int len, const char *match)
7c92fe0e 49{
695d95df
JK
50 return !strncasecmp(word, match, len) && !match[len];
51}
52
17a4be26
JK
53static 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
695d95df
JK
63static int parse_color(struct color *out, const char *name, int len)
64{
65 /* Positions in array must match ANSI color codes */
7c92fe0e 66 static const char * const color_names[] = {
695d95df 67 "black", "red", "green", "yellow",
7c92fe0e
JK
68 "blue", "magenta", "cyan", "white"
69 };
70 char *end;
71 int i;
695d95df
JK
72 long val;
73
74 /* First try the special word "normal"... */
75 if (match_word(name, len, "normal")) {
76 out->type = COLOR_NORMAL;
77 return 0;
78 }
79
17a4be26
JK
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
695d95df 90 /* Then pick from our human-readable color names... */
7c92fe0e 91 for (i = 0; i < ARRAY_SIZE(color_names); i++) {
695d95df
JK
92 if (match_word(name, len, color_names[i])) {
93 out->type = COLOR_ANSI;
94 out->value = i;
95 return 0;
96 }
7c92fe0e 97 }
695d95df
JK
98
99 /* And finally try a literal 256-color-mode number */
100 val = strtol(name, &end, 10);
101 if (end - name == len) {
102 /*
103 * Allow "-1" as an alias for "normal", but other negative
104 * numbers are bogus.
105 */
106 if (val < -1)
107 ; /* fall through to error */
108 else if (val < 0) {
109 out->type = COLOR_NORMAL;
110 return 0;
111 /* Rewrite low numbers as more-portable standard colors. */
112 } else if (val < 8) {
113 out->type = COLOR_ANSI;
114 out->value = val;
3759d27a 115 return 0;
695d95df
JK
116 } else if (val < 256) {
117 out->type = COLOR_256;
118 out->value = val;
119 return 0;
120 }
121 }
122
123 return -1;
7c92fe0e
JK
124}
125
df8e472c 126static int parse_attr(const char *name, size_t len)
7c92fe0e 127{
df8e472c
JK
128 static const struct {
129 const char *name;
130 size_t len;
131 int val, neg;
132 } attrs[] = {
133#define ATTR(x, val, neg) { (x), sizeof(x)-1, (val), (neg) }
134 ATTR("bold", 1, 22),
135 ATTR("dim", 2, 22),
54590a0e 136 ATTR("italic", 3, 23),
df8e472c
JK
137 ATTR("ul", 4, 24),
138 ATTR("blink", 5, 25),
9dc3515c
JK
139 ATTR("reverse", 7, 27),
140 ATTR("strike", 9, 29)
df8e472c 141#undef ATTR
7c92fe0e 142 };
df8e472c 143 int negate = 0;
7c92fe0e 144 int i;
df8e472c 145
5621068f
JK
146 if (skip_prefix_mem(name, len, "no", &name, &len)) {
147 skip_prefix_mem(name, len, "-", &name, &len);
df8e472c 148 negate = 1;
5621068f 149 }
df8e472c
JK
150
151 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
152 if (attrs[i].len == len && !memcmp(attrs[i].name, name, len))
153 return negate ? attrs[i].neg : attrs[i].val;
7c92fe0e
JK
154 }
155 return -1;
156}
157
f6c5a296 158int color_parse(const char *value, char *dst)
2c2dc7c8 159{
f6c5a296 160 return color_parse_mem(value, strlen(value), dst);
2c2dc7c8
RS
161}
162
695d95df
JK
163/*
164 * Write the ANSI color codes for "c" to "out"; the string should
165 * already have the ANSI escape code in it. "out" should have enough
166 * space in it to fit any color.
167 */
168static char *color_output(char *out, const struct color *c, char type)
169{
170 switch (c->type) {
171 case COLOR_UNSPECIFIED:
172 case COLOR_NORMAL:
173 break;
174 case COLOR_ANSI:
175 *out++ = type;
176 *out++ = '0' + c->value;
177 break;
178 case COLOR_256:
179 out += sprintf(out, "%c8;5;%d", type, c->value);
180 break;
17a4be26
JK
181 case COLOR_RGB:
182 out += sprintf(out, "%c8;2;%d;%d;%d", type,
183 c->red, c->green, c->blue);
184 break;
695d95df
JK
185 }
186 return out;
187}
188
189static int color_empty(const struct color *c)
190{
191 return c->type <= COLOR_NORMAL;
192}
193
f6c5a296 194int color_parse_mem(const char *value, int value_len, char *dst)
7c92fe0e
JK
195{
196 const char *ptr = value;
2c2dc7c8 197 int len = value_len;
8b124135 198 unsigned int attr = 0;
695d95df
JK
199 struct color fg = { COLOR_UNSPECIFIED };
200 struct color bg = { COLOR_UNSPECIFIED };
7c92fe0e 201
2c2dc7c8 202 if (!strncasecmp(value, "reset", len)) {
dc6ebd4c 203 strcpy(dst, GIT_COLOR_RESET);
f6c5a296 204 return 0;
7c92fe0e
JK
205 }
206
8b124135 207 /* [fg [bg]] [attr]... */
2c2dc7c8 208 while (len > 0) {
7c92fe0e 209 const char *word = ptr;
695d95df 210 struct color c;
2c2dc7c8 211 int val, wordlen = 0;
7c92fe0e 212
2c2dc7c8
RS
213 while (len > 0 && !isspace(word[wordlen])) {
214 wordlen++;
215 len--;
216 }
7c92fe0e 217
2c2dc7c8
RS
218 ptr = word + wordlen;
219 while (len > 0 && isspace(*ptr)) {
7c92fe0e 220 ptr++;
2c2dc7c8
RS
221 len--;
222 }
7c92fe0e 223
695d95df
JK
224 if (!parse_color(&c, word, wordlen)) {
225 if (fg.type == COLOR_UNSPECIFIED) {
226 fg = c;
7c92fe0e
JK
227 continue;
228 }
695d95df
JK
229 if (bg.type == COLOR_UNSPECIFIED) {
230 bg = c;
7c92fe0e
JK
231 continue;
232 }
233 goto bad;
234 }
2c2dc7c8 235 val = parse_attr(word, wordlen);
8b124135
JH
236 if (0 <= val)
237 attr |= (1 << val);
238 else
7c92fe0e 239 goto bad;
7c92fe0e
JK
240 }
241
695d95df 242 if (attr || !color_empty(&fg) || !color_empty(&bg)) {
7c92fe0e 243 int sep = 0;
8b124135 244 int i;
7c92fe0e
JK
245
246 *dst++ = '\033';
247 *dst++ = '[';
8b124135
JH
248
249 for (i = 0; attr; i++) {
250 unsigned bit = (1 << i);
251 if (!(attr & bit))
252 continue;
253 attr &= ~bit;
254 if (sep++)
255 *dst++ = ';';
ff40d185 256 dst += sprintf(dst, "%d", i);
7c92fe0e 257 }
695d95df 258 if (!color_empty(&fg)) {
7c92fe0e
JK
259 if (sep++)
260 *dst++ = ';';
71b59849
JK
261 /* foreground colors are all in the 3x range */
262 dst = color_output(dst, &fg, '3');
7c92fe0e 263 }
695d95df 264 if (!color_empty(&bg)) {
7c92fe0e
JK
265 if (sep++)
266 *dst++ = ';';
71b59849
JK
267 /* background colors are all in the 4x range */
268 dst = color_output(dst, &bg, '4');
7c92fe0e
JK
269 }
270 *dst++ = 'm';
271 }
272 *dst = 0;
f6c5a296 273 return 0;
7c92fe0e 274bad:
f6c5a296 275 return error(_("invalid color value: %.*s"), value_len, value);
7c92fe0e
JK
276}
277
e269eb79 278int git_config_colorbool(const char *var, const char *value)
7c92fe0e 279{
57f2b842
JH
280 if (value) {
281 if (!strcasecmp(value, "never"))
282 return 0;
283 if (!strcasecmp(value, "always"))
284 return 1;
285 if (!strcasecmp(value, "auto"))
daa0c3d9 286 return GIT_COLOR_AUTO;
7c92fe0e 287 }
57f2b842 288
73e9da01
ML
289 if (!var)
290 return -1;
291
57f2b842
JH
292 /* Missing or explicit false to turn off colorization */
293 if (!git_config_bool(var, value))
7c92fe0e 294 return 0;
57f2b842
JH
295
296 /* any normal truth value defaults to 'auto' */
daa0c3d9
JK
297 return GIT_COLOR_AUTO;
298}
299
300static int check_auto_color(void)
301{
e269eb79
JK
302 if (color_stdout_is_tty < 0)
303 color_stdout_is_tty = isatty(1);
304 if (color_stdout_is_tty || (pager_in_use() && pager_use_color)) {
57f2b842
JH
305 char *term = getenv("TERM");
306 if (term && strcmp(term, "dumb"))
307 return 1;
308 }
309 return 0;
7c92fe0e
JK
310}
311
daa0c3d9
JK
312int want_color(int var)
313{
314 static int want_auto = -1;
315
c9bfb953
JK
316 if (var < 0)
317 var = git_use_color_default;
318
daa0c3d9
JK
319 if (var == GIT_COLOR_AUTO) {
320 if (want_auto < 0)
321 want_auto = check_auto_color();
322 return want_auto;
323 }
c9bfb953 324 return var;
daa0c3d9
JK
325}
326
3e1dd17a 327int git_color_config(const char *var, const char *value, void *cb)
6b2f2d98
MK
328{
329 if (!strcmp(var, "color.ui")) {
e269eb79 330 git_use_color_default = git_config_colorbool(var, value);
6b2f2d98
MK
331 return 0;
332 }
333
3e1dd17a
JK
334 return 0;
335}
336
337int git_color_default_config(const char *var, const char *value, void *cb)
338{
339 if (git_color_config(var, value, cb) < 0)
340 return -1;
341
ef90d6d4 342 return git_default_config(var, value, cb);
6b2f2d98
MK
343}
344
becbdae8
JN
345void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb)
346{
347 if (*color)
348 fprintf(fp, "%s", color);
349 fprintf(fp, "%s", sb->buf);
350 if (*color)
351 fprintf(fp, "%s", GIT_COLOR_RESET);
352}
353
f26a0012 354static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
7c92fe0e
JK
355 va_list args, const char *trail)
356{
357 int r = 0;
358
359 if (*color)
f26a0012
KH
360 r += fprintf(fp, "%s", color);
361 r += vfprintf(fp, fmt, args);
7c92fe0e 362 if (*color)
dc6ebd4c 363 r += fprintf(fp, "%s", GIT_COLOR_RESET);
7c92fe0e 364 if (trail)
f26a0012 365 r += fprintf(fp, "%s", trail);
7c92fe0e
JK
366 return r;
367}
368
369
370
f26a0012 371int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
7c92fe0e
JK
372{
373 va_list args;
374 int r;
375 va_start(args, fmt);
f26a0012 376 r = color_vfprintf(fp, color, fmt, args, NULL);
7c92fe0e
JK
377 va_end(args);
378 return r;
379}
380
f26a0012 381int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
7c92fe0e
JK
382{
383 va_list args;
384 int r;
385 va_start(args, fmt);
f26a0012 386 r = color_vfprintf(fp, color, fmt, args, "\n");
7c92fe0e
JK
387 va_end(args);
388 return r;
389}
148135fc
JK
390
391int color_is_nil(const char *c)
392{
393 return !strcmp(c, "NIL");
394}