| author | |
| committer | |
| log | 88d927a511922efd82c4ec862c8e2aa83df84391 |
| tree | 16449de5465989e1e3f8ae7894b5544cd9491109 |
| parent | 83e0e23f8aa2d90495bbf9c3649aa68f7c55c926 |
This fixes a regression introduced in #12298 where colors would never reset in a Windows console because the attributes would be queried on every `setColor` call, and then try to 'reset' the attributes to what it just queried (i.e. it was essentially doing a complicated no-op on .Reset).
This fixes the problem while (I think) keeping with the spirit of the changes in #12298--that is, `TTY.Config` is not specifically tied to stderr like it was before #12298. To that end, detectTTYConfig now takes a `File` and that's what gets used to query the initial attributes to reset to.
(for context, before #12298, the first `setColor` call is where the reset attributes would get queried and it would always use stderr to do it)4 files changed, 35 insertions(+), 26 deletions(-)
lib/std/builtin.zig+1-1| ... | ... | @@ -51,7 +51,7 @@ pub const StackTrace = struct { |
| 51 | 51 | const debug_info = std.debug.getSelfDebugInfo() catch |err| { |
| 52 | 52 | return writer.print("\nUnable to print stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}); |
| 53 | 53 | }; |
| 54 | const tty_config = std.debug.detectTTYConfig(); | |
| 54 | const tty_config = std.debug.detectTTYConfig(std.io.getStdErr()); | |
| 55 | 55 | try writer.writeAll("\n"); |
| 56 | 56 | std.debug.writeStackTrace(self, writer, arena.allocator(), debug_info, tty_config) catch |err| { |
| 57 | 57 | try writer.print("Unable to print stack trace: {s}\n", .{@errorName(err)}); |
lib/std/debug.zig+26-17| ... | ... | @@ -109,17 +109,24 @@ pub fn getSelfDebugInfo() !*DebugInfo { |
| 109 | 109 | } |
| 110 | 110 | } |
| 111 | 111 | |
| 112 | pub fn detectTTYConfig() TTY.Config { | |
| 112 | pub fn detectTTYConfig(file: std.fs.File) TTY.Config { | |
| 113 | 113 | if (process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) { |
| 114 | 114 | return .escape_codes; |
| 115 | 115 | } else if (process.hasEnvVarConstant("NO_COLOR")) { |
| 116 | 116 | return .no_color; |
| 117 | 117 | } else { |
| 118 | const stderr_file = io.getStdErr(); | |
| 119 | if (stderr_file.supportsAnsiEscapeCodes()) { | |
| 118 | if (file.supportsAnsiEscapeCodes()) { | |
| 120 | 119 | return .escape_codes; |
| 121 | } else if (native_os == .windows and stderr_file.isTty()) { | |
| 122 | return .{ .windows_api = stderr_file }; | |
| 120 | } else if (native_os == .windows and file.isTty()) { | |
| 121 | var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; | |
| 122 | if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) { | |
| 123 | // TODO: Should this return an error instead? | |
| 124 | return .no_color; | |
| 125 | } | |
| 126 | return .{ .windows_api = .{ | |
| 127 | .handle = file.handle, | |
| 128 | .reset_attributes = info.wAttributes, | |
| 129 | } }; | |
| 123 | 130 | } else { |
| 124 | 131 | return .no_color; |
| 125 | 132 | } |
| ... | ... | @@ -146,7 +153,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { |
| 146 | 153 | stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return; |
| 147 | 154 | return; |
| 148 | 155 | }; |
| 149 | writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(), start_addr) catch |err| { | |
| 156 | writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(io.getStdErr()), start_addr) catch |err| { | |
| 150 | 157 | stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return; |
| 151 | 158 | return; |
| 152 | 159 | }; |
| ... | ... | @@ -174,7 +181,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { |
| 174 | 181 | stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return; |
| 175 | 182 | return; |
| 176 | 183 | }; |
| 177 | const tty_config = detectTTYConfig(); | |
| 184 | const tty_config = detectTTYConfig(io.getStdErr()); | |
| 178 | 185 | printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return; |
| 179 | 186 | var it = StackIterator.init(null, bp); |
| 180 | 187 | while (it.next()) |return_address| { |
| ... | ... | @@ -257,7 +264,7 @@ pub fn dumpStackTrace(stack_trace: std.builtin.StackTrace) void { |
| 257 | 264 | stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return; |
| 258 | 265 | return; |
| 259 | 266 | }; |
| 260 | writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, detectTTYConfig()) catch |err| { | |
| 267 | writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, detectTTYConfig(io.getStdErr())) catch |err| { | |
| 261 | 268 | stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return; |
| 262 | 269 | return; |
| 263 | 270 | }; |
| ... | ... | @@ -600,7 +607,12 @@ pub const TTY = struct { |
| 600 | 607 | pub const Config = union(enum) { |
| 601 | 608 | no_color, |
| 602 | 609 | escape_codes, |
| 603 | windows_api: File, | |
| 610 | windows_api: if (native_os == .windows) WindowsContext else void, | |
| 611 | ||
| 612 | pub const WindowsContext = struct { | |
| 613 | handle: File.Handle, | |
| 614 | reset_attributes: u16, | |
| 615 | }; | |
| 604 | 616 | |
| 605 | 617 | pub fn setColor(conf: Config, out_stream: anytype, color: Color) !void { |
| 606 | 618 | nosuspend switch (conf) { |
| ... | ... | @@ -617,19 +629,16 @@ pub const TTY = struct { |
| 617 | 629 | }; |
| 618 | 630 | try out_stream.writeAll(color_string); |
| 619 | 631 | }, |
| 620 | .windows_api => |file| if (native_os == .windows) { | |
| 621 | var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; | |
| 622 | if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) | |
| 623 | return error.FailedRetrievingTerminalInfo; | |
| 632 | .windows_api => |ctx| if (native_os == .windows) { | |
| 624 | 633 | const attributes = switch (color) { |
| 625 | 634 | .Red => windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY, |
| 626 | 635 | .Green => windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY, |
| 627 | 636 | .Cyan => windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY, |
| 628 | 637 | .White, .Bold => windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY, |
| 629 | 638 | .Dim => windows.FOREGROUND_INTENSITY, |
| 630 | .Reset => info.wAttributes, | |
| 639 | .Reset => ctx.reset_attributes, | |
| 631 | 640 | }; |
| 632 | try windows.SetConsoleTextAttribute(file.handle, attributes); | |
| 641 | try windows.SetConsoleTextAttribute(ctx.handle, attributes); | |
| 633 | 642 | } else { |
| 634 | 643 | unreachable; |
| 635 | 644 | }, |
| ... | ... | @@ -2005,7 +2014,7 @@ test "#4353: std.debug should manage resources correctly" { |
| 2005 | 2014 | const writer = std.io.null_writer; |
| 2006 | 2015 | var di = try openSelfDebugInfo(testing.allocator); |
| 2007 | 2016 | defer di.deinit(); |
| 2008 | try printSourceAtAddress(&di, writer, showMyTrace(), detectTTYConfig()); | |
| 2017 | try printSourceAtAddress(&di, writer, showMyTrace(), detectTTYConfig(std.io.getStdErr())); | |
| 2009 | 2018 | } |
| 2010 | 2019 | |
| 2011 | 2020 | noinline fn showMyTrace() usize { |
| ... | ... | @@ -2065,7 +2074,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize |
| 2065 | 2074 | pub fn dump(t: @This()) void { |
| 2066 | 2075 | if (!enabled) return; |
| 2067 | 2076 | |
| 2068 | const tty_config = detectTTYConfig(); | |
| 2077 | const tty_config = detectTTYConfig(std.io.getStdErr()); | |
| 2069 | 2078 | const stderr = io.getStdErr().writer(); |
| 2070 | 2079 | const end = @min(t.index, size); |
| 2071 | 2080 | const debug_info = getSelfDebugInfo() catch |err| { |
lib/std/testing.zig+1-1| ... | ... | @@ -312,7 +312,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const |
| 312 | 312 | const actual_window = actual[window_start..@min(actual.len, window_start + max_window_size)]; |
| 313 | 313 | const actual_truncated = window_start + actual_window.len < actual.len; |
| 314 | 314 | |
| 315 | const ttyconf = std.debug.detectTTYConfig(); | |
| 315 | const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr()); | |
| 316 | 316 | var differ = if (T == u8) BytesDiffer{ |
| 317 | 317 | .expected = expected_window, |
| 318 | 318 | .actual = actual_window, |
src/main.zig+7-7| ... | ... | @@ -3431,7 +3431,7 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void |
| 3431 | 3431 | |
| 3432 | 3432 | if (errors.list.len != 0) { |
| 3433 | 3433 | const ttyconf: std.debug.TTY.Config = switch (comp.color) { |
| 3434 | .auto => std.debug.detectTTYConfig(), | |
| 3434 | .auto => std.debug.detectTTYConfig(std.io.getStdErr()), | |
| 3435 | 3435 | .on => .escape_codes, |
| 3436 | 3436 | .off => .no_color, |
| 3437 | 3437 | }; |
| ... | ... | @@ -4252,7 +4252,7 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void |
| 4252 | 4252 | |
| 4253 | 4253 | try Compilation.AllErrors.addZir(arena_instance.allocator(), &errors, &file); |
| 4254 | 4254 | const ttyconf: std.debug.TTY.Config = switch (color) { |
| 4255 | .auto => std.debug.detectTTYConfig(), | |
| 4255 | .auto => std.debug.detectTTYConfig(std.io.getStdErr()), | |
| 4256 | 4256 | .on => .escape_codes, |
| 4257 | 4257 | .off => .no_color, |
| 4258 | 4258 | }; |
| ... | ... | @@ -4465,7 +4465,7 @@ fn fmtPathFile( |
| 4465 | 4465 | |
| 4466 | 4466 | try Compilation.AllErrors.addZir(arena_instance.allocator(), &errors, &file); |
| 4467 | 4467 | const ttyconf: std.debug.TTY.Config = switch (fmt.color) { |
| 4468 | .auto => std.debug.detectTTYConfig(), | |
| 4468 | .auto => std.debug.detectTTYConfig(std.io.getStdErr()), | |
| 4469 | 4469 | .on => .escape_codes, |
| 4470 | 4470 | .off => .no_color, |
| 4471 | 4471 | }; |
| ... | ... | @@ -4586,7 +4586,7 @@ fn printErrsMsgToStdErr( |
| 4586 | 4586 | }; |
| 4587 | 4587 | |
| 4588 | 4588 | const ttyconf: std.debug.TTY.Config = switch (color) { |
| 4589 | .auto => std.debug.detectTTYConfig(), | |
| 4589 | .auto => std.debug.detectTTYConfig(std.io.getStdErr()), | |
| 4590 | 4590 | .on => .escape_codes, |
| 4591 | 4591 | .off => .no_color, |
| 4592 | 4592 | }; |
| ... | ... | @@ -5176,7 +5176,7 @@ pub fn cmdAstCheck( |
| 5176 | 5176 | var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena); |
| 5177 | 5177 | try Compilation.AllErrors.addZir(arena, &errors, &file); |
| 5178 | 5178 | const ttyconf: std.debug.TTY.Config = switch (color) { |
| 5179 | .auto => std.debug.detectTTYConfig(), | |
| 5179 | .auto => std.debug.detectTTYConfig(std.io.getStdErr()), | |
| 5180 | 5180 | .on => .escape_codes, |
| 5181 | 5181 | .off => .no_color, |
| 5182 | 5182 | }; |
| ... | ... | @@ -5301,7 +5301,7 @@ pub fn cmdChangelist( |
| 5301 | 5301 | if (file.zir.hasCompileErrors()) { |
| 5302 | 5302 | var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena); |
| 5303 | 5303 | try Compilation.AllErrors.addZir(arena, &errors, &file); |
| 5304 | const ttyconf = std.debug.detectTTYConfig(); | |
| 5304 | const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr()); | |
| 5305 | 5305 | for (errors.items) |full_err_msg| { |
| 5306 | 5306 | full_err_msg.renderToStdErr(ttyconf); |
| 5307 | 5307 | } |
| ... | ... | @@ -5340,7 +5340,7 @@ pub fn cmdChangelist( |
| 5340 | 5340 | if (file.zir.hasCompileErrors()) { |
| 5341 | 5341 | var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena); |
| 5342 | 5342 | try Compilation.AllErrors.addZir(arena, &errors, &file); |
| 5343 | const ttyconf = std.debug.detectTTYConfig(); | |
| 5343 | const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr()); | |
| 5344 | 5344 | for (errors.items) |full_err_msg| { |
| 5345 | 5345 | full_err_msg.renderToStdErr(ttyconf); |
| 5346 | 5346 | } |