From e2b954c2738c683a85b864eb33530f0e3dbbc480 Mon Sep 17 00:00:00 2001 From: Martin Wickham Date: Mon, 21 Jun 2021 13:47:38 -0500 Subject: [PATCH] Add support for NO_COLOR --- lib/std/debug.zig | 8 ++++---- lib/std/process.zig | 20 ++++++++++++++++++++ lib/std/special/build_runner.zig | 5 +++++ src/main.zig | 18 +++++++----------- src/stage1/errmsg.cpp | 4 ++-- src/stage1/os.cpp | 5 +++-- src/stage1/os.hpp | 2 +- 7 files changed, 42 insertions(+), 20 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 57445d3cb1..f74d0b3f91 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -90,11 +90,11 @@ pub fn getSelfDebugInfo() !*DebugInfo { } pub fn detectTTYConfig() TTY.Config { - var bytes: [128]u8 = undefined; - const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator; - if (process.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| { + if (process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) { return .escape_codes; - } else |_| { + } else if (process.hasEnvVarConstant("NO_COLOR")) { + return .no_color; + } else { const stderr_file = io.getStdErr(); if (stderr_file.supportsAnsiEscapeCodes()) { return .escape_codes; diff --git a/lib/std/process.zig b/lib/std/process.zig index 83926ee5af..4e875e7ebd 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -179,6 +179,26 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned } } +pub fn hasEnvVarConstant(comptime key: []const u8) bool { + if (builtin.os.tag == .windows) { + const key_w = comptime std.unicode.utf8ToUtf16LeStringLiteral(key); + return std.os.getenvW(key_w) != null; + } else { + return os.getenv(key) != null; + } +} + +pub fn hasEnvVar(allocator: *Allocator, key: []const u8) error{OutOfMemory}!bool { + if (builtin.os.tag == .windows) { + var stack_alloc = std.heap.stackFallback(256 * @sizeOf(u16), allocator); + const key_w = try std.unicode.utf8ToUtf16LeWithNull(&stack_alloc.allocator, key); + defer stack_alloc.allocator.free(key_w); + return std.os.getenvW(key_w) != null; + } else { + return os.getenv(key) != null; + } +} + test "os.getEnvVarOwned" { var ga = std.testing.allocator; try testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV")); diff --git a/lib/std/special/build_runner.zig b/lib/std/special/build_runner.zig index 7530fae4f0..475199eaf4 100644 --- a/lib/std/special/build_runner.zig +++ b/lib/std/special/build_runner.zig @@ -63,6 +63,11 @@ pub fn main() !void { var install_prefix: ?[]const u8 = null; var dir_list = Builder.DirList{}; + // before arg parsing, check for the NO_COLOR environment variable + // if it exists, default the color setting to .off + // explicit --color arguments will still override this setting. + builder.color = if (std.process.hasEnvVarConstant("NO_COLOR")) .off else .auto; + while (nextArg(args, &arg_idx)) |arg| { if (mem.startsWith(u8, arg, "-D")) { const option_contents = arg[2..]; diff --git a/src/main.zig b/src/main.zig index 37044d0b99..2b961bb64c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -503,15 +503,6 @@ const Emit = union(enum) { } }; -fn optionalBoolEnvVar(arena: *Allocator, name: []const u8) !bool { - if (std.process.getEnvVarOwned(arena, name)) |_| { - return true; - } else |err| switch (err) { - error.EnvironmentVariableNotFound => return false, - else => |e| return e, - } -} - fn optionalStringEnvVar(arena: *Allocator, name: []const u8) !?[]const u8 { if (std.process.getEnvVarOwned(arena, name)) |value| { return value; @@ -548,8 +539,8 @@ fn buildOutputType( var single_threaded = false; var function_sections = false; var watch = false; - var verbose_link = try optionalBoolEnvVar(arena, "ZIG_VERBOSE_LINK"); - var verbose_cc = try optionalBoolEnvVar(arena, "ZIG_VERBOSE_CC"); + var verbose_link = std.process.hasEnvVarConstant("ZIG_VERBOSE_LINK"); + var verbose_cc = std.process.hasEnvVarConstant("ZIG_VERBOSE_CC"); var verbose_air = false; var verbose_llvm_ir = false; var verbose_cimport = false; @@ -670,6 +661,11 @@ fn buildOutputType( defer freePkgTree(gpa, &pkg_tree_root, false); var cur_pkg: *Package = &pkg_tree_root; + // before arg parsing, check for the NO_COLOR environment variable + // if it exists, default the color setting to .off + // explicit --color arguments will still override this setting. + color = if (std.process.hasEnvVarConstant("NO_COLOR")) .off else .auto; + switch (arg_mode) { .build, .translate_c, .zig_test, .run => { var optimize_mode_string: ?[]const u8 = null; diff --git a/src/stage1/errmsg.cpp b/src/stage1/errmsg.cpp index e04d39fe88..943b118ddb 100644 --- a/src/stage1/errmsg.cpp +++ b/src/stage1/errmsg.cpp @@ -16,8 +16,8 @@ enum ErrType { }; static void print_err_msg_type(ErrorMsg *err, ErrColor color, ErrType err_type) { - bool is_tty = os_stderr_tty(); - bool use_colors = color == ErrColorOn || (color == ErrColorAuto && is_tty); + bool supports_color = os_stderr_supports_color(); + bool use_colors = color == ErrColorOn || (color == ErrColorAuto && supports_color); // Show the error location, if available if (err->path != nullptr) { diff --git a/src/stage1/os.cpp b/src/stage1/os.cpp index a4c5330a1f..10cd2c08fe 100644 --- a/src/stage1/os.cpp +++ b/src/stage1/os.cpp @@ -834,13 +834,14 @@ static bool is_stderr_cyg_pty(void) { } #endif -bool os_stderr_tty(void) { +bool os_stderr_supports_color(void) { + if (getenv("NO_COLOR") != NULL) return false; #if defined(ZIG_OS_WINDOWS) return _isatty(_fileno(stderr)) != 0 || is_stderr_cyg_pty(); #elif defined(ZIG_OS_POSIX) return isatty(STDERR_FILENO) != 0; #else -#error "missing os_stderr_tty implementation" +#error "missing os_stderr_supports_color implementation" #endif } diff --git a/src/stage1/os.hpp b/src/stage1/os.hpp index d4eb9b5d07..f1022778d4 100644 --- a/src/stage1/os.hpp +++ b/src/stage1/os.hpp @@ -99,7 +99,7 @@ Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents); Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd); -bool os_stderr_tty(void); +bool os_stderr_supports_color(void); void os_stderr_set_color(TermColor color); Error os_rename(Buf *src_path, Buf *dest_path);