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 {...@@ -218,6 +218,7 @@ pub const Environ = struct {
218 DEBUGINFOD_CACHE_PATH: ?[:0]const u8 = null,218 DEBUGINFOD_CACHE_PATH: ?[:0]const u8 = null,
219 XDG_CACHE_HOME: ?[:0]const u8 = null,219 XDG_CACHE_HOME: ?[:0]const u8 = null,
220 HOME: ?[:0]const u8 = null,220 HOME: ?[:0]const u8 = null,
221 TERM: ?[:0]const u8 = null,
221 },222 },
222 };223 };
223224
...@@ -8800,9 +8801,8 @@ fn isTty(file: File) Io.Cancelable!bool {...@@ -8800,9 +8801,8 @@ fn isTty(file: File) Io.Cancelable!bool {
88008801
8801fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiEscapeCodesError!void {8802fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiEscapeCodesError!void {
8802 const t: *Threaded = @ptrCast(@alignCast(userdata));8803 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
8807 // For Windows Terminal, VT Sequences processing is enabled by default.8807 // For Windows Terminal, VT Sequences processing is enabled by default.
8808 const console: File = .{8808 const console: File = .{
...@@ -8850,14 +8850,13 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE...@@ -8850,14 +8850,13 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE
88508850
8851fn fileSupportsAnsiEscapeCodes(userdata: ?*anyopaque, file: File) Io.Cancelable!bool {8851fn fileSupportsAnsiEscapeCodes(userdata: ?*anyopaque, file: File) Io.Cancelable!bool {
8852 const t: *Threaded = @ptrCast(@alignCast(userdata));8852 const t: *Threaded = @ptrCast(@alignCast(userdata));
8853 _ = t;8853 return supportsAnsiEscapeCodes(t, file);
8854 return supportsAnsiEscapeCodes(file);
8855}8854}
88568855
8857fn supportsAnsiEscapeCodes(file: File) Io.Cancelable!bool {8856fn supportsAnsiEscapeCodes(t: *Threaded, file: File) Io.Cancelable!bool {
8858 if (is_windows) {8857 if (is_windows) {
8859 var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE;8858 var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE;
8860 switch ((try deviceIoControl(&.{8859 return switch ((try deviceIoControl(&.{
8861 .file = .{8860 .file = .{
8862 .handle = windows.peb().ProcessParameters.ConsoleHandle,8861 .handle = windows.peb().ProcessParameters.ConsoleHandle,
8863 .flags = .{ .nonblocking = false },8862 .flags = .{ .nonblocking = false },
...@@ -8865,15 +8864,33 @@ fn supportsAnsiEscapeCodes(file: File) Io.Cancelable!bool {...@@ -8865,15 +8864,33 @@ fn supportsAnsiEscapeCodes(file: File) Io.Cancelable!bool {
8865 .code = windows.IOCTL.CONDRV.ISSUE_USER_IO,8864 .code = windows.IOCTL.CONDRV.ISSUE_USER_IO,
8866 .in = @ptrCast(&get_console_mode.request(file, 0, .{}, 0, .{})),8865 .in = @ptrCast(&get_console_mode.request(file, 0, .{}, 0, .{})),
8867 })).u.Status) {8866 })).u.Status) {
8868 .SUCCESS => if (get_console_mode.Data & windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0)8867 .SUCCESS => get_console_mode.Data & windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0,
8869 return true,
8870 .CANCELLED => unreachable,8868 .CANCELLED => unreachable,
8871 .INVALID_HANDLE => return isCygwinPty(file),8869 .INVALID_HANDLE => isCygwinPty(file),
8872 else => return false,8870 else => false,
8873 }8871 };
8874 }8872 }
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
8878 return false;8895 return false;
8879}8896}