]> git.ipfire.org Git - thirdparty/git.git/blame - color.c
treewide: remove cache.h inclusion due to object.h changes
[thirdparty/git.git] / color.c
CommitLineData
7c92fe0e 1#include "cache.h"
b2141fc1 2#include "config.h"
85023577 3#include "color.h"
f394e093 4#include "gettext.h"
41771fa4 5#include "hex.h"
7c92fe0e 6
4c7f1819 7static int git_use_color_default = GIT_COLOR_AUTO;
e269eb79 8int color_stdout_is_tty = -1;
6b2f2d98 9
7cd52b5b
DM
10/*
11 * The list of available column colors.
12 */
13const char *column_colors_ansi[] = {
14 GIT_COLOR_RED,
15 GIT_COLOR_GREEN,
16 GIT_COLOR_YELLOW,
17 GIT_COLOR_BLUE,
18 GIT_COLOR_MAGENTA,
19 GIT_COLOR_CYAN,
20 GIT_COLOR_BOLD_RED,
21 GIT_COLOR_BOLD_GREEN,
22 GIT_COLOR_BOLD_YELLOW,
23 GIT_COLOR_BOLD_BLUE,
24 GIT_COLOR_BOLD_MAGENTA,
25 GIT_COLOR_BOLD_CYAN,
26 GIT_COLOR_RESET,
27};
28
4a28eb0a
ES
29enum {
30 COLOR_BACKGROUND_OFFSET = 10,
31 COLOR_FOREGROUND_ANSI = 30,
32 COLOR_FOREGROUND_RGB = 38,
33 COLOR_FOREGROUND_256 = 38,
1751b09a 34 COLOR_FOREGROUND_BRIGHT_ANSI = 90,
4a28eb0a
ES
35};
36
7cd52b5b
DM
37/* Ignore the RESET at the end when giving the size */
38const int column_colors_ansi_max = ARRAY_SIZE(column_colors_ansi) - 1;
39
695d95df
JK
40/* An individual foreground or background color. */
41struct color {
42 enum {
43 COLOR_UNSPECIFIED = 0,
44 COLOR_NORMAL,
05f1f41c 45 COLOR_ANSI, /* basic 0-7 ANSI colors + "default" (value = 9) */
17a4be26
JK
46 COLOR_256,
47 COLOR_RGB
695d95df
JK
48 } type;
49 /* The numeric value for ANSI and 256-color modes */
50 unsigned char value;
17a4be26
JK
51 /* 24-bit RGB color values */
52 unsigned char red, green, blue;
695d95df
JK
53};
54
55/*
56 * "word" is a buffer of length "len"; does it match the NUL-terminated
57 * "match" exactly?
58 */
59static int match_word(const char *word, int len, const char *match)
7c92fe0e 60{
695d95df
JK
61 return !strncasecmp(word, match, len) && !match[len];
62}
63
17a4be26
JK
64static int get_hex_color(const char *in, unsigned char *out)
65{
66 unsigned int val;
67 val = (hexval(in[0]) << 4) | hexval(in[1]);
68 if (val & ~0xff)
69 return -1;
70 *out = val;
71 return 0;
72}
73
1751b09a
ES
74/*
75 * If an ANSI color is recognized in "name", fill "out" and return 0.
76 * Otherwise, leave out unchanged and return -1.
77 */
78static int parse_ansi_color(struct color *out, const char *name, int len)
695d95df
JK
79{
80 /* Positions in array must match ANSI color codes */
7c92fe0e 81 static const char * const color_names[] = {
695d95df 82 "black", "red", "green", "yellow",
7c92fe0e
JK
83 "blue", "magenta", "cyan", "white"
84 };
7c92fe0e 85 int i;
1751b09a
ES
86 int color_offset = COLOR_FOREGROUND_ANSI;
87
05f1f41c
RE
88 if (match_word(name, len, "default")) {
89 /*
90 * Restores to the terminal's default color, which may not be
91 * the same as explicitly setting "white" or "black".
92 *
93 * ECMA-48 - Control Functions \
94 * for Coded Character Sets, 5th edition (June 1991):
95 * > 39 default display colour (implementation-defined)
96 * > 49 default background colour (implementation-defined)
97 *
98 * Although not supported /everywhere/--according to terminfo,
99 * some terminals define "op" (original pair) as a blunt
100 * "set to white on black", or even "send full SGR reset"--
101 * it's standard and well-supported enough that if a user
102 * asks for it in their config this will do the right thing.
103 */
104 out->type = COLOR_ANSI;
105 out->value = 9 + color_offset;
106 return 0;
107 }
108
1751b09a
ES
109 if (strncasecmp(name, "bright", 6) == 0) {
110 color_offset = COLOR_FOREGROUND_BRIGHT_ANSI;
111 name += 6;
112 len -= 6;
113 }
114 for (i = 0; i < ARRAY_SIZE(color_names); i++) {
115 if (match_word(name, len, color_names[i])) {
116 out->type = COLOR_ANSI;
117 out->value = i + color_offset;
118 return 0;
119 }
120 }
121 return -1;
122}
123
124static int parse_color(struct color *out, const char *name, int len)
125{
126 char *end;
695d95df
JK
127 long val;
128
129 /* First try the special word "normal"... */
130 if (match_word(name, len, "normal")) {
131 out->type = COLOR_NORMAL;
132 return 0;
133 }
134
17a4be26
JK
135 /* Try a 24-bit RGB value */
136 if (len == 7 && name[0] == '#') {
137 if (!get_hex_color(name + 1, &out->red) &&
138 !get_hex_color(name + 3, &out->green) &&
139 !get_hex_color(name + 5, &out->blue)) {
140 out->type = COLOR_RGB;
141 return 0;
142 }
143 }
144
695d95df 145 /* Then pick from our human-readable color names... */
1751b09a
ES
146 if (parse_ansi_color(out, name, len) == 0) {
147 return 0;
7c92fe0e 148 }
695d95df
JK
149
150 /* And finally try a literal 256-color-mode number */
151 val = strtol(name, &end, 10);
152 if (end - name == len) {
153 /*
154 * Allow "-1" as an alias for "normal", but other negative
155 * numbers are bogus.
156 */
157 if (val < -1)
158 ; /* fall through to error */
159 else if (val < 0) {
160 out->type = COLOR_NORMAL;
161 return 0;
c444f032 162 /* Rewrite 0-7 as more-portable standard colors. */
695d95df
JK
163 } else if (val < 8) {
164 out->type = COLOR_ANSI;
4a28eb0a 165 out->value = val + COLOR_FOREGROUND_ANSI;
3759d27a 166 return 0;
c444f032
ES
167 /* Rewrite 8-15 as more-portable aixterm colors. */
168 } else if (val < 16) {
169 out->type = COLOR_ANSI;
170 out->value = val - 8 + COLOR_FOREGROUND_BRIGHT_ANSI;
171 return 0;
695d95df
JK
172 } else if (val < 256) {
173 out->type = COLOR_256;
174 out->value = val;
175 return 0;
176 }
177 }
178
179 return -1;
7c92fe0e
JK
180}
181
df8e472c 182static int parse_attr(const char *name, size_t len)
7c92fe0e 183{
df8e472c
JK
184 static const struct {
185 const char *name;
186 size_t len;
187 int val, neg;
188 } attrs[] = {
189#define ATTR(x, val, neg) { (x), sizeof(x)-1, (val), (neg) }
190 ATTR("bold", 1, 22),
191 ATTR("dim", 2, 22),
54590a0e 192 ATTR("italic", 3, 23),
df8e472c
JK
193 ATTR("ul", 4, 24),
194 ATTR("blink", 5, 25),
9dc3515c
JK
195 ATTR("reverse", 7, 27),
196 ATTR("strike", 9, 29)
df8e472c 197#undef ATTR
7c92fe0e 198 };
df8e472c 199 int negate = 0;
7c92fe0e 200 int i;
df8e472c 201
5621068f
JK
202 if (skip_prefix_mem(name, len, "no", &name, &len)) {
203 skip_prefix_mem(name, len, "-", &name, &len);
df8e472c 204 negate = 1;
5621068f 205 }
df8e472c
JK
206
207 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
208 if (attrs[i].len == len && !memcmp(attrs[i].name, name, len))
209 return negate ? attrs[i].neg : attrs[i].val;
7c92fe0e
JK
210 }
211 return -1;
212}
213
f6c5a296 214int color_parse(const char *value, char *dst)
2c2dc7c8 215{
f6c5a296 216 return color_parse_mem(value, strlen(value), dst);
2c2dc7c8
RS
217}
218
695d95df
JK
219/*
220 * Write the ANSI color codes for "c" to "out"; the string should
221 * already have the ANSI escape code in it. "out" should have enough
222 * space in it to fit any color.
223 */
4a28eb0a 224static char *color_output(char *out, int len, const struct color *c, int background)
695d95df 225{
4a28eb0a
ES
226 int offset = 0;
227
228 if (background)
229 offset = COLOR_BACKGROUND_OFFSET;
695d95df
JK
230 switch (c->type) {
231 case COLOR_UNSPECIFIED:
232 case COLOR_NORMAL:
233 break;
234 case COLOR_ANSI:
4a28eb0a 235 out += xsnprintf(out, len, "%d", c->value + offset);
695d95df
JK
236 break;
237 case COLOR_256:
4a28eb0a
ES
238 out += xsnprintf(out, len, "%d;5;%d", COLOR_FOREGROUND_256 + offset,
239 c->value);
695d95df 240 break;
17a4be26 241 case COLOR_RGB:
4a28eb0a
ES
242 out += xsnprintf(out, len, "%d;2;%d;%d;%d",
243 COLOR_FOREGROUND_RGB + offset,
cbc8feea 244 c->red, c->green, c->blue);
17a4be26 245 break;
695d95df
JK
246 }
247 return out;
248}
249
250static int color_empty(const struct color *c)
251{
252 return c->type <= COLOR_NORMAL;
253}
254
f6c5a296 255int color_parse_mem(const char *value, int value_len, char *dst)
7c92fe0e
JK
256{
257 const char *ptr = value;
2c2dc7c8 258 int len = value_len;
cbc8feea 259 char *end = dst + COLOR_MAXLEN;
de658515 260 unsigned int has_reset = 0;
8b124135 261 unsigned int attr = 0;
695d95df
JK
262 struct color fg = { COLOR_UNSPECIFIED };
263 struct color bg = { COLOR_UNSPECIFIED };
7c92fe0e 264
bc407565
NTND
265 while (len > 0 && isspace(*ptr)) {
266 ptr++;
267 len--;
268 }
269
55cccf4b
JK
270 if (!len) {
271 dst[0] = '\0';
272 return 0;
273 }
c2f41bf5 274
de658515 275 /* [reset] [fg [bg]] [attr]... */
2c2dc7c8 276 while (len > 0) {
7c92fe0e 277 const char *word = ptr;
3e1952ed 278 struct color c = { COLOR_UNSPECIFIED };
2c2dc7c8 279 int val, wordlen = 0;
7c92fe0e 280
2c2dc7c8
RS
281 while (len > 0 && !isspace(word[wordlen])) {
282 wordlen++;
283 len--;
284 }
7c92fe0e 285
2c2dc7c8
RS
286 ptr = word + wordlen;
287 while (len > 0 && isspace(*ptr)) {
7c92fe0e 288 ptr++;
2c2dc7c8
RS
289 len--;
290 }
7c92fe0e 291
de658515
RE
292 if (match_word(word, wordlen, "reset")) {
293 has_reset = 1;
294 continue;
295 }
296
695d95df
JK
297 if (!parse_color(&c, word, wordlen)) {
298 if (fg.type == COLOR_UNSPECIFIED) {
299 fg = c;
7c92fe0e
JK
300 continue;
301 }
695d95df
JK
302 if (bg.type == COLOR_UNSPECIFIED) {
303 bg = c;
7c92fe0e
JK
304 continue;
305 }
306 goto bad;
307 }
2c2dc7c8 308 val = parse_attr(word, wordlen);
8b124135
JH
309 if (0 <= val)
310 attr |= (1 << val);
311 else
7c92fe0e 312 goto bad;
7c92fe0e
JK
313 }
314
cbc8feea
JK
315#undef OUT
316#define OUT(x) do { \
317 if (dst == end) \
033abf97 318 BUG("color parsing ran out of space"); \
cbc8feea
JK
319 *dst++ = (x); \
320} while(0)
321
de658515 322 if (has_reset || attr || !color_empty(&fg) || !color_empty(&bg)) {
7c92fe0e 323 int sep = 0;
8b124135 324 int i;
7c92fe0e 325
cbc8feea
JK
326 OUT('\033');
327 OUT('[');
8b124135 328
de658515
RE
329 if (has_reset)
330 sep++;
331
8b124135
JH
332 for (i = 0; attr; i++) {
333 unsigned bit = (1 << i);
334 if (!(attr & bit))
335 continue;
336 attr &= ~bit;
337 if (sep++)
cbc8feea
JK
338 OUT(';');
339 dst += xsnprintf(dst, end - dst, "%d", i);
7c92fe0e 340 }
695d95df 341 if (!color_empty(&fg)) {
7c92fe0e 342 if (sep++)
cbc8feea 343 OUT(';');
4a28eb0a 344 dst = color_output(dst, end - dst, &fg, 0);
7c92fe0e 345 }
695d95df 346 if (!color_empty(&bg)) {
7c92fe0e 347 if (sep++)
cbc8feea 348 OUT(';');
4a28eb0a 349 dst = color_output(dst, end - dst, &bg, 1);
7c92fe0e 350 }
cbc8feea 351 OUT('m');
7c92fe0e 352 }
cbc8feea 353 OUT(0);
f6c5a296 354 return 0;
7c92fe0e 355bad:
f6c5a296 356 return error(_("invalid color value: %.*s"), value_len, value);
cbc8feea 357#undef OUT
7c92fe0e
JK
358}
359
e269eb79 360int git_config_colorbool(const char *var, const char *value)
7c92fe0e 361{
57f2b842
JH
362 if (value) {
363 if (!strcasecmp(value, "never"))
364 return 0;
365 if (!strcasecmp(value, "always"))
2c1acdf6 366 return 1;
57f2b842 367 if (!strcasecmp(value, "auto"))
daa0c3d9 368 return GIT_COLOR_AUTO;
7c92fe0e 369 }
57f2b842 370
73e9da01
ML
371 if (!var)
372 return -1;
373
57f2b842
JH
374 /* Missing or explicit false to turn off colorization */
375 if (!git_config_bool(var, value))
7c92fe0e 376 return 0;
57f2b842
JH
377
378 /* any normal truth value defaults to 'auto' */
daa0c3d9
JK
379 return GIT_COLOR_AUTO;
380}
381
295d949c 382static int check_auto_color(int fd)
daa0c3d9 383{
295d949c
JS
384 static int color_stderr_is_tty = -1;
385 int *is_tty_p = fd == 1 ? &color_stdout_is_tty : &color_stderr_is_tty;
386 if (*is_tty_p < 0)
387 *is_tty_p = isatty(fd);
388 if (*is_tty_p || (fd == 1 && pager_in_use() && pager_use_color)) {
a64f213d 389 if (!is_terminal_dumb())
57f2b842
JH
390 return 1;
391 }
392 return 0;
7c92fe0e
JK
393}
394
295d949c 395int want_color_fd(int fd, int var)
daa0c3d9 396{
6cdf8a79
397 /*
398 * NEEDSWORK: This function is sometimes used from multiple threads, and
399 * we end up using want_auto racily. That "should not matter" since
400 * we always write the same value, but it's still wrong. This function
401 * is listed in .tsan-suppressions for the time being.
402 */
403
295d949c 404 static int want_auto[3] = { -1, -1, -1 };
daa0c3d9 405
65bb21e7
ES
406 if (fd < 1 || fd >= ARRAY_SIZE(want_auto))
407 BUG("file descriptor out of range: %d", fd);
408
c9bfb953
JK
409 if (var < 0)
410 var = git_use_color_default;
411
daa0c3d9 412 if (var == GIT_COLOR_AUTO) {
295d949c
JS
413 if (want_auto[fd] < 0)
414 want_auto[fd] = check_auto_color(fd);
415 return want_auto[fd];
daa0c3d9 416 }
c9bfb953 417 return var;
daa0c3d9
JK
418}
419
5cf88fd8 420int git_color_config(const char *var, const char *value, void *cb UNUSED)
6b2f2d98
MK
421{
422 if (!strcmp(var, "color.ui")) {
e269eb79 423 git_use_color_default = git_config_colorbool(var, value);
6b2f2d98
MK
424 return 0;
425 }
426
3e1dd17a
JK
427 return 0;
428}
429
33c643bb
JK
430int git_color_default_config(const char *var, const char *value, void *cb)
431{
432 if (git_color_config(var, value, cb) < 0)
433 return -1;
434
435 return git_default_config(var, value, cb);
436}
437
becbdae8
JN
438void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb)
439{
440 if (*color)
441 fprintf(fp, "%s", color);
442 fprintf(fp, "%s", sb->buf);
443 if (*color)
444 fprintf(fp, "%s", GIT_COLOR_RESET);
445}
446
f26a0012 447static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
7c92fe0e
JK
448 va_list args, const char *trail)
449{
450 int r = 0;
451
452 if (*color)
f26a0012
KH
453 r += fprintf(fp, "%s", color);
454 r += vfprintf(fp, fmt, args);
7c92fe0e 455 if (*color)
dc6ebd4c 456 r += fprintf(fp, "%s", GIT_COLOR_RESET);
7c92fe0e 457 if (trail)
f26a0012 458 r += fprintf(fp, "%s", trail);
7c92fe0e
JK
459 return r;
460}
461
f26a0012 462int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
7c92fe0e
JK
463{
464 va_list args;
465 int r;
466 va_start(args, fmt);
f26a0012 467 r = color_vfprintf(fp, color, fmt, args, NULL);
7c92fe0e
JK
468 va_end(args);
469 return r;
470}
471
f26a0012 472int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
7c92fe0e
JK
473{
474 va_list args;
475 int r;
476 va_start(args, fmt);
f26a0012 477 r = color_vfprintf(fp, color, fmt, args, "\n");
7c92fe0e
JK
478 va_end(args);
479 return r;
480}
148135fc
JK
481
482int color_is_nil(const char *c)
483{
484 return !strcmp(c, "NIL");
485}