]> git.ipfire.org Git - thirdparty/git.git/blame - color.c
t4034: abstract away SHA-1-specific constants
[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
695d95df
JK
164/*
165 * Write the ANSI color codes for "c" to "out"; the string should
166 * already have the ANSI escape code in it. "out" should have enough
167 * space in it to fit any color.
168 */
cbc8feea 169static char *color_output(char *out, int len, const struct color *c, char type)
695d95df
JK
170{
171 switch (c->type) {
172 case COLOR_UNSPECIFIED:
173 case COLOR_NORMAL:
174 break;
175 case COLOR_ANSI:
cbc8feea 176 if (len < 2)
033abf97 177 BUG("color parsing ran out of space");
695d95df
JK
178 *out++ = type;
179 *out++ = '0' + c->value;
180 break;
181 case COLOR_256:
cbc8feea 182 out += xsnprintf(out, len, "%c8;5;%d", type, c->value);
695d95df 183 break;
17a4be26 184 case COLOR_RGB:
cbc8feea
JK
185 out += xsnprintf(out, len, "%c8;2;%d;%d;%d", type,
186 c->red, c->green, c->blue);
17a4be26 187 break;
695d95df
JK
188 }
189 return out;
190}
191
192static int color_empty(const struct color *c)
193{
194 return c->type <= COLOR_NORMAL;
195}
196
f6c5a296 197int color_parse_mem(const char *value, int value_len, char *dst)
7c92fe0e
JK
198{
199 const char *ptr = value;
2c2dc7c8 200 int len = value_len;
cbc8feea 201 char *end = dst + COLOR_MAXLEN;
8b124135 202 unsigned int attr = 0;
695d95df
JK
203 struct color fg = { COLOR_UNSPECIFIED };
204 struct color bg = { COLOR_UNSPECIFIED };
7c92fe0e 205
bc407565
NTND
206 while (len > 0 && isspace(*ptr)) {
207 ptr++;
208 len--;
209 }
210
55cccf4b
JK
211 if (!len) {
212 dst[0] = '\0';
213 return 0;
214 }
c2f41bf5 215
bc407565 216 if (!strncasecmp(ptr, "reset", len)) {
cbc8feea 217 xsnprintf(dst, end - dst, GIT_COLOR_RESET);
f6c5a296 218 return 0;
7c92fe0e
JK
219 }
220
8b124135 221 /* [fg [bg]] [attr]... */
2c2dc7c8 222 while (len > 0) {
7c92fe0e 223 const char *word = ptr;
3e1952ed 224 struct color c = { COLOR_UNSPECIFIED };
2c2dc7c8 225 int val, wordlen = 0;
7c92fe0e 226
2c2dc7c8
RS
227 while (len > 0 && !isspace(word[wordlen])) {
228 wordlen++;
229 len--;
230 }
7c92fe0e 231
2c2dc7c8
RS
232 ptr = word + wordlen;
233 while (len > 0 && isspace(*ptr)) {
7c92fe0e 234 ptr++;
2c2dc7c8
RS
235 len--;
236 }
7c92fe0e 237
695d95df
JK
238 if (!parse_color(&c, word, wordlen)) {
239 if (fg.type == COLOR_UNSPECIFIED) {
240 fg = c;
7c92fe0e
JK
241 continue;
242 }
695d95df
JK
243 if (bg.type == COLOR_UNSPECIFIED) {
244 bg = c;
7c92fe0e
JK
245 continue;
246 }
247 goto bad;
248 }
2c2dc7c8 249 val = parse_attr(word, wordlen);
8b124135
JH
250 if (0 <= val)
251 attr |= (1 << val);
252 else
7c92fe0e 253 goto bad;
7c92fe0e
JK
254 }
255
cbc8feea
JK
256#undef OUT
257#define OUT(x) do { \
258 if (dst == end) \
033abf97 259 BUG("color parsing ran out of space"); \
cbc8feea
JK
260 *dst++ = (x); \
261} while(0)
262
695d95df 263 if (attr || !color_empty(&fg) || !color_empty(&bg)) {
7c92fe0e 264 int sep = 0;
8b124135 265 int i;
7c92fe0e 266
cbc8feea
JK
267 OUT('\033');
268 OUT('[');
8b124135
JH
269
270 for (i = 0; attr; i++) {
271 unsigned bit = (1 << i);
272 if (!(attr & bit))
273 continue;
274 attr &= ~bit;
275 if (sep++)
cbc8feea
JK
276 OUT(';');
277 dst += xsnprintf(dst, end - dst, "%d", i);
7c92fe0e 278 }
695d95df 279 if (!color_empty(&fg)) {
7c92fe0e 280 if (sep++)
cbc8feea 281 OUT(';');
71b59849 282 /* foreground colors are all in the 3x range */
cbc8feea 283 dst = color_output(dst, end - dst, &fg, '3');
7c92fe0e 284 }
695d95df 285 if (!color_empty(&bg)) {
7c92fe0e 286 if (sep++)
cbc8feea 287 OUT(';');
71b59849 288 /* background colors are all in the 4x range */
cbc8feea 289 dst = color_output(dst, end - dst, &bg, '4');
7c92fe0e 290 }
cbc8feea 291 OUT('m');
7c92fe0e 292 }
cbc8feea 293 OUT(0);
f6c5a296 294 return 0;
7c92fe0e 295bad:
f6c5a296 296 return error(_("invalid color value: %.*s"), value_len, value);
cbc8feea 297#undef OUT
7c92fe0e
JK
298}
299
e269eb79 300int git_config_colorbool(const char *var, const char *value)
7c92fe0e 301{
57f2b842
JH
302 if (value) {
303 if (!strcasecmp(value, "never"))
304 return 0;
305 if (!strcasecmp(value, "always"))
2c1acdf6 306 return 1;
57f2b842 307 if (!strcasecmp(value, "auto"))
daa0c3d9 308 return GIT_COLOR_AUTO;
7c92fe0e 309 }
57f2b842 310
73e9da01
ML
311 if (!var)
312 return -1;
313
57f2b842
JH
314 /* Missing or explicit false to turn off colorization */
315 if (!git_config_bool(var, value))
7c92fe0e 316 return 0;
57f2b842
JH
317
318 /* any normal truth value defaults to 'auto' */
daa0c3d9
JK
319 return GIT_COLOR_AUTO;
320}
321
295d949c 322static int check_auto_color(int fd)
daa0c3d9 323{
295d949c
JS
324 static int color_stderr_is_tty = -1;
325 int *is_tty_p = fd == 1 ? &color_stdout_is_tty : &color_stderr_is_tty;
326 if (*is_tty_p < 0)
327 *is_tty_p = isatty(fd);
328 if (*is_tty_p || (fd == 1 && pager_in_use() && pager_use_color)) {
a64f213d 329 if (!is_terminal_dumb())
57f2b842
JH
330 return 1;
331 }
332 return 0;
7c92fe0e
JK
333}
334
295d949c 335int want_color_fd(int fd, int var)
daa0c3d9 336{
6cdf8a79
337 /*
338 * NEEDSWORK: This function is sometimes used from multiple threads, and
339 * we end up using want_auto racily. That "should not matter" since
340 * we always write the same value, but it's still wrong. This function
341 * is listed in .tsan-suppressions for the time being.
342 */
343
295d949c 344 static int want_auto[3] = { -1, -1, -1 };
daa0c3d9 345
65bb21e7
ES
346 if (fd < 1 || fd >= ARRAY_SIZE(want_auto))
347 BUG("file descriptor out of range: %d", fd);
348
c9bfb953
JK
349 if (var < 0)
350 var = git_use_color_default;
351
daa0c3d9 352 if (var == GIT_COLOR_AUTO) {
295d949c
JS
353 if (want_auto[fd] < 0)
354 want_auto[fd] = check_auto_color(fd);
355 return want_auto[fd];
daa0c3d9 356 }
c9bfb953 357 return var;
daa0c3d9
JK
358}
359
3e1dd17a 360int git_color_config(const char *var, const char *value, void *cb)
6b2f2d98
MK
361{
362 if (!strcmp(var, "color.ui")) {
e269eb79 363 git_use_color_default = git_config_colorbool(var, value);
6b2f2d98
MK
364 return 0;
365 }
366
3e1dd17a
JK
367 return 0;
368}
369
33c643bb
JK
370int git_color_default_config(const char *var, const char *value, void *cb)
371{
372 if (git_color_config(var, value, cb) < 0)
373 return -1;
374
375 return git_default_config(var, value, cb);
376}
377
becbdae8
JN
378void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb)
379{
380 if (*color)
381 fprintf(fp, "%s", color);
382 fprintf(fp, "%s", sb->buf);
383 if (*color)
384 fprintf(fp, "%s", GIT_COLOR_RESET);
385}
386
f26a0012 387static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
7c92fe0e
JK
388 va_list args, const char *trail)
389{
390 int r = 0;
391
392 if (*color)
f26a0012
KH
393 r += fprintf(fp, "%s", color);
394 r += vfprintf(fp, fmt, args);
7c92fe0e 395 if (*color)
dc6ebd4c 396 r += fprintf(fp, "%s", GIT_COLOR_RESET);
7c92fe0e 397 if (trail)
f26a0012 398 r += fprintf(fp, "%s", trail);
7c92fe0e
JK
399 return r;
400}
401
f26a0012 402int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
7c92fe0e
JK
403{
404 va_list args;
405 int r;
406 va_start(args, fmt);
f26a0012 407 r = color_vfprintf(fp, color, fmt, args, NULL);
7c92fe0e
JK
408 va_end(args);
409 return r;
410}
411
f26a0012 412int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
7c92fe0e
JK
413{
414 va_list args;
415 int r;
416 va_start(args, fmt);
f26a0012 417 r = color_vfprintf(fp, color, fmt, args, "\n");
7c92fe0e
JK
418 va_end(args);
419 return r;
420}
148135fc
JK
421
422int color_is_nil(const char *c)
423{
424 return !strcmp(c, "NIL");
425}