authorgravatar for alancocanour@gmail.comAlan Cocanour <alancocanour@gmail.com> 2026-05-07 20:12:58-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-26 17:56:40-07:00
log9c565509313cc497739d518e7bf2de69b1f195bb
tree9d5a8e525e2fb1f812d7f7c6e571d7b310e7227d
parent3852c8eae40755340cf9b06e4e3798884b0ecb7f

Respect environment variable preference for color in all zig commands

This makes all commands in the zig executable that support color output respect the user's preference for color output based on the NO_COLOR and CLICOLOR_FORCE environment variables. Setting color preference via command line option still overrides preferences set via environment variables.

2 files changed, 29 insertions(+), 19 deletions(-)

lib/std/zig.zig+12
......@@ -65,6 +65,18 @@ pub const Color = enum {
6565 .off => .no_color,
6666 };
6767 }
68
69 /// Determine the preference for color or no color based on the NO_COLOR and
70 /// CLICOLOR_FORCE environment variables. Color is always disabled on WASI per
71 /// https://github.com/WebAssembly/WASI/issues/162
72 pub fn settingFromEnvironment(environ_map: *const std.process.Environ.Map) Color {
73 return if (@import("builtin").os.tag == .wasi or EnvVar.NO_COLOR.isSet(environ_map))
74 .off
75 else if (EnvVar.CLICOLOR_FORCE.isSet(environ_map))
76 .on
77 else
78 .auto;
79 }
6880};
6981
7082/// There are many assumptions in the entire codebase that Zig source files can
src/main.zig+17-19
......@@ -327,6 +327,7 @@ fn mainArgs(
327327 .depend_on_aro = true,
328328 .prepend_zig_lib_dir_path = true,
329329 .server = use_server,
330 .color = Color.settingFromEnvironment(environ_map),
330331 });
331332 } else if (mem.eql(u8, cmd, "fmt")) {
332333 dev.check(.fmt_command);
......@@ -335,11 +336,13 @@ fn mainArgs(
335336 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
336337 .cmd_name = "objcopy",
337338 .root_src_path = "objcopy.zig",
339 .color = Color.settingFromEnvironment(environ_map),
338340 });
339341 } else if (mem.eql(u8, cmd, "objdump")) {
340342 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
341343 .cmd_name = "objdump",
342344 .root_src_path = "objdump.zig",
345 .color = Color.settingFromEnvironment(environ_map),
343346 });
344347 } else if (mem.eql(u8, cmd, "fetch")) {
345348 return cmdFetch(gpa, arena, io, cmd_args, environ_map);
......@@ -348,6 +351,7 @@ fn mainArgs(
348351 .cmd_name = "libc",
349352 .root_src_path = "libc.zig",
350353 .prepend_zig_lib_dir_path = true,
354 .color = Color.settingFromEnvironment(environ_map),
351355 });
352356 } else if (mem.eql(u8, cmd, "std")) {
353357 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
......@@ -356,6 +360,7 @@ fn mainArgs(
356360 .prepend_zig_lib_dir_path = true,
357361 .prepend_zig_exe_path = true,
358362 .prepend_global_cache_path = true,
363 .color = Color.settingFromEnvironment(environ_map),
359364 });
360365 } else if (mem.eql(u8, cmd, "init")) {
361366 return cmdInit(gpa, arena, io, cmd_args);
......@@ -387,6 +392,7 @@ fn mainArgs(
387392 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
388393 .cmd_name = "reduce",
389394 .root_src_path = "reduce.zig",
395 .color = Color.settingFromEnvironment(environ_map),
390396 });
391397 } else if (mem.eql(u8, cmd, "zen")) {
392398 dev.check(.zen_command);
......@@ -395,9 +401,9 @@ fn mainArgs(
395401 dev.check(.help_command);
396402 return Io.File.stdout().writeStreamingAll(io, usage);
397403 } else if (mem.eql(u8, cmd, "ast-check")) {
398 return cmdAstCheck(arena, io, cmd_args);
404 return cmdAstCheck(arena, io, cmd_args, environ_map);
399405 } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "changelist")) {
400 return cmdChangelist(arena, io, cmd_args);
406 return cmdChangelist(arena, io, cmd_args, environ_map);
401407 } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "dump-zir")) {
402408 return cmdDumpZir(arena, io, cmd_args);
403409 } else {
......@@ -1024,16 +1030,7 @@ fn buildOutputType(
10241030 };
10251031 defer create_module.link_inputs.deinit(gpa);
10261032
1027 // before arg parsing, check for the NO_COLOR and CLICOLOR_FORCE environment variables
1028 // if set, default the color setting to .off or .on, respectively
1029 // explicit --color arguments will still override this setting.
1030 // Disable color on WASI per https://github.com/WebAssembly/WASI/issues/162
1031 var color: Color = if (native_os == .wasi or EnvVar.NO_COLOR.isSet(environ_map))
1032 .off
1033 else if (EnvVar.CLICOLOR_FORCE.isSet(environ_map))
1034 .on
1035 else
1036 .auto;
1033 var color: Color = Color.settingFromEnvironment(environ_map);
10371034 var n_jobs: ?u32 = null;
10381035
10391036 switch (arg_mode) {
......@@ -4734,7 +4731,7 @@ fn cmdTranslateC(
47344731 p.* = result;
47354732 return;
47364733 } else {
4737 const color: Color = .auto;
4734 const color: Color = Color.settingFromEnvironment(environ_map);
47384735 result.errors.renderToStderr(io, .{}, color) catch {};
47394736 process.exit(1);
47404737 }
......@@ -4780,6 +4777,7 @@ pub fn translateC(
47804777 .root_src_path = "translate-c/main.zig",
47814778 .depend_on_aro = true,
47824779 .capture = capture,
4780 .color = Color.settingFromEnvironment(environ_map),
47834781 });
47844782}
47854783
......@@ -5005,7 +5003,7 @@ fn cmdBuild(
50055003 configure_argv.addManyAsArrayAssumeCapacity(2).* = .{ "--build-root", undefined };
50065004 const conf_argv_index_build_root = configure_argv.items.len - 1;
50075005
5008 var color: Color = .auto;
5006 var color: Color = Color.settingFromEnvironment(environ_map);
50095007 var n_jobs: ?u32 = null;
50105008
50115009 {
......@@ -6543,12 +6541,12 @@ const usage_ast_check =
65436541 \\
65446542;
65456543
6546fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8) !void {
6544fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: *const std.process.Environ.Map) !void {
65476545 dev.check(.ast_check_command);
65486546
65496547 const Zir = std.zig.Zir;
65506548
6551 var color: Color = .auto;
6549 var color: Color = Color.settingFromEnvironment(environ_map);
65526550 var want_output_text = false;
65536551 var force_zon = false;
65546552 var zig_source_path: ?[]const u8 = null;
......@@ -6755,10 +6753,10 @@ fn cmdDumpZir(arena: Allocator, io: Io, args: []const []const u8) !void {
67556753}
67566754
67576755/// This is only enabled for debug builds.
6758fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8) !void {
6756fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map: *const std.process.Environ.Map) !void {
67596757 dev.check(.changelist_command);
67606758
6761 const color: Color = .auto;
6759 const color: Color = Color.settingFromEnvironment(environ_map);
67626760 const Zir = std.zig.Zir;
67636761
67646762 const old_source_path = args[0];
......@@ -7130,7 +7128,7 @@ fn cmdFetch(
71307128) !void {
71317129 dev.check(.fetch_command);
71327130
7133 const color: Color = .auto;
7131 const color: Color = Color.settingFromEnvironment(environ_map);
71347132 var opt_path_or_url: ?[]const u8 = null;
71357133 var override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map);
71367134 var override_local_cache_dir: ?[]const u8 = EnvVar.ZIG_LOCAL_CACHE_DIR.get(environ_map);