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