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