From 29811d42e3b47236af7a3ebfa97184ff02f4deb2 Mon Sep 17 00:00:00 2001 From: Charlie Gordon Date: Sat, 8 Mar 2025 23:54:03 +0100 Subject: [PATCH] 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="blue:bright-blue"`, `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 --- ast/utils.c2 | 118 +++++++++++++------- ast_utils/color.c2 | 31 +++++- ast_utils/color_config.c2 | 212 ++++++++++++++++++++++++++++++++++++ common/console.c2 | 39 +++++-- common/diagnostics.c2 | 16 ++- common/source_mgr.c2 | 18 +-- compiler/c2recipe_parser.c2 | 15 +-- compiler/main.c2 | 6 +- parser/c2_parser.c2 | 15 ++- recipe.txt | 7 ++ tools/c2cat.c2 | 18 +++ tools/c2loc.c2 | 2 + tools/tester/test_utils.c2 | 25 +++-- tools/tester/tester.c2 | 3 +- 14 files changed, 424 insertions(+), 101 deletions(-) create mode 100644 ast_utils/color_config.c2 diff --git a/ast/utils.c2 b/ast/utils.c2 index f77627a4..b368da88 100644 --- a/ast/utils.c2 +++ b/ast/utils.c2 @@ -117,6 +117,7 @@ public type Globals struct @(opaque) { #if AstStatistics Stats stats; #endif + Color[15] colors; } // The only globals for AST are here, since they must be set explicitly for plugins!! @@ -127,26 +128,41 @@ public QualType* builtins; public fn Globals* getGlobals() { return globals; } // only used by plugins -public fn void setGlobals(Globals* g) @(unused){ +public fn void setGlobals(Globals* g) @(unused) { globals = g; attr.initialize(g.attr_name_indexes); + col_Normal = g.colors[0]; + col_Error = g.colors[1]; + col_Warning = g.colors[2]; + col_Keyword = g.colors[3]; + col_Identifier = g.colors[4]; + col_Literal = g.colors[5]; + col_Comment = g.colors[6]; + col_Stmt = g.colors[7]; + col_Decl = g.colors[8]; + col_Expr = g.colors[9]; + col_Attr = g.colors[10]; + col_Template = g.colors[11]; + col_Type = g.colors[12]; + col_Value = g.colors[13]; + col_Calc = g.colors[14]; } - // wordsize in bytes, must NOT be called from Plugin! public fn void initialize(Context* c, string_pool.Pool* astPool, u32 wordsize, bool use_color) { - globals = stdlib.malloc(sizeof(Globals)); - globals.pointers.init(c); - globals.string_types.init(c); - globals.wordsize = wordsize; - globals.use_color = use_color; - globals.names_pool = astPool; - globals.ast_count = 1; - globals.ast_capacity = 0; - globals.ast_list = nil; - globals.dump_buf = string_buffer.create(4096, use_color, 2); + Globals* g = stdlib.malloc(sizeof(Globals)); + globals = g; // needed by stats called indirectly by BuiltinType.create + g.pointers.init(c); + g.string_types.init(c); + g.wordsize = wordsize; + g.use_color = use_color; + g.names_pool = astPool; + g.ast_count = 1; + g.ast_capacity = 0; + g.ast_list = nil; + g.dump_buf = string_buffer.create(4096, use_color, 2); #if AstStatistics - globals.stats.reset(); + g.stats.reset(); #endif // create all Qualtypes for builtin-types, 1 extra for void-ptr @@ -160,43 +176,64 @@ public fn void initialize(Context* c, string_pool.Pool* astPool, u32 wordsize, b builtins[elemsof(BuiltinKind)].set(void_ptr); void_ptr.setCanonicalType(builtins[elemsof(BuiltinKind)]); - string.memcpy(globals.builtinType_sizes, BuiltinType_default_sizes, sizeof(BuiltinType_default_sizes)); - globals.builtinType_sizes[BuiltinKind.ISize] = wordsize; - globals.builtinType_sizes[BuiltinKind.USize] = wordsize; + string.memcpy(g.builtinType_sizes, BuiltinType_default_sizes, sizeof(BuiltinType_default_sizes)); + g.builtinType_sizes[BuiltinKind.ISize] = wordsize; + g.builtinType_sizes[BuiltinKind.USize] = wordsize; - string.memcpy(globals.builtinType_width, BuiltinType_default_widths, sizeof(BuiltinType_default_widths)); - globals.builtinType_width[BuiltinKind.ISize] = wordsize * 8; - globals.builtinType_width[BuiltinKind.USize] = wordsize * 8; + string.memcpy(g.builtinType_width, BuiltinType_default_widths, sizeof(BuiltinType_default_widths)); + g.builtinType_width[BuiltinKind.ISize] = wordsize * 8; + g.builtinType_width[BuiltinKind.USize] = wordsize * 8; for (u32 i=0; i 0 && n <= Color.CustomEnd - Color.CustomStart + 1) + return (Color)(Color.CustomStart + n - 1); + } + return Color.None; +} + +fn bool setPaletteColor(Color col, const char *val) { + u32 pal; + if (sscanf(val, "%*1[pP]%u", &pal) == 1) { + snprintf(defaultColors[col], elemsof(defaultColors[col]), "\033[38;5;%dm", pal); + return true; + } + u32 r, g, b; + if (sscanf(val, "#%2x%2x%2x", &r, &g, &b) == 3 + || sscanf(val, "rgb(%u,%u,%u)", &r, &g, &b) == 3) { + snprintf(defaultColors[col], elemsof(defaultColors[col]), "\033[38;2;%d;%d;%dm", r, g, b); + return true; + } + return false; +} + +fn bool setColorString(Color col, const char *val) { + if (!val || *val == '\0') { + *defaultColors[col] = '\0'; + return true; + } + if (!strcmp(val, "default")) { + *defaultColors[col] = '\0'; + if (col < elemsof(standardColors) && standardColors[col]) + strcpy(defaultColors[col], standardColors[col]); + return true; + } + if (Color col1 = findStandardColor(val)) { + strcpy(defaultColors[col], standardColors[col1]); + return true; + } + return setPaletteColor(col, val); +} + +// Normalize a color name into array dest. +// s and dest can point to the same array +fn char* normalizeColor(char *dest, u32 size, const char* s) { + if (!size) return nil; + u32 len = size - 1; + u32 i = 0; + if (s) { + for (const char* p = s; *p && i < len; p++) { + char c = (char)tolower(*p); + if (c != '-' && c != '_') { + if (i < len) dest[i++] = c; + } + } + } + dest[i] = '\0'; + if (*dest == 'b' && !strncmp(dest + 1, "right", 5)) { + memmove(dest + 1, dest + 6, i + 1 - 6); + } + return dest; +} + +fn void customizeStandardColors(const char *p) { + if (!p) return; + + char[16] name; + char[16] val; + while (getConfigEntry(name, elemsof(name), val, elemsof(val), &p)) { + // check for standard color customisation + if (Color col = findStandardColor(normalizeColor(name, elemsof(name), name), true)) { + setColorString(col, normalizeColor(val, elemsof(val), val)); + } + } +} + +fn bool getConfigEntry(char* buf1, u32 size1, char* buf2, u32 size2, const char** pp) { + const char *p = *pp; + for (;;) { + while (isspace(*p)) + p++; + if (*p == '\0' || *p == '[') + return false; + if (*p != '#') + break; + while (*p && *p++ != '\n') + continue; + } + u32 i = 0; + u32 j = 0; + while (*p && *p != '=' && *p != ':' && *p != ';' && !isspace(*p)) { + char c = *p++; + if (i + 1 < size1) + buf1[i++] = c; + if (j + 1 < size2) + buf2[j++] = c; + } + if (size1) buf1[i] = '\0'; + if (size2) buf2[j] = '\0'; + while (*p == ' ') p++; + if (*p == '=' || *p == ':') { + p++; + while (*p == ' ') p++; + j = 0; + while (*p && *p != ';' && *p != '\n') { + char c = *p++; + if (j + 1 < size2) buf2[j++] = c; + } + if (size2) buf2[j] = '\0'; + } + while (*p) { + char c = *p++; + if (c == '\n' || c == ';') + break; + } + *pp = p; + return true; +} + +fn Color convertColor(const char *val, Color def) { + if (!val || *val == '\0') + return None; + + if (Color col = findStandardColor(val)) + return col; + + //if (!strcmp(val, "default")) + // return def; + + for (u32 i = Color.CustomStart; i <= Color.CustomEnd; i++) { + if (!defaultColors[i]) { + Color col = (Color)i; + if (setPaletteColor(col, val)) return col; + // TODO: complain about unknown color + return def; + } + } + // TODO: complain about out of custom colors + return def; +} + +public fn Color getConfigColor(const char* cat, Color def) { + if (!use_color) + return None; + if (c2_colors) { + const char *p = c2_colors; + char[16] cat1; + char[16] style; + char[16] val; + if (!strcmp(p, "none")) + return None; + normalizeColor(cat1, elemsof(cat1), cat); + while (getConfigEntry(style, elemsof(style), val, elemsof(val), &p)) { + if (!strcmp(normalizeColor(style, elemsof(style), style), cat1)) + return convertColor(normalizeColor(val, elemsof(val), val), def); + } + } + return def; +} + +public fn void freeConfigColors() { + for (u32 i = Color.CustomStart; i <= Color.CustomEnd; i++) { + *defaultColors[i] = '\0'; + } +} diff --git a/common/console.c2 b/common/console.c2 index 71fe13e8..fd8eda6b 100644 --- a/common/console.c2 +++ b/common/console.c2 @@ -26,8 +26,19 @@ bool show_timing = false; const u32 BUF_SIZE = 4096; +Color col_normal = color.Normal; +Color col_error = color.Red; +Color col_warning = color.Yellow; +Color col_debug = color.Blue; +Color col_timing = color.Blue; + public fn void init() { use_color = color.useColor(); + col_normal = color.getConfigColor("normal", color.Normal); + col_error = color.getConfigColor("error", color.Red); + col_warning = color.getConfigColor("warning", color.Yellow); + col_debug = color.getConfigColor("debug", color.Blue); + col_timing = color.getConfigColor("timing", color.Blue); } public fn void setDebug(bool enable) { @@ -47,7 +58,7 @@ public fn void debug(const char* format @(printf_format), ...) { vsnprintf(buf, sizeof(buf), format, args); va_end(args); if (use_color) { - printf("%s%s%s\n", color.Blue.str(), buf, color.Normal.str()); + printf("%s%s%s\n", col_debug.str(), buf, col_normal.str()); } else { printf("%s\n", buf); } @@ -69,7 +80,7 @@ public fn void warn(const char* format @(printf_format), ...) { vsnprintf(buf, sizeof(buf), format, args); va_end(args); if (use_color) { - fprintf(stderr, "%swarning: %s%s\n", color.Yellow.str(), buf, color.Normal.str()); + fprintf(stderr, "%swarning: %s%s\n", col_warning.str(), buf, col_normal.str()); } else { fprintf(stderr, "warning: %s\n", buf); } @@ -79,32 +90,40 @@ public fn void error(const char* format @(printf_format), ...) { char[BUF_SIZE] buf; va_list args; va_start(args, format); - vsprintf(buf, format, args); + vsnprintf(buf, sizeof(buf), format, args); va_end(args); if (use_color) { - fprintf(stderr, "%serror: %s%s\n", color.Red.str(), buf, color.Normal.str()); + fprintf(stderr, "%serror: %s%s\n", col_error.str(), buf, col_normal.str()); } else { fprintf(stderr, "error: %s\n", buf); } } -public fn void error_diag(const char* loc, const char* format @(printf_format), ...) { +public fn void diag(bool err, const char* loc, const char* format @(printf_format), ...) { char[BUF_SIZE] buf; va_list args; va_start(args, format); - vsprintf(buf, format, args); + vsnprintf(buf, sizeof(buf), format, args); va_end(args); - if (use_color) { - fprintf(stderr, "%s%s: error: %s%s\n", color.Red.str(), loc, buf, color.Normal.str()); + if (err) { + if (use_color) { + fprintf(stderr, "%s%s: error: %s%s\n", col_error.str(), loc, buf, col_normal.str()); + } else { + fprintf(stderr, "%s: error: %s\n", loc, buf); + } } else { - fprintf(stderr, "%s: error: %s\n", loc, buf); + if (use_color) { + fprintf(stderr, "%s%s: warning: %s%s\n", col_warning.str(), loc, buf, col_normal.str()); + } else { + fprintf(stderr, "%s: warning: %s\n", loc, buf); + } } } public fn void log_time(const char* item, u64 duration) { if (!show_timing) return; if (use_color) { - printf("%s%s took %d usec%s\n", color.Blue.str(), item, duration, color.Normal.str()); + printf("%s%s took %d usec%s\n", col_timing.str(), item, duration, col_normal.str()); } else { printf("%s took %d usec\n", item, duration); } diff --git a/common/diagnostics.c2 b/common/diagnostics.c2 index cd5de2a6..6ef60138 100644 --- a/common/diagnostics.c2 +++ b/common/diagnostics.c2 @@ -40,6 +40,13 @@ public fn Diags* create(source_mgr.SourceMgr* sm, bool use_color, const utils.Pa diags.sm = sm; diags.out = string_buffer.create(512, use_color, 1); diags.path_info = path_info; + if (use_color) { + for (u32 i = 0; i < elemsof(category_colors); i++) { + category_colors[i] = color.getConfigColor(category_names[i], category_colors[i]); + } + col_Normal = getConfigColor("normal", color.Normal); + col_Range = getConfigColor("range", color.Bgreen); + } return diags; } @@ -75,6 +82,9 @@ Color[] category_colors = { Color.Bred, } +Color col_Normal = Color.Normal; +Color col_Range = Color.Bgreen; + public fn void Diags.error(Diags* diags, SrcLoc loc, const char* format @(printf_format), ...) { va_list args; va_start(args, format); @@ -167,7 +177,7 @@ fn void Diags.internal(Diags* diags, out.color(category_colors[category]); out.add(category_names[category]); out.add(": "); - out.color(color.Normal); + out.color(col_Normal); out.vprintf(format, args); out.newline(); @@ -234,12 +244,12 @@ fn void Diags.internal(Diags* diags, char c = ' '; if (text[col - 1] == '\t') // if a TAB was output in the soure c = '\t'; // output a TAB at the same position - if (col == range_start_col) out.color(color.Bgreen); + if (col == range_start_col) out.color(col_Range); if (col >= range_start_col && col < range_end_col) c = '~'; if (col == loc_col) c = '^'; out.add1(c); } - out.color(color.Normal); + out.color(col_Normal); out.newline(); } fputs(out.data(), stderr); diff --git a/common/source_mgr.c2 b/common/source_mgr.c2 index 0d858b51..f860e923 100644 --- a/common/source_mgr.c2 +++ b/common/source_mgr.c2 @@ -15,7 +15,7 @@ module source_mgr; -import color; +import console; import file_utils; import string_pool; import src_loc local; @@ -175,20 +175,12 @@ public fn i32 SourceMgr.addResource(SourceMgr* sm, const char* name, const void* public fn i32 SourceMgr.loadFile(SourceMgr* sm, const char* filename, SrcLoc sloc) { file_utils.File file.init("", filename); if (!file.load()) { - char[256] tmp; - *tmp = '\0'; if (sloc) { - Location loc = sm.locate(sloc); - if (loc.line_start) { - stdio.snprintf(tmp, elemsof(tmp), "%s:%d:%d: ", loc.filename, loc.line, loc.column); - } - } - // Cannot use console since we need source loc first - if (color.useColor()) { - stdio.fprintf(stdio.stderr, "%s%serror:%s cannot open %s: %s\n", - tmp, color.Red.str(), color.Normal.str(), filename, file.getError()); + char[256] locstr; + sm.loc2str(sloc, locstr, elemsof(locstr)); + console.diag(true, locstr, "cannot open %s: %s", filename, file.getError()); } else { - stdio.fprintf(stdio.stderr, "%serror: cannot open %s: %s\n", tmp, filename, file.getError()); + console.error("cannot open %s: %s", filename, file.getError()); } return -1; } diff --git a/compiler/c2recipe_parser.c2 b/compiler/c2recipe_parser.c2 index 54e51dac..47e6b43e 100644 --- a/compiler/c2recipe_parser.c2 +++ b/compiler/c2recipe_parser.c2 @@ -16,7 +16,7 @@ module c2recipe; import build_target; -import color; +import console; import ctype; import file_list local; import source_mgr; @@ -182,12 +182,8 @@ fn void Parser.error(Parser* p, const char* format @(printf_format), ...) @(nore char[256] locstr; p.sm.loc2str(p.token.loc, locstr, elemsof(locstr)); + console.diag(true, locstr, "%s", msg); - if (color.useColor()) { - fprintf(stderr, "%s: %serror:%s %s\n", locstr, color.Red.str(), color.Normal.str(), msg); - } else { - fprintf(stderr, "%s: error: %s\n", locstr, msg); - } longjmp(&p.jmpbuf, 1); } @@ -200,12 +196,7 @@ fn void Parser.warning(Parser* p, const char* format @(printf_format), ...) { char[256] locstr; p.sm.loc2str(p.token.loc, locstr, elemsof(locstr)); - - if (color.useColor()) { - fprintf(stderr, "%s: %swarning:%s %s\n", locstr, color.Red.str(), color.Normal.str(), msg); - } else { - fprintf(stderr, "%s: warning: %s\n", locstr, msg); - } + console.diag(false, locstr, "%s", msg); } fn void Parser.consumeToken(Parser* p) { diff --git a/compiler/main.c2 b/compiler/main.c2 index 2492d926..9b627faf 100644 --- a/compiler/main.c2 +++ b/compiler/main.c2 @@ -516,7 +516,7 @@ fn void Context.handle_args(Context* c, i32 argc, char** argv) { source_mgr.Location loc = c.sm.locate(p.loc); char[256] loc_str; stdio.sprintf(loc_str, "%s:%d:%d", loc.filename, loc.line, loc.column); - console.error_diag(loc_str, "%s", c.plugins.getError()); + console.diag(true, loc_str, "%s", c.plugins.getError()); exit(EXIT_FAILURE); } } @@ -552,7 +552,7 @@ fn void Context.handle_plugins(Context* c) { source_mgr.Location loc = c.sm.locate(p.loc); char[256] loc_str; stdio.sprintf(loc_str, "%s:%d:%d", loc.filename, loc.line, loc.column); - console.error_diag(loc_str, "%s", c.plugins.getError()); + console.diag(true, loc_str, "%s", c.plugins.getError()); exit(EXIT_FAILURE); } } @@ -598,7 +598,7 @@ fn bool Context.build_target(Context* c, source_mgr.Location loc = c.sm.locate(p.loc); char[256] loc_str; stdio.sprintf(loc_str, "%s:%d:%d", loc.filename, loc.line, loc.column); - console.error_diag(loc_str, "%s", c.plugins.getError()); + console.diag(true, loc_str, "%s", c.plugins.getError()); continue; } } diff --git a/parser/c2_parser.c2 b/parser/c2_parser.c2 index 19039110..03adb4f6 100644 --- a/parser/c2_parser.c2 +++ b/parser/c2_parser.c2 @@ -19,7 +19,6 @@ import ast_builder local; import ast local; import attr; import c2_tokenizer; -import color; import constants; import diagnostics; import keywords; @@ -819,15 +818,15 @@ fn void Parser.dump_token(Parser* p, const Token* tok) @(unused) { out.clear(); if (tok.kind.isKeyword()) - out.color(color.Green); + out.color(col_Keyword); out.print("%12s", tok.kind.str()); if (tok.kind.isKeyword()) - out.color(color.Normal); + out.color(col_Normal); char[256] locstr; p.sm.loc2str(tok.loc, locstr, elemsof(locstr)); out.print(" %6d %s ", tok.loc, locstr); - out.color(color.Cyan); + out.color(col_Literal); switch (tok.kind) { case Identifier: out.add(p.pool.idx2str(tok.name_idx)); @@ -880,7 +879,7 @@ fn void Parser.dump_token(Parser* p, const Token* tok) @(unused) { out.add1('"'); out.encodeBytes(p.pool.idx2str(tok.text_idx), tok.text_len, '"'); out.add1('"'); - out.color(color.Normal); + out.color(col_Normal); out.print(" (len %d)", tok.text_len); break; case LineComment: @@ -893,18 +892,18 @@ fn void Parser.dump_token(Parser* p, const Token* tok) @(unused) { out.add("*/"); break; case Warning: - out.color(color.Yellow); + out.color(col_Warning); out.add(tok.error_msg); break; case Error: - out.color(color.Red); + out.color(col_Error); out.add(p.tokenizer.error_msg); break; default: break; } // TODO use callback - out.color(color.Normal); + out.color(col_Normal); out.newline(); fputs(out.data(), stdout); } diff --git a/recipe.txt b/recipe.txt index dc01afcf..ea7b527b 100644 --- a/recipe.txt +++ b/recipe.txt @@ -31,6 +31,7 @@ set ast ast_utils/attr.c2 ast_utils/attr_table.c2 ast_utils/color.c2 + ast_utils/color_config.c2 ast_utils/constants.c2 ast_utils/context.c2 ast_utils/number_radix.c2 @@ -372,9 +373,11 @@ executable tester # $config TesterDebug ast_utils/color.c2 + ast_utils/color_config.c2 ast_utils/constants.c2 ast_utils/string_buffer.c2 + common/console.c2 common/file/file_utils.c2 common/file/reader.c2 common/file/writer.c2 @@ -393,12 +396,14 @@ executable c2cat $backend c ast_utils/color.c2 + ast_utils/color_config.c2 ast_utils/constants.c2 ast_utils/number_radix.c2 ast_utils/src_loc.c2 ast_utils/string_buffer.c2 ast_utils/string_pool.c2 + common/console.c2 common/file/file_utils.c2 common/file/reader.c2 common/string_list.c2 @@ -423,6 +428,7 @@ executable c2loc $backend c ast_utils/color.c2 + ast_utils/color_config.c2 ast_utils/constants.c2 ast_utils/src_loc.c2 ast_utils/string_buffer.c2 @@ -430,6 +436,7 @@ executable c2loc common/build_target.c2 common/file_list.c2 + common/console.c2 common/file/file_utils.c2 common/file/reader.c2 common/library_list.c2 diff --git a/tools/c2cat.c2 b/tools/c2cat.c2 index dc7eb1f2..83a22f94 100644 --- a/tools/c2cat.c2 +++ b/tools/c2cat.c2 @@ -80,6 +80,23 @@ const char*[] attr_names = { "auto_func", } +fn void init_colors() { + color.useColor(); + col_keyword = color.getConfigColor("keyword", color.Byellow); + col_type = color.getConfigColor("type", color.Green); + col_feature = color.getConfigColor("feature", color.Blue); + col_attr = color.getConfigColor("attr", color.Blue); + col_identifier = color.getConfigColor("identifier", Color.None); + col_integer = color.getConfigColor("integer", color.Magenta); + col_float = color.getConfigColor("float", color.Magenta); + col_charconst = color.getConfigColor("charconst", color.Magenta); + col_string = color.getConfigColor("string", color.Magenta); + col_comment = color.getConfigColor("comment", color.Bcyan); + col_invalid = color.getConfigColor("invalid", color.Bred); + col_error = color.getConfigColor("error", color.Bred); + col_normal = color.getConfigColor("normal", color.Normal); +} + fn bool is_attribute(const char* str) { for (u32 i=0; i 2) printf("==> %s <==\n", argv[i]); diff --git a/tools/c2loc.c2 b/tools/c2loc.c2 index 558bd471..32561db0 100644 --- a/tools/c2loc.c2 +++ b/tools/c2loc.c2 @@ -17,6 +17,7 @@ module c2loc_main; import build_target; import c2recipe; +import console; import constants; import file_list; import source_mgr; @@ -106,6 +107,7 @@ fn void handle_target(build_target.Target* t, const char* name) { public fn i32 main(i32 argc, const char** argv) { + console.init(); parse_opts(argc, argv); if (other_dir) { diff --git a/tools/tester/test_utils.c2 b/tools/tester/test_utils.c2 index c47e76c0..12a26c8f 100644 --- a/tools/tester/test_utils.c2 +++ b/tools/tester/test_utils.c2 @@ -26,10 +26,11 @@ import string_buffer; public bool color_output; const char* proc_name = ""; -public Color colError = Bred; -public Color colSkip = Bcyan; -public Color colOk = Green; -public Color colDebug = Bmagenta; +public Color colError = Bred; +public Color colSkip = Bcyan; +public Color colOk = Green; +public Color colDebug = Bmagenta; +public Color colNormal = Normal; // NOTE: end must point AFTER last valid char (could be 0-terminator) @@ -45,9 +46,15 @@ public fn void skipTrailingWhitespace(const char* start, const char** end) { *end = cp; } -public fn void set_color_output(const char *name, bool enable) { +public fn void set_color_output(const char *name) { proc_name = name; - color_output = enable; + color_output = color.useColor(); + // customize colors + colError = color.getConfigColor("test.error", color.Bred); + colSkip = color.getConfigColor("test.skip", color.Bcyan); + colOk = color.getConfigColor("test.ok", color.Green); + colDebug = color.getConfigColor("test.debug", color.Bmagenta); + colNormal = color.getConfigColor("test.normal", color.Normal); } public fn void color_print(Color col, const char* format @(printf_format), ...) { @@ -57,7 +64,7 @@ public fn void color_print(Color col, const char* format @(printf_format), ...) vsnprintf(buffer, sizeof(buffer), format, args); va_end(args); - if (color_output) printf("%s%s%s\n", col.str(), buffer, color.Normal.str()); + if (color_output) printf("%s%s%s\n", col.str(), buffer, colNormal.str()); else printf("%s\n", buffer); } @@ -68,7 +75,7 @@ public fn void print_error(const char* format @(printf_format), ...) { vsnprintf(buffer, sizeof(buffer), format, args); va_end(args); - if (color_output) fprintf(stderr, "%s: %s%s%s\n", proc_name, color.Byellow.str(), buffer, color.Normal.str()); + if (color_output) fprintf(stderr, "%s: %s%s%s\n", proc_name, colError.str(), buffer, colNormal.str()); else fprintf(stderr, "%s: %s\n", proc_name, buffer); } @@ -85,7 +92,7 @@ public fn void color_print2(string_buffer.Buf* output, output.color(col); output.add(buffer); - output.color(color.Normal); + output.color(colNormal); output.newline(); } diff --git a/tools/tester/tester.c2 b/tools/tester/tester.c2 index 498668a9..63cac8c6 100644 --- a/tools/tester/tester.c2 +++ b/tools/tester/tester.c2 @@ -25,7 +25,6 @@ import c_errno local; import unistd; import pthread; -import color; import test_utils local; import test_db local; import string_buffer; @@ -311,7 +310,7 @@ public fn i32 main(i32 argc, char** argv) { u64 t1 = now(); - set_color_output(argv[0], color.useColor()); + set_color_output(argv[0]); for (i32 i = 1; i < argc; i++) { char *arg = argv[i];