diff --git a/ast/utils.c2 b/ast/utils.c2 index aedc05e8..b3e85391 100644 --- a/ast/utils.c2 +++ b/ast/utils.c2 @@ -114,6 +114,7 @@ public type Globals struct @(opaque) { #if AstStatistics Stats stats; #endif + const char*[15] colors; } // The only globals for AST are here, since they must be set explicitly for plugins!! @@ -124,12 +125,26 @@ 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)); @@ -181,6 +196,22 @@ public fn void initialize(Context* c, string_pool.Pool* astPool, u32 wordsize, b attr.register(astPool, globals.attr_name_indexes); attr.initialize(globals.attr_name_indexes); + + globals.colors[0] = col_Normal = color.getConfigColor("normal", color.Normal); + globals.colors[1] = col_Error = color.getConfigColor("error", color.Red); + globals.colors[2] = col_Warning = color.getConfigColor("warning", color.Yellow); + globals.colors[3] = col_Keyword = color.getConfigColor("keyword", color.Green); + globals.colors[4] = col_Identifier = color.getConfigColor("identifier", color.Cyan); + globals.colors[5] = col_Literal = color.getConfigColor("literal", color.Cyan); + globals.colors[6] = col_Comment = color.getConfigColor("comment", color.Cyan); + globals.colors[7] = col_Stmt = color.getConfigColor("ast.stmt", color.Bmagenta); + globals.colors[8] = col_Decl = color.getConfigColor("ast.decl", color.Bgreen); + globals.colors[9] = col_Expr = color.getConfigColor("ast.expr", color.Bmagenta); + globals.colors[10] = col_Attr = color.getConfigColor("ast.attr", color.Blue); + globals.colors[11] = col_Template = color.getConfigColor("ast.template", color.Green); + globals.colors[12] = col_Type = color.getConfigColor("ast.type", color.Green); + globals.colors[13] = col_Value = color.getConfigColor("ast.value", color.Bcyan); + globals.colors[14] = col_Calc = color.getConfigColor("ast.calc", color.Yellow); // all calculated values } public fn void deinit(bool print_stats) { @@ -196,6 +227,7 @@ public fn void deinit(bool print_stats) { globals.string_types.clear(); stdlib.free(globals); stdlib.free(builtins); + // TODO: free allocated config colors } public fn u32 getWordSize() { @@ -297,17 +329,22 @@ public fn QualType getNativeType() { return builtins[kind]; } +public const char* col_Normal = color.Normal; +public const char* col_Error = color.Red; +public const char* col_Warning = color.Yellow; +public const char* col_Keyword = color.Green; +public const char* col_Identifier = color.Cyan; +public const char* col_Literal = color.Cyan; +public const char* col_Comment = color.Cyan; + const char* col_Stmt = color.Bmagenta; const char* col_Decl = color.Bgreen; const char* col_Expr = color.Bmagenta; const char* col_Attr = color.Blue; const char* col_Template = color.Green; -//const char* col_Cast = color.Red; const char* col_Type = color.Green; const char* col_Value = color.Bcyan; -const char* col_Error = color.Red; const char* col_Calc = color.Yellow; // all calculated value -const char* col_Normal = color.Normal; public type AttrHandlerFn fn bool (void* arg, Decl* d, const attr.Attr* a); diff --git a/ast_utils/color.c2 b/ast_utils/color.c2 index 60cc5b6d..63578e66 100644 --- a/ast_utils/color.c2 +++ b/ast_utils/color.c2 @@ -14,27 +14,149 @@ */ module color; -import unistd; - -public const char[] Black = "\033[0;30m"; -public const char[] Red = "\033[0;31m"; -public const char[] Green = "\033[0;32m"; -public const char[] Yellow = "\033[0;33m"; -public const char[] Blue = "\033[0;34m"; -public const char[] Magenta = "\033[0;35m"; -public const char[] Cyan = "\033[0;36m"; -public const char[] Grey = "\033[0;37m"; -public const char[] Darkgrey = "\033[01;30m"; -public const char[] Bred = "\033[01;31m"; -public const char[] Bgreen = "\033[01;32m"; -public const char[] Byellow = "\033[01;33m"; -public const char[] Bblue = "\033[01;34m"; -public const char[] Bmagenta = "\033[01;35m"; -public const char[] Bcyan = "\033[01;36m"; -public const char[] White = "\033[01;37m"; -public const char[] Normal = "\033[0m"; + +import ctype local; +import stdio local; +import stdlib local; +import string local; +import unistd local; + +public const char[] Black @(unused) = "\033[0;30m"; +public const char[] Red @(unused) = "\033[0;31m"; +public const char[] Green @(unused) = "\033[0;32m"; +public const char[] Yellow @(unused) = "\033[0;33m"; +public const char[] Blue @(unused) = "\033[0;34m"; +public const char[] Magenta @(unused) = "\033[0;35m"; +public const char[] Cyan @(unused) = "\033[0;36m"; +public const char[] Grey @(unused) = "\033[0;37m"; +public const char[] Darkgrey @(unused) = "\033[01;30m"; +public const char[] Bred @(unused) = "\033[01;31m"; +public const char[] Bgreen @(unused) = "\033[01;32m"; +public const char[] Byellow @(unused) = "\033[01;33m"; +public const char[] Bblue @(unused) = "\033[01;34m"; +public const char[] Bmagenta @(unused) = "\033[01;35m"; +public const char[] Bcyan @(unused) = "\033[01;36m"; +public const char[] White @(unused) = "\033[01;37m"; +public const char[] Normal @(unused) = "\033[0m"; + +i8 use_color = -1; +char *c2_colors; public fn bool useColor() { - return unistd.isatty(1); + if (use_color < 0) { + use_color = isatty(1) != 0; + if (use_color) { + char *p = getenv("C2_COLORS"); + if (p) { + if (!strcmp(p, "none")) + use_color = 0; + else + c2_colors = p; + } + } + } + return use_color; +} + +const char*[] standardColors = { + "black", Black, + "red", Red, + "green", Green, + "yellow", Yellow, + "blue", Blue, + "magenta", Magenta, + "cyan", Cyan, + "grey", Grey, + "darkgrey", Darkgrey, + "bred", Bred, + "bgreen", Bgreen, + "byellow", Byellow, + "bblue", Bblue, + "bmagenta", Bmagenta, + "bcyan", Bcyan, + "white", White, + "normal", Normal, +} + +fn bool getStyleDef(char* buf1, u32 size1, char* buf2, u32 size2, const char** pp) { + const char *p = *pp; + while (isspace(*p)) + p++; + if (!*p) + return false; + u32 i = 0; + while (isalpha(*p) || *p == '.' || *p == '_') { + char c = cast(tolower(*p++)); + if (i + 1 < size1) + buf1[i++] = c; + } + buf1[i] = '\0'; + if (*p != '=' && *p != ':') + return false; + p++; + i = 0; + while (*p && *p != ' ' && *p != ',' && *p != ';') { + char c = cast(tolower(*p++)); + if (i + 1 < size2 && c != '-' && c != '_') + buf2[i++] = c; + } + buf2[i] = '\0'; + if (*p == ',' || *p == ';') + p++; + *pp = p; + return true; } +fn bool matchColorName(const char *p, const char *name) { + while (*p) { + char c = *p++; + if (c == 'b' && !strncmp(p, "right", 5)) + p += 5; + if (c != *name++) + return false; + } + return *name == '\0'; +} + +fn const char* convertColor(const char *val, const char *def) { + if (*val == '\0') + return ""; + + for (u32 i = 0; i < elemsof(standardColors); i += 2) { + if (matchColorName(val, standardColors[i])) + return standardColors[i + 1]; + } + if (!strcasecmp(val, "default")) + return def; + + char[32] buf; + i32 pal; + i32 r; + i32 g; + i32 b; + if (sscanf(val, "%*1[pP]%d", &pal) == 1) { + snprintf(buf, elemsof(buf), "\033[38;5;%dm", pal); + } else + if (sscanf(val, "#%2x%2x%2x", &r, &g, &b) == 3) { + snprintf(buf, elemsof(buf), "\033[38;2;%d;%d;%dm", r, g, b); + } else { + // TODO: complain about unknown color + return def; + } + return strdup(buf); +} + +public fn const char* getConfigColor(const char* cat, const char* def) { + if (!use_color) + return ""; + if (c2_colors) { + const char *p = c2_colors; + char[16] style; + char[16] val; + while (getStyleDef(style, elemsof(style), val, elemsof(val), &p)) { + if (!strcmp(style, cat)) + return convertColor(val, def); + } + } + return def; +} diff --git a/common/console.c2 b/common/console.c2 index 278dc09c..de69be09 100644 --- a/common/console.c2 +++ b/common/console.c2 @@ -26,8 +26,19 @@ bool show_timing = false; const u32 BUF_SIZE = 4096; +const char* col_normal = color.Normal; +const char* col_error = color.Red; +const char* col_warning = color.Yellow; +const char* col_debug = color.Blue; +const char* 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) { @@ -46,11 +57,7 @@ public fn void debug(const char* format @(printf_format), ...) { va_start(args, format); vsnprintf(buf, sizeof(buf), format, args); va_end(args); - if (use_color) { - printf("%s%s%s\n", color.Blue, buf, color.Normal); - } else { - printf("%s\n", buf); - } + printf("%s%s%s\n", col_debug, buf, col_normal); } public fn void log(const char* format @(printf_format), ...) { @@ -68,45 +75,29 @@ public fn void warn(const char* format @(printf_format), ...) { va_start(args, format); vsnprintf(buf, sizeof(buf), format, args); va_end(args); - if (use_color) { - fprintf(stderr, "%swarning: %s%s\n", color.Yellow, buf, color.Normal); - } else { - fprintf(stderr, "warning: %s\n", buf); - } + fprintf(stderr, "%swarning: %s%s\n", col_warning, buf, col_normal); } 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, buf, color.Normal); - } else { - fprintf(stderr, "error: %s\n", buf); - } + fprintf(stderr, "%serror: %s%s\n", col_error, buf, col_normal); } public fn void error_diag(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, loc, buf, color.Normal); - } else { - fprintf(stderr, "%s: error: %s\n", loc, buf); - } + fprintf(stderr, "%s%s: error: %s%s\n", col_error, loc, buf, col_normal); } 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, item, duration, color.Normal); - } else { - printf("%s took %d usec\n", item, duration); - } + printf("%s%s took %d usec%s\n", col_timing, item, duration, col_normal); } diff --git a/common/diagnostics.c2 b/common/diagnostics.c2 index da84992e..58d4415b 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 = color.getConfigColor("normal", color.Normal); + col_Range = color.getConfigColor("range", color.Bgreen); + } return diags; } @@ -75,6 +82,9 @@ const char*[] category_colors = { color.Bred, } +const char* col_Normal = color.Normal; +const char* 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 5b42be7b..97800d5c 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_buffer; import string_pool; @@ -186,7 +186,7 @@ public fn void SourceMgr.clear(SourceMgr* sm, i32 handle) { for (u32 i = start_handle; i < sm.num_files; i++) { File* f = &sm.files[i]; if (f.needed && !f.is_generated) { - stdio.printf("WARN %s still not closed\n", sm.pool.idx2str(f.filename)); + console.warn("%s still not closed", sm.pool.idx2str(f.filename)); } f.clear(); } @@ -216,13 +216,10 @@ fn file_utils.Reader SourceMgr.openInternal(SourceMgr* sm, const char* filename, if (file.open(filename)) { sm.num_open++; } else { - // TODO only color if enabled (cannot use console since we need source loc first) if (loc) { - stdio.fprintf(stdio.stderr, "%s: %serror:%s cannot open %s: %s\n", - sm.loc2str(loc), color.Red, color.Normal, filename, file.getError()); + console.error_diag(sm.loc2str(loc), "cannot open %s: %s", filename, file.getError()); } else { - stdio.fprintf(stdio.stderr, "%serror%s: cannot open %s: %s\n", - color.Red, color.Normal, filename, file.getError()); + console.error("cannot open %s: %s", filename, file.getError()); } } return file; @@ -285,9 +282,7 @@ public fn i32 SourceMgr.addGenerated(SourceMgr* sm, public fn i32 SourceMgr.open(SourceMgr* sm, u32 filename, SrcLoc loc, bool is_source) { if (sm.num_open == sm.max_open) { if (!sm.close_oldest()) { - // TODO use diags (color) - stdio.fprintf(stdio.stderr, "%serror%s: too many files open\n", - color.Red, color.Normal); + console.error("too many files open"); return -1; } } @@ -339,9 +334,7 @@ fn void SourceMgr.checkOpen(SourceMgr* sm, i32 handle) { if (sm.num_open == sm.max_open) { if (!sm.close_oldest()) { - // TODO use diags (color) - stdio.fprintf(stdio.stderr, "%serror%s: too many files open\n", - color.Red, color.Normal); + console.error("too many files open"); stdlib.exit(-1); } } diff --git a/compiler/c2recipe_parser.c2 b/compiler/c2recipe_parser.c2 index 4a855745..b2d6c550 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 source_mgr; import src_loc local; @@ -195,14 +195,10 @@ fn void Parser.error(Parser* p, const char* format @(printf_format), ...) @(nore char[128] msg; va_list args; va_start(args, format); - vsnprintf(msg, sizeof(msg)-1, format, args); + vsnprintf(msg, elemsof(msg), format, args); va_end(args); - if (color.useColor()) { - fprintf(stderr, "%s: %serror:%s %s\n", p.sm.loc2str(p.token.loc), color.Red, color.Normal, msg); - } else { - fprintf(stderr, "%s: error: %s\n", p.sm.loc2str(p.token.loc), msg); - } + console.error_diag(p.sm.loc2str(p.token.loc), "%s", msg); longjmp(&p.jmpbuf, 1); } diff --git a/parser/c2_parser.c2 b/parser/c2_parser.c2 index 0458d605..87f1a64d 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; @@ -733,13 +732,13 @@ fn void Parser.dump_token(Parser* p, const Token* tok) @(unused) { out.clear(); if (is_keyword(tok.kind)) - out.color(color.Green); + out.color(col_Keyword); out.print("%12s", tok.kind.str()); if (is_keyword(tok.kind)) - out.color(color.Normal); + out.color(col_Normal); out.print(" %6d %s ", tok.loc, p.sm.loc2str(tok.loc)); - out.color(color.Cyan); + out.color(col_Literal); switch (tok.kind) { case Identifier: out.add(p.pool.idx2str(tok.name_idx)); @@ -791,7 +790,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: @@ -804,18 +803,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 ea46334c..e7196014 100644 --- a/recipe.txt +++ b/recipe.txt @@ -338,6 +338,7 @@ executable tester ast_utils/color.c2 ast_utils/string_buffer.c2 + common/console.c2 common/constants.c2 common/file/reader.c2 common/file/writer.c2 @@ -361,6 +362,7 @@ executable c2cat ast_utils/string_buffer.c2 ast_utils/string_pool.c2 + common/console.c2 common/constants.c2 common/file/reader.c2 common/string_list.c2 @@ -390,6 +392,7 @@ executable c2loc ast_utils/string_pool.c2 common/build_target.c2 + common/console.c2 common/constants.c2 common/file/reader.c2 common/library_list.c2 diff --git a/tools/c2cat.c2 b/tools/c2cat.c2 index 2aa49728..51767e53 100644 --- a/tools/c2cat.c2 +++ b/tools/c2cat.c2 @@ -17,6 +17,7 @@ module c2cat_main; import c2_tokenizer; import color; +import console; import file_utils; import keywords; import string_buffer; @@ -81,21 +82,20 @@ const char*[] attr_names = { fn void init_colors() { - if (!color.useColor()) { - col_keyword = ""; - col_type = ""; - col_feature = ""; - col_attr = ""; - col_identifier = ""; - col_integer = ""; - col_float = ""; - col_charconst = ""; - col_string = ""; - col_comment = ""; - col_invalid = ""; - col_error = ""; - col_normal = ""; - } + color.useColor(); + col_keyword = color.getConfigColor("c2.keyword", color.Byellow); + col_type = color.getConfigColor("c2.type", color.Green); + col_feature = color.getConfigColor("c2.feature", color.Blue); + col_attr = color.getConfigColor("c2.attr", color.Blue); + col_identifier = color.getConfigColor("c2.identifier", ""); + col_integer = color.getConfigColor("c2.integer", color.Magenta); + col_float = color.getConfigColor("c2.float", color.Magenta); + col_charconst = color.getConfigColor("c2.charconst", color.Magenta); + col_string = color.getConfigColor("c2.string", color.Magenta); + col_comment = color.getConfigColor("c2.comment", color.Bcyan); + col_invalid = color.getConfigColor("c2.invalid", color.Bred); + col_error = color.getConfigColor("c2.error", color.Bred); + col_normal = color.getConfigColor("c2.normal", color.Normal); } fn bool is_attribute(const char* str) { @@ -343,6 +343,7 @@ public fn i32 c2cat(const char* filename) public fn i32 main(i32 argc, const char** argv) { if (argc == 1) usage(argv[0]); + console.init(); init_colors(); for (i32 i = 1; i < argc; i++) { if (argc > 2) diff --git a/tools/c2loc.c2 b/tools/c2loc.c2 index e4486b9f..f17490fb 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 source_mgr; import string_pool; @@ -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_db.c2 b/tools/tester/test_db.c2 index 63deab82..579c5cb0 100644 --- a/tools/tester/test_db.c2 +++ b/tools/tester/test_db.c2 @@ -22,7 +22,6 @@ import stdlib local; import string local; import unistd local; -import color; import constants; import expect_file local; import file_utils; @@ -470,7 +469,7 @@ fn void Db.error(Db* db, const char* format @(printf_format), ...) { vsnprintf(msg, sizeof(msg), format, args); va_end(args); // TODO use colError? - color_print2(db.output, color.Bred, "%s:%d: %s", db.filename, db.line_nr, msg); + color_print2(db.output, colError, "%s:%d: %s", db.filename, db.line_nr, msg); db.hasErrors = true; } @@ -747,7 +746,7 @@ public fn void Db.testFile(Db* db) { // TODO print pipe_stderr db.output.color(colError); db.output.add("c2c crashed!"); - db.output.color(color.Normal); + db.output.color(colNormal); db.output.newline(); db.hasErrors = true; return; @@ -762,7 +761,7 @@ public fn void Db.testFile(Db* db) { if (retcode == 254) { // from TODO/FATAL_ERROR macros db.output.color(colError); db.output.add("c2c returned error"); - db.output.color(color.Normal); + db.output.color(colNormal); db.output.newline(); db.hasErrors = true; return; @@ -864,7 +863,7 @@ public fn bool Db.printIssues(const Db* db) { db.output.color(colError); db.output.print("%s:%d: expected error '%s'", iter.getFilename(), iter.getLineNr(), iter.getMsg()); - db.output.color(color.Normal); + db.output.color(colNormal); db.output.newline(); res = true; iter.next(); @@ -875,7 +874,7 @@ public fn bool Db.printIssues(const Db* db) { db.output.color(colError); db.output.print("%s:%d: expected warning '%s'", iter.getFilename(), iter.getLineNr(), iter.getMsg()); - db.output.color(color.Normal); + db.output.color(colNormal); db.output.newline(); res = true; iter.next(); @@ -886,7 +885,7 @@ public fn bool Db.printIssues(const Db* db) { db.output.color(colError); db.output.print("%s:%d: expected note '%s'", iter.getFilename(), iter.getLineNr(), iter.getMsg()); - db.output.color(color.Normal); + db.output.color(colNormal); db.output.newline(); res = true; iter.next(); diff --git a/tools/tester/test_utils.c2 b/tools/tester/test_utils.c2 index 9a93422d..bfc66b0b 100644 --- a/tools/tester/test_utils.c2 +++ b/tools/tester/test_utils.c2 @@ -30,6 +30,7 @@ public const char* colError = color.Bred; public const char* colSkip = color.Bcyan; public const char* colOk = color.Green; public const char* colDebug = color.Bmagenta; +public const char* colNormal = color.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(const char* col, const char* format @(printf_format), ...) { @@ -57,7 +64,7 @@ public fn void color_print(const char* col, const char* format @(printf_format), vsnprintf(buffer, sizeof(buffer), format, args); va_end(args); - if (color_output) printf("%s%s%s\n", col, buffer, color.Normal); + if (color_output) printf("%s%s%s\n", col, buffer, colNormal); 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, buffer, color.Normal); + if (color_output) fprintf(stderr, "%s: %s%s%s\n", proc_name, colError, buffer, colNormal); else fprintf(stderr, "%s: %s\n", proc_name, buffer); } @@ -83,7 +90,7 @@ public fn void color_print2(string_buffer.Buf* output, vsnprintf(buffer, sizeof(buffer), format, args); va_end(args); - if (color_output) output.print("%s%s%s\n", col, buffer, color.Normal); + if (color_output) output.print("%s%s%s\n", col, buffer, colNormal); else output.print("%s\n", buffer); } diff --git a/tools/tester/tester.c2 b/tools/tester/tester.c2 index ef995604..bd2f57f3 100644 --- a/tools/tester/tester.c2 +++ b/tools/tester/tester.c2 @@ -318,7 +318,7 @@ public fn i32 main(i32 argc, char** argv) { u64 t1 = now(); - set_color_output(argv[0], unistd.isatty(1)); + set_color_output(argv[0]); for (i32 i = 1; i < argc; i++) { char *arg = argv[i];