]>
Commit | Line | Data |
---|---|---|
f3065bdb | 1 | /* Output colorization. |
8d9254fc | 2 | Copyright (C) 2011-2020 Free Software Foundation, Inc. |
f3065bdb JJ |
3 | |
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) | |
7 | any later version. | |
8 | ||
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. | |
13 | ||
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 | |
17 | 02110-1301, USA. */ | |
18 | ||
19 | #include "config.h" | |
20 | #include "system.h" | |
21 | #include "diagnostic-color.h" | |
d2608235 | 22 | #include "diagnostic-url.h" |
f3065bdb | 23 | |
db0d1bae LH |
24 | #ifdef __MINGW32__ |
25 | # include <windows.h> | |
26 | #endif | |
27 | ||
28f4a4a8 | 28 | #include "color-macros.h" |
f3065bdb JJ |
29 | |
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. */ | |
74 | struct color_cap | |
75 | { | |
76 | const char *name; | |
77 | const char *val; | |
78 | unsigned char name_len; | |
79 | bool free_val; | |
80 | }; | |
81 | ||
82 | /* For GCC_COLORS. */ | |
83 | static struct color_cap color_dict[] = | |
84 | { | |
85 | { "error", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_RED), 5, false }, | |
86 | { "warning", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_MAGENTA), | |
87 | 7, false }, | |
88 | { "note", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_CYAN), 4, false }, | |
8a645150 DM |
89 | { "range1", SGR_SEQ (COLOR_FG_GREEN), 6, false }, |
90 | { "range2", SGR_SEQ (COLOR_FG_BLUE), 6, false }, | |
f3065bdb JJ |
91 | { "locus", SGR_SEQ (COLOR_BOLD), 5, false }, |
92 | { "quote", SGR_SEQ (COLOR_BOLD), 5, false }, | |
4bc1899b | 93 | { "path", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_CYAN), 4, false }, |
d41e76cf DM |
94 | { "fixit-insert", SGR_SEQ (COLOR_FG_GREEN), 12, false }, |
95 | { "fixit-delete", SGR_SEQ (COLOR_FG_RED), 12, false }, | |
c65236d6 DM |
96 | { "diff-filename", SGR_SEQ (COLOR_BOLD), 13, false }, |
97 | { "diff-hunk", SGR_SEQ (COLOR_FG_CYAN), 9, false }, | |
98 | { "diff-delete", SGR_SEQ (COLOR_FG_RED), 11, false }, | |
99 | { "diff-insert", SGR_SEQ (COLOR_FG_GREEN), 11, false }, | |
f012c8ef | 100 | { "type-diff", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN), 9, false }, |
f3065bdb JJ |
101 | { NULL, NULL, 0, false } |
102 | }; | |
103 | ||
104 | const char * | |
105 | colorize_start (bool show_color, const char *name, size_t name_len) | |
106 | { | |
107 | struct color_cap const *cap; | |
108 | ||
109 | if (!show_color) | |
110 | return ""; | |
111 | ||
112 | for (cap = color_dict; cap->name; cap++) | |
113 | if (cap->name_len == name_len | |
114 | && memcmp (cap->name, name, name_len) == 0) | |
115 | break; | |
116 | if (cap->name == NULL) | |
117 | return ""; | |
118 | ||
119 | return cap->val; | |
120 | } | |
121 | ||
122 | const char * | |
123 | colorize_stop (bool show_color) | |
124 | { | |
125 | return show_color ? SGR_RESET : ""; | |
126 | } | |
127 | ||
128 | /* Parse GCC_COLORS. The default would look like: | |
d41e76cf | 129 | GCC_COLORS='error=01;31:warning=01;35:note=01;36:\ |
4bc1899b | 130 | range1=32:range2=34:locus=01:quote=01:path=01;36:\ |
f012c8ef DM |
131 | fixit-insert=32:fixit-delete=31:'\ |
132 | diff-filename=01:diff-hunk=32:diff-delete=31:diff-insert=32:\ | |
133 | type-diff=01;32' | |
f3065bdb JJ |
134 | No character escaping is needed or supported. */ |
135 | static bool | |
136 | parse_gcc_colors (void) | |
137 | { | |
138 | const char *p, *q, *name, *val; | |
139 | char *b; | |
140 | size_t name_len = 0, val_len = 0; | |
141 | ||
142 | p = getenv ("GCC_COLORS"); /* Plural! */ | |
143 | if (p == NULL) | |
144 | return true; | |
145 | if (*p == '\0') | |
146 | return false; | |
147 | ||
148 | name = q = p; | |
149 | val = NULL; | |
150 | /* From now on, be well-formed or you're gone. */ | |
151 | for (;;) | |
152 | if (*q == ':' || *q == '\0') | |
153 | { | |
154 | struct color_cap *cap; | |
155 | ||
156 | if (val) | |
157 | val_len = q - val; | |
158 | else | |
159 | name_len = q - name; | |
160 | /* Empty name without val (empty cap) | |
161 | won't match and will be ignored. */ | |
162 | for (cap = color_dict; cap->name; cap++) | |
163 | if (cap->name_len == name_len | |
164 | && memcmp (cap->name, name, name_len) == 0) | |
165 | break; | |
166 | /* If name unknown, go on for forward compatibility. */ | |
167 | if (cap->val && val) | |
168 | { | |
169 | if (cap->free_val) | |
170 | free (CONST_CAST (char *, cap->val)); | |
171 | b = XNEWVEC (char, val_len + sizeof (SGR_SEQ (""))); | |
172 | memcpy (b, SGR_START, strlen (SGR_START)); | |
173 | memcpy (b + strlen (SGR_START), val, val_len); | |
174 | memcpy (b + strlen (SGR_START) + val_len, SGR_END, | |
175 | sizeof (SGR_END)); | |
176 | cap->val = (const char *) b; | |
177 | cap->free_val = true; | |
178 | } | |
179 | if (*q == '\0') | |
180 | return true; | |
181 | name = ++q; | |
182 | val = NULL; | |
183 | } | |
184 | else if (*q == '=') | |
185 | { | |
186 | if (q == name || val) | |
187 | return true; | |
188 | ||
189 | name_len = q - name; | |
190 | val = ++q; /* Can be the empty string. */ | |
191 | } | |
192 | else if (val == NULL) | |
193 | q++; /* Accumulate name. */ | |
194 | else if (*q == ';' || (*q >= '0' && *q <= '9')) | |
195 | q++; /* Accumulate val. Protect the terminal from being sent | |
196 | garbage. */ | |
197 | else | |
198 | return true; | |
199 | } | |
200 | ||
f3065bdb JJ |
201 | /* Return true if we should use color when in auto mode, false otherwise. */ |
202 | static bool | |
203 | should_colorize (void) | |
204 | { | |
db0d1bae LH |
205 | #ifdef __MINGW32__ |
206 | /* For consistency reasons, one should check the handle returned by | |
207 | _get_osfhandle(_fileno(stderr)) because the function | |
208 | pp_write_text_to_stream() in pretty-print.c calls fputs() on | |
209 | that stream. However, the code below for non-Windows doesn't seem | |
210 | to care about it either... */ | |
211 | HANDLE h; | |
212 | DWORD m; | |
213 | ||
214 | h = GetStdHandle (STD_ERROR_HANDLE); | |
215 | return (h != INVALID_HANDLE_VALUE) && (h != NULL) | |
216 | && GetConsoleMode (h, &m); | |
217 | #else | |
f3065bdb | 218 | char const *t = getenv ("TERM"); |
458c8d64 | 219 | /* emacs M-x shell sets TERM="dumb". */ |
f3065bdb | 220 | return t && strcmp (t, "dumb") != 0 && isatty (STDERR_FILENO); |
db0d1bae | 221 | #endif |
f3065bdb JJ |
222 | } |
223 | ||
f3065bdb JJ |
224 | bool |
225 | colorize_init (diagnostic_color_rule_t rule) | |
226 | { | |
227 | switch (rule) | |
228 | { | |
229 | case DIAGNOSTICS_COLOR_NO: | |
230 | return false; | |
231 | case DIAGNOSTICS_COLOR_YES: | |
232 | return parse_gcc_colors (); | |
233 | case DIAGNOSTICS_COLOR_AUTO: | |
234 | if (should_colorize ()) | |
235 | return parse_gcc_colors (); | |
236 | else | |
237 | return false; | |
238 | default: | |
239 | gcc_unreachable (); | |
240 | } | |
241 | } | |
d2608235 | 242 | |
458c8d64 BE |
243 | /* Return URL_FORMAT_XXX which tells how we should emit urls |
244 | when in always mode. | |
245 | We use GCC_URLS and if that is not defined TERM_URLS. | |
246 | If neither is defined the feature is enabled by default. */ | |
247 | ||
248 | static diagnostic_url_format | |
249 | parse_env_vars_for_urls () | |
250 | { | |
251 | const char *p; | |
252 | ||
253 | p = getenv ("GCC_URLS"); /* Plural! */ | |
254 | if (p == NULL) | |
255 | p = getenv ("TERM_URLS"); | |
256 | ||
257 | if (p == NULL) | |
258 | return URL_FORMAT_DEFAULT; | |
259 | ||
260 | if (*p == '\0') | |
261 | return URL_FORMAT_NONE; | |
262 | ||
263 | if (!strcmp (p, "no")) | |
264 | return URL_FORMAT_NONE; | |
265 | ||
266 | if (!strcmp (p, "st")) | |
267 | return URL_FORMAT_ST; | |
268 | ||
269 | if (!strcmp (p, "bel")) | |
270 | return URL_FORMAT_BEL; | |
271 | ||
272 | return URL_FORMAT_DEFAULT; | |
273 | } | |
274 | ||
275 | /* Return true if we should use urls when in auto mode, false otherwise. */ | |
276 | ||
277 | static bool | |
278 | auto_enable_urls () | |
279 | { | |
280 | #ifdef __MINGW32__ | |
281 | return false; | |
282 | #else | |
283 | const char *term, *colorterm; | |
284 | ||
285 | /* First check the terminal is capable of printing color escapes, | |
286 | if not URLs won't work either. */ | |
287 | if (!should_colorize ()) | |
288 | return false; | |
289 | ||
290 | /* xfce4-terminal is known to not implement URLs at this time. | |
291 | Recently new installations (0.8) will safely ignore the URL escape | |
292 | sequences, but a large number of legacy installations (0.6.3) print | |
293 | garbage when URLs are printed. Therefore we lose nothing by | |
294 | disabling this feature for that specific terminal type. */ | |
295 | colorterm = getenv ("COLORTERM"); | |
296 | if (colorterm && !strcmp (colorterm, "xfce4-terminal")) | |
297 | return false; | |
298 | ||
299 | /* Old versions of gnome-terminal where URL escapes cause screen | |
300 | corruptions set COLORTERM="gnome-terminal", recent versions | |
301 | with working URL support set this to "truecolor". */ | |
302 | if (colorterm && !strcmp (colorterm, "gnome-terminal")) | |
303 | return false; | |
304 | ||
305 | /* Since the following checks are less specific than the ones | |
306 | above, let GCC_URLS and TERM_URLS override the decision. */ | |
307 | if (getenv ("GCC_URLS") || getenv ("TERM_URLS")) | |
308 | return true; | |
309 | ||
310 | /* In an ssh session the COLORTERM is not there, but TERM=xterm | |
311 | can be used as an indication of a incompatible terminal while | |
312 | TERM=xterm-256color appears to be a working terminal. */ | |
313 | term = getenv ("TERM"); | |
314 | if (!colorterm && term && !strcmp (term, "xterm")) | |
315 | return false; | |
316 | ||
317 | /* When logging in a linux over serial line, we see TERM=linux | |
318 | and no COLORTERM, it is unlikely that the URL escapes will | |
319 | work in that environmen either. */ | |
320 | if (!colorterm && term && !strcmp (term, "linux")) | |
321 | return false; | |
322 | ||
323 | return true; | |
324 | #endif | |
325 | } | |
326 | ||
327 | /* Determine if URLs should be enabled, based on RULE, | |
328 | and, if so, which format to use. | |
d2608235 DM |
329 | This reuses the logic for colorization. */ |
330 | ||
458c8d64 BE |
331 | diagnostic_url_format |
332 | determine_url_format (diagnostic_url_rule_t rule) | |
d2608235 DM |
333 | { |
334 | switch (rule) | |
335 | { | |
336 | case DIAGNOSTICS_URL_NO: | |
458c8d64 | 337 | return URL_FORMAT_NONE; |
d2608235 | 338 | case DIAGNOSTICS_URL_YES: |
458c8d64 | 339 | return parse_env_vars_for_urls (); |
d2608235 | 340 | case DIAGNOSTICS_URL_AUTO: |
458c8d64 BE |
341 | if (auto_enable_urls ()) |
342 | return parse_env_vars_for_urls (); | |
343 | else | |
344 | return URL_FORMAT_NONE; | |
d2608235 DM |
345 | default: |
346 | gcc_unreachable (); | |
347 | } | |
348 | } |