authorgravatar for diegopyl1209@gmail.comDiego Peña y Lillo <diegopyl1209@gmail.com> 2026-06-16 12:23:04+02:00
committergravatar for justusk@noreply.codeberg.orgJustus Klausecker <justusk@noreply.codeberg.org> 2026-06-16 12:23:04+02:00
logf3607c75cc072df8ad52d3ae8ff6bcfb2dfeeb8f
tree349b6ac44a02fe8871484acae0f8e9cfbbf21114
parent0bcaad394ddbc629ab0b38aebbe90545ea3e9bab

Handle TERM=dumb for stdout/stderr (#35767)

fix: #35760 Reviewed-on: https://codeberg.org/ziglang/zig/pulls/35767 Reviewed-by: Justus Klausecker <justusk@noreply.codeberg.org>

1 files changed, 29 insertions(+), 12 deletions(-)

lib/std/Io/Threaded.zig+29-12
......@@ -218,6 +218,7 @@ pub const Environ = struct {
218218 DEBUGINFOD_CACHE_PATH: ?[:0]const u8 = null,
219219 XDG_CACHE_HOME: ?[:0]const u8 = null,
220220 HOME: ?[:0]const u8 = null,
221 TERM: ?[:0]const u8 = null,
221222 },
222223 };
223224
......@@ -8800,9 +8801,8 @@ fn isTty(file: File) Io.Cancelable!bool {
88008801
88018802fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiEscapeCodesError!void {
88028803 const t: *Threaded = @ptrCast(@alignCast(userdata));
8803 _ = t;
88048804
8805 if (!is_windows) return if (!try supportsAnsiEscapeCodes(file)) error.NotTerminalDevice;
8805 if (!is_windows) return if (!try supportsAnsiEscapeCodes(t, file)) error.NotTerminalDevice;
88068806
88078807 // For Windows Terminal, VT Sequences processing is enabled by default.
88088808 const console: File = .{
......@@ -8850,14 +8850,13 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE
88508850
88518851fn fileSupportsAnsiEscapeCodes(userdata: ?*anyopaque, file: File) Io.Cancelable!bool {
88528852 const t: *Threaded = @ptrCast(@alignCast(userdata));
8853 _ = t;
8854 return supportsAnsiEscapeCodes(file);
8853 return supportsAnsiEscapeCodes(t, file);
88558854}
88568855
8857fn supportsAnsiEscapeCodes(file: File) Io.Cancelable!bool {
8856fn supportsAnsiEscapeCodes(t: *Threaded, file: File) Io.Cancelable!bool {
88588857 if (is_windows) {
88598858 var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE;
8860 switch ((try deviceIoControl(&.{
8859 return switch ((try deviceIoControl(&.{
88618860 .file = .{
88628861 .handle = windows.peb().ProcessParameters.ConsoleHandle,
88638862 .flags = .{ .nonblocking = false },
......@@ -8865,15 +8864,33 @@ fn supportsAnsiEscapeCodes(file: File) Io.Cancelable!bool {
88658864 .code = windows.IOCTL.CONDRV.ISSUE_USER_IO,
88668865 .in = @ptrCast(&get_console_mode.request(file, 0, .{}, 0, .{})),
88678866 })).u.Status) {
8868 .SUCCESS => if (get_console_mode.Data & windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0)
8869 return true,
8867 .SUCCESS => get_console_mode.Data & windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0,
88708868 .CANCELLED => unreachable,
8871 .INVALID_HANDLE => return isCygwinPty(file),
8872 else => return false,
8873 }
8869 .INVALID_HANDLE => isCygwinPty(file),
8870 else => false,
8871 };
88748872 }
88758873
8876 if (try isTty(file)) return true;
8874 if (native_os == .wasi) {
8875 // WASI sanitizes stdout when fd is a tty so ANSI escape codes
8876 // will not be interpreted as actual cursor commands, and
8877 // stderr is always sanitized.
8878
8879 return false;
8880 }
8881
8882 if (try isTty(file)) {
8883 if (file.handle == posix.STDOUT_FILENO or file.handle == posix.STDERR_FILENO) {
8884 t.scanEnviron();
8885 if (t.environ.string.TERM) |term| {
8886 if (std.mem.eql(u8, term, "dumb")) {
8887 return false;
8888 }
8889 }
8890 }
8891
8892 return true;
8893 }
88778894
88788895 return false;
88798896}