1 /* Output colorization.
2 Copyright (C) 2011-2022 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21 #include "diagnostic-color.h"
22 #include "diagnostic-url.h"
28 #include "color-macros.h"
30 /* The context and logic for choosing default --color screen attributes
31 (foreground and background colors, etc.) are the following.
32 -- There are eight basic colors available, each with its own
33 nominal luminosity to the human eye and foreground/background
34 codes (black [0 %, 30/40], blue [11 %, 34/44], red [30 %, 31/41],
35 magenta [41 %, 35/45], green [59 %, 32/42], cyan [70 %, 36/46],
36 yellow [89 %, 33/43], and white [100 %, 37/47]).
37 -- Sometimes, white as a background is actually implemented using
38 a shade of light gray, so that a foreground white can be visible
39 on top of it (but most often not).
40 -- Sometimes, black as a foreground is actually implemented using
41 a shade of dark gray, so that it can be visible on top of a
42 background black (but most often not).
43 -- Sometimes, more colors are available, as extensions.
44 -- Other attributes can be selected/deselected (bold [1/22],
45 underline [4/24], standout/inverse [7/27], blink [5/25], and
46 invisible/hidden [8/28]). They are sometimes implemented by
47 using colors instead of what their names imply; e.g., bold is
48 often achieved by using brighter colors. In practice, only bold
49 is really available to us, underline sometimes being mapped by
50 the terminal to some strange color choice, and standout best
51 being left for use by downstream programs such as less(1).
52 -- We cannot assume that any of the extensions or special features
53 are available for the purpose of choosing defaults for everyone.
54 -- The most prevalent default terminal backgrounds are pure black
55 and pure white, and are not necessarily the same shades of
56 those as if they were selected explicitly with SGR sequences.
57 Some terminals use dark or light pictures as default background,
58 but those are covered over by an explicit selection of background
59 color with an SGR sequence; their users will appreciate their
60 background pictures not be covered like this, if possible.
61 -- Some uses of colors attributes is to make some output items
62 more understated (e.g., context lines); this cannot be achieved
63 by changing the background color.
64 -- For these reasons, the GCC color defaults should strive not
65 to change the background color from its default, unless it's
66 for a short item that should be highlighted, not understated.
67 -- The GCC foreground color defaults (without an explicitly set
68 background) should provide enough contrast to be readable on any
69 terminal with either a black (dark) or white (light) background.
70 This only leaves red, magenta, green, and cyan (and their bold
71 counterparts) and possibly bold blue. */
72 /* Default colors. The user can overwrite them using environment
73 variable GCC_COLORS. */
78 unsigned char name_len
;
83 static struct color_cap color_dict
[] =
85 { "error", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_RED
), 5, false },
86 { "warning", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_MAGENTA
),
88 { "note", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_CYAN
), 4, false },
89 { "range1", SGR_SEQ (COLOR_FG_GREEN
), 6, false },
90 { "range2", SGR_SEQ (COLOR_FG_BLUE
), 6, false },
91 { "locus", SGR_SEQ (COLOR_BOLD
), 5, false },
92 { "quote", SGR_SEQ (COLOR_BOLD
), 5, false },
93 { "path", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_CYAN
), 4, false },
94 { "fnname", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN
), 6, false },
95 { "targs", SGR_SEQ (COLOR_FG_MAGENTA
), 5, false },
96 { "fixit-insert", SGR_SEQ (COLOR_FG_GREEN
), 12, false },
97 { "fixit-delete", SGR_SEQ (COLOR_FG_RED
), 12, false },
98 { "diff-filename", SGR_SEQ (COLOR_BOLD
), 13, false },
99 { "diff-hunk", SGR_SEQ (COLOR_FG_CYAN
), 9, false },
100 { "diff-delete", SGR_SEQ (COLOR_FG_RED
), 11, false },
101 { "diff-insert", SGR_SEQ (COLOR_FG_GREEN
), 11, false },
102 { "type-diff", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN
), 9, false },
103 { NULL
, NULL
, 0, false }
107 colorize_start (bool show_color
, const char *name
, size_t name_len
)
109 struct color_cap
const *cap
;
114 for (cap
= color_dict
; cap
->name
; cap
++)
115 if (cap
->name_len
== name_len
116 && memcmp (cap
->name
, name
, name_len
) == 0)
118 if (cap
->name
== NULL
)
125 colorize_stop (bool show_color
)
127 return show_color
? SGR_RESET
: "";
130 /* Parse GCC_COLORS. The default would look like:
131 GCC_COLORS='error=01;31:warning=01;35:note=01;36:\
132 range1=32:range2=34:locus=01:quote=01:path=01;36:\
133 fixit-insert=32:fixit-delete=31:'\
134 diff-filename=01:diff-hunk=32:diff-delete=31:diff-insert=32:\
136 No character escaping is needed or supported. */
138 parse_gcc_colors (void)
140 const char *p
, *q
, *name
, *val
;
142 size_t name_len
= 0, val_len
= 0;
144 p
= getenv ("GCC_COLORS"); /* Plural! */
152 /* From now on, be well-formed or you're gone. */
154 if (*q
== ':' || *q
== '\0')
156 struct color_cap
*cap
;
162 /* Empty name without val (empty cap)
163 won't match and will be ignored. */
164 for (cap
= color_dict
; cap
->name
; cap
++)
165 if (cap
->name_len
== name_len
166 && memcmp (cap
->name
, name
, name_len
) == 0)
168 /* If name unknown, go on for forward compatibility. */
172 free (CONST_CAST (char *, cap
->val
));
173 b
= XNEWVEC (char, val_len
+ sizeof (SGR_SEQ ("")));
174 memcpy (b
, SGR_START
, strlen (SGR_START
));
175 memcpy (b
+ strlen (SGR_START
), val
, val_len
);
176 memcpy (b
+ strlen (SGR_START
) + val_len
, SGR_END
,
178 cap
->val
= (const char *) b
;
179 cap
->free_val
= true;
188 if (q
== name
|| val
)
192 val
= ++q
; /* Can be the empty string. */
194 else if (val
== NULL
)
195 q
++; /* Accumulate name. */
196 else if (*q
== ';' || (*q
>= '0' && *q
<= '9'))
197 q
++; /* Accumulate val. Protect the terminal from being sent
203 /* Return true if we should use color when in auto mode, false otherwise. */
205 should_colorize (void)
208 /* For consistency reasons, one should check the handle returned by
209 _get_osfhandle(_fileno(stderr)) because the function
210 pp_write_text_to_stream() in pretty-print.cc calls fputs() on
211 that stream. However, the code below for non-Windows doesn't seem
212 to care about it either... */
216 h
= GetStdHandle (STD_ERROR_HANDLE
);
217 return (h
!= INVALID_HANDLE_VALUE
) && (h
!= NULL
)
218 && GetConsoleMode (h
, &m
);
220 char const *t
= getenv ("TERM");
221 /* emacs M-x shell sets TERM="dumb". */
222 return t
&& strcmp (t
, "dumb") != 0 && isatty (STDERR_FILENO
);
227 colorize_init (diagnostic_color_rule_t rule
)
231 case DIAGNOSTICS_COLOR_NO
:
233 case DIAGNOSTICS_COLOR_YES
:
234 return parse_gcc_colors ();
235 case DIAGNOSTICS_COLOR_AUTO
:
236 if (should_colorize ())
237 return parse_gcc_colors ();
245 /* Return URL_FORMAT_XXX which tells how we should emit urls
247 We use GCC_URLS and if that is not defined TERM_URLS.
248 If neither is defined the feature is enabled by default. */
250 static diagnostic_url_format
251 parse_env_vars_for_urls ()
255 p
= getenv ("GCC_URLS"); /* Plural! */
257 p
= getenv ("TERM_URLS");
260 return URL_FORMAT_DEFAULT
;
263 return URL_FORMAT_NONE
;
265 if (!strcmp (p
, "no"))
266 return URL_FORMAT_NONE
;
268 if (!strcmp (p
, "st"))
269 return URL_FORMAT_ST
;
271 if (!strcmp (p
, "bel"))
272 return URL_FORMAT_BEL
;
274 return URL_FORMAT_DEFAULT
;
277 /* Return true if we should use urls when in auto mode, false otherwise. */
285 const char *term
, *colorterm
;
287 /* First check the terminal is capable of printing color escapes,
288 if not URLs won't work either. */
289 if (!should_colorize ())
292 /* xfce4-terminal is known to not implement URLs at this time.
293 Recently new installations (0.8) will safely ignore the URL escape
294 sequences, but a large number of legacy installations (0.6.3) print
295 garbage when URLs are printed. Therefore we lose nothing by
296 disabling this feature for that specific terminal type. */
297 colorterm
= getenv ("COLORTERM");
298 if (colorterm
&& !strcmp (colorterm
, "xfce4-terminal"))
301 /* Old versions of gnome-terminal where URL escapes cause screen
302 corruptions set COLORTERM="gnome-terminal", recent versions
303 with working URL support set this to "truecolor". */
304 if (colorterm
&& !strcmp (colorterm
, "gnome-terminal"))
307 /* Since the following checks are less specific than the ones
308 above, let GCC_URLS and TERM_URLS override the decision. */
309 if (getenv ("GCC_URLS") || getenv ("TERM_URLS"))
312 /* In an ssh session the COLORTERM is not there, but TERM=xterm
313 can be used as an indication of a incompatible terminal while
314 TERM=xterm-256color appears to be a working terminal. */
315 term
= getenv ("TERM");
316 if (!colorterm
&& term
&& !strcmp (term
, "xterm"))
319 /* When logging in a linux over serial line, we see TERM=linux
320 and no COLORTERM, it is unlikely that the URL escapes will
321 work in that environmen either. */
322 if (!colorterm
&& term
&& !strcmp (term
, "linux"))
329 /* Determine if URLs should be enabled, based on RULE,
330 and, if so, which format to use.
331 This reuses the logic for colorization. */
333 diagnostic_url_format
334 determine_url_format (diagnostic_url_rule_t rule
)
338 case DIAGNOSTICS_URL_NO
:
339 return URL_FORMAT_NONE
;
340 case DIAGNOSTICS_URL_YES
:
341 return parse_env_vars_for_urls ();
342 case DIAGNOSTICS_URL_AUTO
:
343 if (auto_enable_urls ())
344 return parse_env_vars_for_urls ();
346 return URL_FORMAT_NONE
;