authorgravatar for carl@astholm.seCarl Åstholm <carl@astholm.se> 2026-02-02 01:24:39+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-04-11 12:25:22-07:00
log3223d3a1ac0aa7a5ffb9252c2e8d871f0bf70ec0
treeb9fc32edffcd5d1673831077f580acd00028e94e
parent3d482643651285143b555b61c5a6a48db6fc8518

Improve debug I/O color detection/handling for WASI and Emscripten

When linking libc, these targets can get their environment variables from `std.c.environ`. Additionally, it's okay for WASI to use ANSI escape sequences; nothing in the relevant specs claim otherwise.

3 files changed, 16 insertions(+), 11 deletions(-)

lib/std/Io/Threaded.zig-7
......@@ -8729,13 +8729,6 @@ fn supportsAnsiEscapeCodes(file: File) Io.Cancelable!bool {
87298729 }
87308730 }
87318731
8732 if (native_os == .wasi) {
8733 // WASI sanitizes stdout when fd is a tty so ANSI escape codes will not
8734 // be interpreted as actual cursor commands, and stderr is always
8735 // sanitized.
8736 return false;
8737 }
8738
87398732 if (try isTty(file)) return true;
87408733
87418734 return false;
lib/std/process/Environ.zig+1-1
......@@ -24,7 +24,7 @@ pub const empty: Environ = .{ .block = .empty };
2424/// operating system `void` is also used.
2525pub const Block = switch (native_os) {
2626 .windows => GlobalBlock,
27 .wasi => switch (builtin.link_libc) {
27 .wasi, .emscripten => switch (builtin.link_libc) {
2828 false => GlobalBlock,
2929 true => PosixBlock,
3030 },
lib/std/start.zig+15-3
......@@ -664,10 +664,22 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal
664664
665665fn mainWithoutEnv(c_argc: c_int, c_argv: [*][*:0]c_char) callconv(.c) c_int {
666666 const argv = @as([*][*:0]u8, @ptrCast(c_argv))[0..@intCast(c_argc)];
667 if (@sizeOf(std.Io.Threaded.Argv0) != 0) {
668 if (std.Options.debug_threaded_io) |t| t.argv0.value = argv[0];
667 const environ: [:null]?[*:0]u8 = switch (builtin.os.tag) {
668 .wasi, .emscripten => environ: {
669 const c_environ = std.c.environ;
670 var env_count: usize = 0;
671 while (c_environ[env_count] != null) : (env_count += 1) {}
672 break :environ c_environ[0..env_count :null];
673 },
674 else => &.{},
675 };
676 const env_block: std.process.Environ.Block = .{ .slice = environ };
677 if (std.Options.debug_threaded_io) |t| {
678 if (@sizeOf(std.Io.Threaded.Argv0) != 0) t.argv0.value = argv[0];
679 t.environ = .{ .process_environ = .{ .block = env_block } };
680 t.environ_initialized = env_block.isEmpty();
669681 }
670 return callMain(argv, .empty);
682 return callMain(argv, env_block);
671683}
672684
673685/// General error message for a malformed return type