Skip to content

Commit 3e46802

Browse files
committed
Control color output with C2_COLORS environment variable
* use style names instead of hard-coded color names * customize color output via environment variable `C2_COLORS`: eg: `C2_COLORS=none`, `C2_COLORS="error:bright-blue"`, `C2_COLORS="error:#d0d0d0"` * use console to output error messages in source_mgr and c2recipe_parser. * use cache to avoid multiple calls to `unix.isatty()` and `stdlib.getenv()` * share global colors with plugins * simplify error formating in **source_mgr.c2** * add c2cat color customisation
1 parent 808ed05 commit 3e46802

File tree

13 files changed

+271
-111
lines changed

13 files changed

+271
-111
lines changed

ast/utils.c2

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ public type Globals struct @(opaque) {
114114
#if AstStatistics
115115
Stats stats;
116116
#endif
117+
const char*[15] colors;
117118
}
118119

119120
// The only globals for AST are here, since they must be set explicitly for plugins!!
@@ -124,12 +125,26 @@ public QualType* builtins;
124125
public fn Globals* getGlobals() { return globals; }
125126

126127
// only used by plugins
127-
public fn void setGlobals(Globals* g) @(unused){
128+
public fn void setGlobals(Globals* g) @(unused) {
128129
globals = g;
129130
attr.initialize(g.attr_name_indexes);
131+
col_Normal = g.colors[0];
132+
col_Error = g.colors[1];
133+
col_Warning = g.colors[2];
134+
col_Keyword = g.colors[3];
135+
col_Identifier = g.colors[4];
136+
col_Literal = g.colors[5];
137+
col_Comment = g.colors[6];
138+
col_Stmt = g.colors[7];
139+
col_Decl = g.colors[8];
140+
col_Expr = g.colors[9];
141+
col_Attr = g.colors[10];
142+
col_Template = g.colors[11];
143+
col_Type = g.colors[12];
144+
col_Value = g.colors[13];
145+
col_Calc = g.colors[14];
130146
}
131147

132-
133148
// wordsize in bytes, must NOT be called from Plugin!
134149
public fn void initialize(Context* c, string_pool.Pool* astPool, u32 wordsize, bool use_color) {
135150
globals = stdlib.malloc(sizeof(Globals));
@@ -181,6 +196,22 @@ public fn void initialize(Context* c, string_pool.Pool* astPool, u32 wordsize, b
181196

182197
attr.register(astPool, globals.attr_name_indexes);
183198
attr.initialize(globals.attr_name_indexes);
199+
200+
globals.colors[0] = col_Normal = color.getConfigColor("normal", color.Normal);
201+
globals.colors[1] = col_Error = color.getConfigColor("error", color.Red);
202+
globals.colors[2] = col_Warning = color.getConfigColor("warning", color.Yellow);
203+
globals.colors[3] = col_Keyword = color.getConfigColor("keyword", color.Green);
204+
globals.colors[4] = col_Identifier = color.getConfigColor("identifier", color.Cyan);
205+
globals.colors[5] = col_Literal = color.getConfigColor("literal", color.Cyan);
206+
globals.colors[6] = col_Comment = color.getConfigColor("comment", color.Cyan);
207+
globals.colors[7] = col_Stmt = color.getConfigColor("ast.stmt", color.Bmagenta);
208+
globals.colors[8] = col_Decl = color.getConfigColor("ast.decl", color.Bgreen);
209+
globals.colors[9] = col_Expr = color.getConfigColor("ast.expr", color.Bmagenta);
210+
globals.colors[10] = col_Attr = color.getConfigColor("ast.attr", color.Blue);
211+
globals.colors[11] = col_Template = color.getConfigColor("ast.template", color.Green);
212+
globals.colors[12] = col_Type = color.getConfigColor("ast.type", color.Green);
213+
globals.colors[13] = col_Value = color.getConfigColor("ast.value", color.Bcyan);
214+
globals.colors[14] = col_Calc = color.getConfigColor("ast.calc", color.Yellow); // all calculated values
184215
}
185216

186217
public fn void deinit(bool print_stats) {
@@ -196,6 +227,7 @@ public fn void deinit(bool print_stats) {
196227
globals.string_types.clear();
197228
stdlib.free(globals);
198229
stdlib.free(builtins);
230+
// TODO: free allocated config colors
199231
}
200232

201233
public fn u32 getWordSize() {
@@ -297,17 +329,22 @@ public fn QualType getNativeType() {
297329
return builtins[kind];
298330
}
299331

332+
public const char* col_Normal = color.Normal;
333+
public const char* col_Error = color.Red;
334+
public const char* col_Warning = color.Yellow;
335+
public const char* col_Keyword = color.Green;
336+
public const char* col_Identifier = color.Cyan;
337+
public const char* col_Literal = color.Cyan;
338+
public const char* col_Comment = color.Cyan;
339+
300340
const char* col_Stmt = color.Bmagenta;
301341
const char* col_Decl = color.Bgreen;
302342
const char* col_Expr = color.Bmagenta;
303343
const char* col_Attr = color.Blue;
304344
const char* col_Template = color.Green;
305-
//const char* col_Cast = color.Red;
306345
const char* col_Type = color.Green;
307346
const char* col_Value = color.Bcyan;
308-
const char* col_Error = color.Red;
309347
const char* col_Calc = color.Yellow; // all calculated value
310-
const char* col_Normal = color.Normal;
311348

312349
public type AttrHandlerFn fn bool (void* arg, Decl* d, const attr.Attr* a);
313350

ast_utils/color.c2

Lines changed: 142 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,149 @@
1414
*/
1515

1616
module color;
17-
import unistd;
18-
19-
public const char[] Black = "\033[0;30m";
20-
public const char[] Red = "\033[0;31m";
21-
public const char[] Green = "\033[0;32m";
22-
public const char[] Yellow = "\033[0;33m";
23-
public const char[] Blue = "\033[0;34m";
24-
public const char[] Magenta = "\033[0;35m";
25-
public const char[] Cyan = "\033[0;36m";
26-
public const char[] Grey = "\033[0;37m";
27-
public const char[] Darkgrey = "\033[01;30m";
28-
public const char[] Bred = "\033[01;31m";
29-
public const char[] Bgreen = "\033[01;32m";
30-
public const char[] Byellow = "\033[01;33m";
31-
public const char[] Bblue = "\033[01;34m";
32-
public const char[] Bmagenta = "\033[01;35m";
33-
public const char[] Bcyan = "\033[01;36m";
34-
public const char[] White = "\033[01;37m";
35-
public const char[] Normal = "\033[0m";
17+
18+
import ctype local;
19+
import stdio local;
20+
import stdlib local;
21+
import string local;
22+
import unistd local;
23+
24+
public const char[] Black @(unused) = "\033[0;30m";
25+
public const char[] Red @(unused) = "\033[0;31m";
26+
public const char[] Green @(unused) = "\033[0;32m";
27+
public const char[] Yellow @(unused) = "\033[0;33m";
28+
public const char[] Blue @(unused) = "\033[0;34m";
29+
public const char[] Magenta @(unused) = "\033[0;35m";
30+
public const char[] Cyan @(unused) = "\033[0;36m";
31+
public const char[] Grey @(unused) = "\033[0;37m";
32+
public const char[] Darkgrey @(unused) = "\033[01;30m";
33+
public const char[] Bred @(unused) = "\033[01;31m";
34+
public const char[] Bgreen @(unused) = "\033[01;32m";
35+
public const char[] Byellow @(unused) = "\033[01;33m";
36+
public const char[] Bblue @(unused) = "\033[01;34m";
37+
public const char[] Bmagenta @(unused) = "\033[01;35m";
38+
public const char[] Bcyan @(unused) = "\033[01;36m";
39+
public const char[] White @(unused) = "\033[01;37m";
40+
public const char[] Normal @(unused) = "\033[0m";
41+
42+
i8 use_color = -1;
43+
char *c2_colors;
3644

3745
public fn bool useColor() {
38-
return unistd.isatty(1);
46+
if (use_color < 0) {
47+
use_color = isatty(1) != 0;
48+
if (use_color) {
49+
char *p = getenv("C2_COLORS");
50+
if (p) {
51+
if (!strcmp(p, "none"))
52+
use_color = 0;
53+
else
54+
c2_colors = p;
55+
}
56+
}
57+
}
58+
return use_color;
59+
}
60+
61+
const char*[] standardColors = {
62+
"black", Black,
63+
"red", Red,
64+
"green", Green,
65+
"yellow", Yellow,
66+
"blue", Blue,
67+
"magenta", Magenta,
68+
"cyan", Cyan,
69+
"grey", Grey,
70+
"darkgrey", Darkgrey,
71+
"bred", Bred,
72+
"bgreen", Bgreen,
73+
"byellow", Byellow,
74+
"bblue", Bblue,
75+
"bmagenta", Bmagenta,
76+
"bcyan", Bcyan,
77+
"white", White,
78+
"normal", Normal,
79+
}
80+
81+
fn bool getStyleDef(char* buf1, u32 size1, char* buf2, u32 size2, const char** pp) {
82+
const char *p = *pp;
83+
while (isspace(*p))
84+
p++;
85+
if (!*p)
86+
return false;
87+
u32 i = 0;
88+
while (isalpha(*p) || *p == '.' || *p == '_') {
89+
char c = cast<char>(tolower(*p++));
90+
if (i + 1 < size1)
91+
buf1[i++] = c;
92+
}
93+
buf1[i] = '\0';
94+
if (*p != '=' && *p != ':')
95+
return false;
96+
p++;
97+
i = 0;
98+
while (*p && *p != ' ' && *p != ',' && *p != ';') {
99+
char c = cast<char>(tolower(*p++));
100+
if (i + 1 < size2 && c != '-' && c != '_')
101+
buf2[i++] = c;
102+
}
103+
buf2[i] = '\0';
104+
if (*p == ',' || *p == ';')
105+
p++;
106+
*pp = p;
107+
return true;
39108
}
40109

110+
fn bool matchColorName(const char *p, const char *name) {
111+
while (*p) {
112+
char c = *p++;
113+
if (c == 'b' && !strncmp(p, "right", 5))
114+
p += 5;
115+
if (c != *name++)
116+
return false;
117+
}
118+
return *name == '\0';
119+
}
120+
121+
fn const char* convertColor(const char *val, const char *def) {
122+
if (*val == '\0')
123+
return "";
124+
125+
for (u32 i = 0; i < elemsof(standardColors); i += 2) {
126+
if (matchColorName(val, standardColors[i]))
127+
return standardColors[i + 1];
128+
}
129+
if (!strcasecmp(val, "default"))
130+
return def;
131+
132+
char[32] buf;
133+
i32 pal;
134+
i32 r;
135+
i32 g;
136+
i32 b;
137+
if (sscanf(val, "%*1[pP]%d", &pal) == 1) {
138+
snprintf(buf, elemsof(buf), "\033[38;5;%dm", pal);
139+
} else
140+
if (sscanf(val, "#%2x%2x%2x", &r, &g, &b) == 3) {
141+
snprintf(buf, elemsof(buf), "\033[38;2;%d;%d;%dm", r, g, b);
142+
} else {
143+
// TODO: complain about unknown color
144+
return def;
145+
}
146+
return strdup(buf);
147+
}
148+
149+
public fn const char* getConfigColor(const char* cat, const char* def) {
150+
if (!use_color)
151+
return "";
152+
if (c2_colors) {
153+
const char *p = c2_colors;
154+
char[16] style;
155+
char[16] val;
156+
while (getStyleDef(style, elemsof(style), val, elemsof(val), &p)) {
157+
if (!strcmp(style, cat))
158+
return convertColor(val, def);
159+
}
160+
}
161+
return def;
162+
}

common/console.c2

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,19 @@ bool show_timing = false;
2626

2727
const u32 BUF_SIZE = 4096;
2828

29+
const char* col_normal = color.Normal;
30+
const char* col_error = color.Red;
31+
const char* col_warning = color.Yellow;
32+
const char* col_debug = color.Blue;
33+
const char* col_timing = color.Blue;
34+
2935
public fn void init() {
3036
use_color = color.useColor();
37+
col_normal = color.getConfigColor("normal", color.Normal);
38+
col_error = color.getConfigColor("error", color.Red);
39+
col_warning = color.getConfigColor("warning", color.Yellow);
40+
col_debug = color.getConfigColor("debug", color.Blue);
41+
col_timing = color.getConfigColor("timing", color.Blue);
3142
}
3243

3344
public fn void setDebug(bool enable) {
@@ -46,11 +57,7 @@ public fn void debug(const char* format @(printf_format), ...) {
4657
va_start(args, format);
4758
vsnprintf(buf, sizeof(buf), format, args);
4859
va_end(args);
49-
if (use_color) {
50-
printf("%s%s%s\n", color.Blue, buf, color.Normal);
51-
} else {
52-
printf("%s\n", buf);
53-
}
60+
printf("%s%s%s\n", col_debug, buf, col_normal);
5461
}
5562

5663
public fn void log(const char* format @(printf_format), ...) {
@@ -68,45 +75,29 @@ public fn void warn(const char* format @(printf_format), ...) {
6875
va_start(args, format);
6976
vsnprintf(buf, sizeof(buf), format, args);
7077
va_end(args);
71-
if (use_color) {
72-
fprintf(stderr, "%swarning: %s%s\n", color.Yellow, buf, color.Normal);
73-
} else {
74-
fprintf(stderr, "warning: %s\n", buf);
75-
}
78+
fprintf(stderr, "%swarning: %s%s\n", col_warning, buf, col_normal);
7679
}
7780

7881
public fn void error(const char* format @(printf_format), ...) {
7982
char[BUF_SIZE] buf;
8083
va_list args;
8184
va_start(args, format);
82-
vsprintf(buf, format, args);
85+
vsnprintf(buf, sizeof(buf), format, args);
8386
va_end(args);
84-
if (use_color) {
85-
fprintf(stderr, "%serror: %s%s\n", color.Red, buf, color.Normal);
86-
} else {
87-
fprintf(stderr, "error: %s\n", buf);
88-
}
87+
fprintf(stderr, "%serror: %s%s\n", col_error, buf, col_normal);
8988
}
9089

9190
public fn void error_diag(const char* loc, const char* format @(printf_format), ...) {
9291
char[BUF_SIZE] buf;
9392
va_list args;
9493
va_start(args, format);
95-
vsprintf(buf, format, args);
94+
vsnprintf(buf, sizeof(buf), format, args);
9695
va_end(args);
97-
if (use_color) {
98-
fprintf(stderr, "%s%s: error: %s%s\n", color.Red, loc, buf, color.Normal);
99-
} else {
100-
fprintf(stderr, "%s: error: %s\n", loc, buf);
101-
}
96+
fprintf(stderr, "%s%s: error: %s%s\n", col_error, loc, buf, col_normal);
10297
}
10398

10499
public fn void log_time(const char* item, u64 duration) {
105100
if (!show_timing) return;
106-
if (use_color) {
107-
printf("%s%s took %d usec%s\n", color.Blue, item, duration, color.Normal);
108-
} else {
109-
printf("%s took %d usec\n", item, duration);
110-
}
101+
printf("%s%s took %d usec%s\n", col_timing, item, duration, col_normal);
111102
}
112103

common/diagnostics.c2

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ public fn Diags* create(source_mgr.SourceMgr* sm, bool use_color, const utils.Pa
4040
diags.sm = sm;
4141
diags.out = string_buffer.create(512, use_color, 1);
4242
diags.path_info = path_info;
43+
if (use_color) {
44+
for (u32 i = 0; i < elemsof(category_colors); i++) {
45+
category_colors[i] = color.getConfigColor(category_names[i], category_colors[i]);
46+
}
47+
col_Normal = color.getConfigColor("normal", color.Normal);
48+
col_Range = color.getConfigColor("range", color.Bgreen);
49+
}
4350
return diags;
4451
}
4552

@@ -75,6 +82,9 @@ const char*[] category_colors = {
7582
color.Bred,
7683
}
7784

85+
const char* col_Normal = color.Normal;
86+
const char* col_Range = color.Bgreen;
87+
7888
public fn void Diags.error(Diags* diags, SrcLoc loc, const char* format @(printf_format), ...) {
7989
va_list args;
8090
va_start(args, format);
@@ -167,7 +177,7 @@ fn void Diags.internal(Diags* diags,
167177
out.color(category_colors[category]);
168178
out.add(category_names[category]);
169179
out.add(": ");
170-
out.color(color.Normal);
180+
out.color(col_Normal);
171181

172182
out.vprintf(format, args);
173183
out.newline();
@@ -234,12 +244,12 @@ fn void Diags.internal(Diags* diags,
234244
char c = ' ';
235245
if (text[col - 1] == '\t') // if a TAB was output in the soure
236246
c = '\t'; // output a TAB at the same position
237-
if (col == range_start_col) out.color(color.Bgreen);
247+
if (col == range_start_col) out.color(col_Range);
238248
if (col >= range_start_col && col < range_end_col) c = '~';
239249
if (col == loc_col) c = '^';
240250
out.add1(c);
241251
}
242-
out.color(color.Normal);
252+
out.color(col_Normal);
243253
out.newline();
244254
}
245255
fputs(out.data(), stderr);

0 commit comments

Comments
 (0)