authorgravatar for mail@linusgroh.deLinus Groh <mail@linusgroh.de> 2023-05-21 14:27:28+01:00
committergravatar for mail@linusgroh.deLinus Groh <mail@linusgroh.de> 2023-05-24 10:15:02+01:00
log0f6fa3f20b3b28958921bd63a9a9d96468455e9c
treeb725c368b43701903b4fe145eb240bfffbdc79e6
parent39c2eee285f820282dedba4404cac1009a5ae2d6

std: Move std.debug.{TTY.Config,detectTTYConfig} to std.io.tty

Also get rid of the TTY wrapper struct, which was exlusively used as a namespace - this is done by the tty.zig root struct now. detectTTYConfig has been renamed to just detectConfig, which is enough given the new namespace. Additionally, a doc comment had been added.

11 files changed, 152 insertions(+), 144 deletions(-)

lib/build_runner.zig+6-6
...@@ -333,7 +333,7 @@ const Run = struct {...@@ -333,7 +333,7 @@ const Run = struct {
333333
334 claimed_rss: usize,334 claimed_rss: usize,
335 enable_summary: ?bool,335 enable_summary: ?bool,
336 ttyconf: std.debug.TTY.Config,336 ttyconf: std.io.tty.Config,
337 stderr: std.fs.File,337 stderr: std.fs.File,
338};338};
339339
...@@ -535,7 +535,7 @@ const PrintNode = struct {...@@ -535,7 +535,7 @@ const PrintNode = struct {
535 last: bool = false,535 last: bool = false,
536};536};
537537
538fn printPrefix(node: *PrintNode, stderr: std.fs.File, ttyconf: std.debug.TTY.Config) !void {538fn printPrefix(node: *PrintNode, stderr: std.fs.File, ttyconf: std.io.tty.Config) !void {
539 const parent = node.parent orelse return;539 const parent = node.parent orelse return;
540 if (parent.parent == null) return;540 if (parent.parent == null) return;
541 try printPrefix(parent, stderr, ttyconf);541 try printPrefix(parent, stderr, ttyconf);
...@@ -553,7 +553,7 @@ fn printTreeStep(...@@ -553,7 +553,7 @@ fn printTreeStep(
553 b: *std.Build,553 b: *std.Build,
554 s: *Step,554 s: *Step,
555 stderr: std.fs.File,555 stderr: std.fs.File,
556 ttyconf: std.debug.TTY.Config,556 ttyconf: std.io.tty.Config,
557 parent_node: *PrintNode,557 parent_node: *PrintNode,
558 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),558 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
559) !void {559) !void {
...@@ -1026,15 +1026,15 @@ fn cleanExit() void {...@@ -1026,15 +1026,15 @@ fn cleanExit() void {
10261026
1027const Color = enum { auto, off, on };1027const Color = enum { auto, off, on };
10281028
1029fn get_tty_conf(color: Color, stderr: std.fs.File) std.debug.TTY.Config {1029fn get_tty_conf(color: Color, stderr: std.fs.File) std.io.tty.Config {
1030 return switch (color) {1030 return switch (color) {
1031 .auto => std.debug.detectTTYConfig(stderr),1031 .auto => std.io.tty.detectConfig(stderr),
1032 .on => .escape_codes,1032 .on => .escape_codes,
1033 .off => .no_color,1033 .off => .no_color,
1034 };1034 };
1035}1035}
10361036
1037fn renderOptions(ttyconf: std.debug.TTY.Config) std.zig.ErrorBundle.RenderOptions {1037fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions {
1038 return .{1038 return .{
1039 .ttyconf = ttyconf,1039 .ttyconf = ttyconf,
1040 .include_source_line = ttyconf != .no_color,1040 .include_source_line = ttyconf != .no_color,
lib/std/Build.zig+1-1
...@@ -1712,7 +1712,7 @@ fn dumpBadGetPathHelp(...@@ -1712,7 +1712,7 @@ fn dumpBadGetPathHelp(
1712 s.name,1712 s.name,
1713 });1713 });
17141714
1715 const tty_config = std.debug.detectTTYConfig(stderr);1715 const tty_config = std.io.tty.detectConfig(stderr);
1716 tty_config.setColor(w, .red) catch {};1716 tty_config.setColor(w, .red) catch {};
1717 try stderr.writeAll(" The step was created by this stack trace:\n");1717 try stderr.writeAll(" The step was created by this stack trace:\n");
1718 tty_config.setColor(w, .reset) catch {};1718 tty_config.setColor(w, .reset) catch {};
lib/std/Build/Step.zig+1-1
...@@ -237,7 +237,7 @@ pub fn dump(step: *Step) void {...@@ -237,7 +237,7 @@ pub fn dump(step: *Step) void {
237237
238 const stderr = std.io.getStdErr();238 const stderr = std.io.getStdErr();
239 const w = stderr.writer();239 const w = stderr.writer();
240 const tty_config = std.debug.detectTTYConfig(stderr);240 const tty_config = std.io.tty.detectConfig(stderr);
241 const debug_info = std.debug.getSelfDebugInfo() catch |err| {241 const debug_info = std.debug.getSelfDebugInfo() catch |err| {
242 w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{242 w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{
243 @errorName(err),243 @errorName(err),
lib/std/builtin.zig+1-1
...@@ -51,7 +51,7 @@ pub const StackTrace = struct {...@@ -51,7 +51,7 @@ pub const StackTrace = struct {
51 const debug_info = std.debug.getSelfDebugInfo() catch |err| {51 const debug_info = std.debug.getSelfDebugInfo() catch |err| {
52 return writer.print("\nUnable to print stack trace: Unable to open debug info: {s}\n", .{@errorName(err)});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(std.io.getStdErr());54 const tty_config = std.io.tty.detectConfig(std.io.getStdErr());
55 try writer.writeAll("\n");55 try writer.writeAll("\n");
56 std.debug.writeStackTrace(self, writer, arena.allocator(), debug_info, tty_config) catch |err| {56 std.debug.writeStackTrace(self, writer, arena.allocator(), debug_info, tty_config) catch |err| {
57 try writer.print("Unable to print stack trace: {s}\n", .{@errorName(err)});57 try writer.print("Unable to print stack trace: {s}\n", .{@errorName(err)});
lib/std/debug.zig+11-126
...@@ -5,7 +5,6 @@ const mem = std.mem;...@@ -5,7 +5,6 @@ const mem = std.mem;
5const io = std.io;5const io = std.io;
6const os = std.os;6const os = std.os;
7const fs = std.fs;7const fs = std.fs;
8const process = std.process;
9const testing = std.testing;8const testing = std.testing;
10const elf = std.elf;9const elf = std.elf;
11const DW = std.dwarf;10const DW = std.dwarf;
...@@ -109,31 +108,6 @@ pub fn getSelfDebugInfo() !*DebugInfo {...@@ -109,31 +108,6 @@ pub fn getSelfDebugInfo() !*DebugInfo {
109 }108 }
110}109}
111110
112pub fn detectTTYConfig(file: std.fs.File) TTY.Config {
113 if (builtin.os.tag == .wasi) {
114 // Per https://github.com/WebAssembly/WASI/issues/162 ANSI codes
115 // aren't currently supported.
116 return .no_color;
117 } else if (process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) {
118 return .escape_codes;
119 } else if (process.hasEnvVarConstant("NO_COLOR")) {
120 return .no_color;
121 } else if (file.supportsAnsiEscapeCodes()) {
122 return .escape_codes;
123 } else if (native_os == .windows and file.isTty()) {
124 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
125 if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) {
126 // TODO: Should this return an error instead?
127 return .no_color;
128 }
129 return .{ .windows_api = .{
130 .handle = file.handle,
131 .reset_attributes = info.wAttributes,
132 } };
133 }
134 return .no_color;
135}
136
137/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.111/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
138/// TODO multithreaded awareness112/// TODO multithreaded awareness
139pub fn dumpCurrentStackTrace(start_addr: ?usize) void {113pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
...@@ -154,7 +128,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {...@@ -154,7 +128,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
154 stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;128 stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
155 return;129 return;
156 };130 };
157 writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(io.getStdErr()), start_addr) catch |err| {131 writeCurrentStackTrace(stderr, debug_info, io.tty.detectConfig(io.getStdErr()), start_addr) catch |err| {
158 stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;132 stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
159 return;133 return;
160 };134 };
...@@ -182,7 +156,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {...@@ -182,7 +156,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
182 stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;156 stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
183 return;157 return;
184 };158 };
185 const tty_config = detectTTYConfig(io.getStdErr());159 const tty_config = io.tty.detectConfig(io.getStdErr());
186 if (native_os == .windows) {160 if (native_os == .windows) {
187 writeCurrentStackTraceWindows(stderr, debug_info, tty_config, ip) catch return;161 writeCurrentStackTraceWindows(stderr, debug_info, tty_config, ip) catch return;
188 return;162 return;
...@@ -265,7 +239,7 @@ pub fn dumpStackTrace(stack_trace: std.builtin.StackTrace) void {...@@ -265,7 +239,7 @@ pub fn dumpStackTrace(stack_trace: std.builtin.StackTrace) void {
265 stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;239 stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
266 return;240 return;
267 };241 };
268 writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, detectTTYConfig(io.getStdErr())) catch |err| {242 writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, io.tty.detectConfig(io.getStdErr())) catch |err| {
269 stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;243 stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
270 return;244 return;
271 };245 };
...@@ -403,7 +377,7 @@ pub fn writeStackTrace(...@@ -403,7 +377,7 @@ pub fn writeStackTrace(
403 out_stream: anytype,377 out_stream: anytype,
404 allocator: mem.Allocator,378 allocator: mem.Allocator,
405 debug_info: *DebugInfo,379 debug_info: *DebugInfo,
406 tty_config: TTY.Config,380 tty_config: io.tty.Config,
407) !void {381) !void {
408 _ = allocator;382 _ = allocator;
409 if (builtin.strip_debug_info) return error.MissingDebugInfo;383 if (builtin.strip_debug_info) return error.MissingDebugInfo;
...@@ -562,7 +536,7 @@ pub const StackIterator = struct {...@@ -562,7 +536,7 @@ pub const StackIterator = struct {
562pub fn writeCurrentStackTrace(536pub fn writeCurrentStackTrace(
563 out_stream: anytype,537 out_stream: anytype,
564 debug_info: *DebugInfo,538 debug_info: *DebugInfo,
565 tty_config: TTY.Config,539 tty_config: io.tty.Config,
566 start_addr: ?usize,540 start_addr: ?usize,
567) !void {541) !void {
568 if (native_os == .windows) {542 if (native_os == .windows) {
...@@ -634,7 +608,7 @@ pub noinline fn walkStackWindows(addresses: []usize) usize {...@@ -634,7 +608,7 @@ pub noinline fn walkStackWindows(addresses: []usize) usize {
634pub fn writeCurrentStackTraceWindows(608pub fn writeCurrentStackTraceWindows(
635 out_stream: anytype,609 out_stream: anytype,
636 debug_info: *DebugInfo,610 debug_info: *DebugInfo,
637 tty_config: TTY.Config,611 tty_config: io.tty.Config,
638 start_addr: ?usize,612 start_addr: ?usize,
639) !void {613) !void {
640 var addr_buf: [1024]usize = undefined;614 var addr_buf: [1024]usize = undefined;
...@@ -651,95 +625,6 @@ pub fn writeCurrentStackTraceWindows(...@@ -651,95 +625,6 @@ pub fn writeCurrentStackTraceWindows(
651 }625 }
652}626}
653627
654/// Provides simple functionality for manipulating the terminal in some way,
655/// for debugging purposes, such as coloring text, etc.
656pub const TTY = struct {
657 pub const Color = enum {
658 red,
659 green,
660 yellow,
661 cyan,
662 white,
663 dim,
664 bold,
665 reset,
666 };
667
668 pub const Config = union(enum) {
669 no_color,
670 escape_codes,
671 windows_api: if (native_os == .windows) WindowsContext else void,
672
673 pub const WindowsContext = struct {
674 handle: File.Handle,
675 reset_attributes: u16,
676 };
677
678 pub fn setColor(conf: Config, out_stream: anytype, color: Color) !void {
679 nosuspend switch (conf) {
680 .no_color => return,
681 .escape_codes => {
682 const color_string = switch (color) {
683 .red => "\x1b[31;1m",
684 .green => "\x1b[32;1m",
685 .yellow => "\x1b[33;1m",
686 .cyan => "\x1b[36;1m",
687 .white => "\x1b[37;1m",
688 .bold => "\x1b[1m",
689 .dim => "\x1b[2m",
690 .reset => "\x1b[0m",
691 };
692 try out_stream.writeAll(color_string);
693 },
694 .windows_api => |ctx| if (native_os == .windows) {
695 const attributes = switch (color) {
696 .red => windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY,
697 .green => windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY,
698 .yellow => windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY,
699 .cyan => windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
700 .white, .bold => windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
701 .dim => windows.FOREGROUND_INTENSITY,
702 .reset => ctx.reset_attributes,
703 };
704 try windows.SetConsoleTextAttribute(ctx.handle, attributes);
705 } else {
706 unreachable;
707 },
708 };
709 }
710
711 pub fn writeDEC(conf: Config, writer: anytype, codepoint: u8) !void {
712 const bytes = switch (conf) {
713 .no_color, .windows_api => switch (codepoint) {
714 0x50...0x5e => @as(*const [1]u8, &codepoint),
715 0x6a => "+", // ┘
716 0x6b => "+", // ┐
717 0x6c => "+", // ┌
718 0x6d => "+", // └
719 0x6e => "+", // ┼
720 0x71 => "-", // ─
721 0x74 => "+", // ├
722 0x75 => "+", // ┤
723 0x76 => "+", // ┴
724 0x77 => "+", // ┬
725 0x78 => "|", // │
726 else => " ", // TODO
727 },
728 .escape_codes => switch (codepoint) {
729 // Here we avoid writing the DEC beginning sequence and
730 // ending sequence in separate syscalls by putting the
731 // beginning and ending sequence into the same string
732 // literals, to prevent terminals ending up in bad states
733 // in case a crash happens between syscalls.
734 inline 0x50...0x7f => |x| "\x1B\x28\x30" ++ [1]u8{x} ++ "\x1B\x28\x42",
735 else => unreachable,
736 },
737 };
738 return writer.writeAll(bytes);
739 }
740 };
741};
742
743fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {628fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {
744 var min: usize = 0;629 var min: usize = 0;
745 var max: usize = symbols.len - 1;630 var max: usize = symbols.len - 1;
...@@ -785,7 +670,7 @@ test "machoSearchSymbols" {...@@ -785,7 +670,7 @@ test "machoSearchSymbols" {
785 try testing.expectEqual(&symbols[2], machoSearchSymbols(&symbols, 5000).?);670 try testing.expectEqual(&symbols[2], machoSearchSymbols(&symbols, 5000).?);
786}671}
787672
788fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: TTY.Config) !void {673fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
789 const module_name = debug_info.getModuleNameForAddress(address);674 const module_name = debug_info.getModuleNameForAddress(address);
790 return printLineInfo(675 return printLineInfo(
791 out_stream,676 out_stream,
...@@ -798,7 +683,7 @@ fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usiz...@@ -798,7 +683,7 @@ fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usiz
798 );683 );
799}684}
800685
801pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: TTY.Config) !void {686pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
802 const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {687 const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
803 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),688 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
804 else => return err,689 else => return err,
...@@ -827,7 +712,7 @@ fn printLineInfo(...@@ -827,7 +712,7 @@ fn printLineInfo(
827 address: usize,712 address: usize,
828 symbol_name: []const u8,713 symbol_name: []const u8,
829 compile_unit_name: []const u8,714 compile_unit_name: []const u8,
830 tty_config: TTY.Config,715 tty_config: io.tty.Config,
831 comptime printLineFromFile: anytype,716 comptime printLineFromFile: anytype,
832) !void {717) !void {
833 nosuspend {718 nosuspend {
...@@ -2193,7 +2078,7 @@ test "manage resources correctly" {...@@ -2193,7 +2078,7 @@ test "manage resources correctly" {
2193 const writer = std.io.null_writer;2078 const writer = std.io.null_writer;
2194 var di = try openSelfDebugInfo(testing.allocator);2079 var di = try openSelfDebugInfo(testing.allocator);
2195 defer di.deinit();2080 defer di.deinit();
2196 try printSourceAtAddress(&di, writer, showMyTrace(), detectTTYConfig(std.io.getStdErr()));2081 try printSourceAtAddress(&di, writer, showMyTrace(), io.tty.detectConfig(std.io.getStdErr()));
2197}2082}
21982083
2199noinline fn showMyTrace() usize {2084noinline fn showMyTrace() usize {
...@@ -2253,7 +2138,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize...@@ -2253,7 +2138,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
2253 pub fn dump(t: @This()) void {2138 pub fn dump(t: @This()) void {
2254 if (!enabled) return;2139 if (!enabled) return;
22552140
2256 const tty_config = detectTTYConfig(std.io.getStdErr());2141 const tty_config = io.tty.detectConfig(std.io.getStdErr());
2257 const stderr = io.getStdErr().writer();2142 const stderr = io.getStdErr().writer();
2258 const end = @min(t.index, size);2143 const end = @min(t.index, size);
2259 const debug_info = getSelfDebugInfo() catch |err| {2144 const debug_info = getSelfDebugInfo() catch |err| {
lib/std/io.zig+2
...@@ -155,6 +155,8 @@ pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAt...@@ -155,6 +155,8 @@ pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAt
155155
156pub const StreamSource = @import("io/stream_source.zig").StreamSource;156pub const StreamSource = @import("io/stream_source.zig").StreamSource;
157157
158pub const tty = @import("io/tty.zig");
159
158/// A Writer that doesn't write to anything.160/// A Writer that doesn't write to anything.
159pub const null_writer = @as(NullWriter, .{ .context = {} });161pub const null_writer = @as(NullWriter, .{ .context = {} });
160162
lib/std/io/tty.zig created+121
...@@ -0,0 +1,121 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const File = std.fs.File;
4const process = std.process;
5const windows = std.os.windows;
6const native_os = builtin.os.tag;
7
8/// Detect suitable TTY configuration options for the given file (commonly stdout/stderr).
9/// This includes feature checks for ANSI escape codes and the Windows console API, as well as
10/// respecting the `NO_COLOR` environment variable.
11pub fn detectConfig(file: File) Config {
12 if (builtin.os.tag == .wasi) {
13 // Per https://github.com/WebAssembly/WASI/issues/162 ANSI codes
14 // aren't currently supported.
15 return .no_color;
16 } else if (process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) {
17 return .escape_codes;
18 } else if (process.hasEnvVarConstant("NO_COLOR")) {
19 return .no_color;
20 } else if (file.supportsAnsiEscapeCodes()) {
21 return .escape_codes;
22 } else if (native_os == .windows and file.isTty()) {
23 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
24 if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) {
25 // TODO: Should this return an error instead?
26 return .no_color;
27 }
28 return .{ .windows_api = .{
29 .handle = file.handle,
30 .reset_attributes = info.wAttributes,
31 } };
32 }
33 return .no_color;
34}
35
36pub const Color = enum {
37 red,
38 green,
39 yellow,
40 cyan,
41 white,
42 dim,
43 bold,
44 reset,
45};
46
47/// Provides simple functionality for manipulating the terminal in some way,
48/// such as coloring text, etc.
49pub const Config = union(enum) {
50 no_color,
51 escape_codes,
52 windows_api: if (native_os == .windows) WindowsContext else void,
53
54 pub const WindowsContext = struct {
55 handle: File.Handle,
56 reset_attributes: u16,
57 };
58
59 pub fn setColor(conf: Config, out_stream: anytype, color: Color) !void {
60 nosuspend switch (conf) {
61 .no_color => return,
62 .escape_codes => {
63 const color_string = switch (color) {
64 .red => "\x1b[31;1m",
65 .green => "\x1b[32;1m",
66 .yellow => "\x1b[33;1m",
67 .cyan => "\x1b[36;1m",
68 .white => "\x1b[37;1m",
69 .bold => "\x1b[1m",
70 .dim => "\x1b[2m",
71 .reset => "\x1b[0m",
72 };
73 try out_stream.writeAll(color_string);
74 },
75 .windows_api => |ctx| if (native_os == .windows) {
76 const attributes = switch (color) {
77 .red => windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY,
78 .green => windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY,
79 .yellow => windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY,
80 .cyan => windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
81 .white, .bold => windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
82 .dim => windows.FOREGROUND_INTENSITY,
83 .reset => ctx.reset_attributes,
84 };
85 try windows.SetConsoleTextAttribute(ctx.handle, attributes);
86 } else {
87 unreachable;
88 },
89 };
90 }
91
92 pub fn writeDEC(conf: Config, writer: anytype, codepoint: u8) !void {
93 const bytes = switch (conf) {
94 .no_color, .windows_api => switch (codepoint) {
95 0x50...0x5e => @as(*const [1]u8, &codepoint),
96 0x6a => "+", // ┘
97 0x6b => "+", // ┐
98 0x6c => "+", // ┌
99 0x6d => "+", // └
100 0x6e => "+", // ┼
101 0x71 => "-", // ─
102 0x74 => "+", // ├
103 0x75 => "+", // ┤
104 0x76 => "+", // ┴
105 0x77 => "+", // ┬
106 0x78 => "|", // │
107 else => " ", // TODO
108 },
109 .escape_codes => switch (codepoint) {
110 // Here we avoid writing the DEC beginning sequence and
111 // ending sequence in separate syscalls by putting the
112 // beginning and ending sequence into the same string
113 // literals, to prevent terminals ending up in bad states
114 // in case a crash happens between syscalls.
115 inline 0x50...0x7f => |x| "\x1B\x28\x30" ++ [1]u8{x} ++ "\x1B\x28\x42",
116 else => unreachable,
117 },
118 };
119 return writer.writeAll(bytes);
120 }
121};
lib/std/testing.zig+4-4
...@@ -279,7 +279,7 @@ test "expectApproxEqRel" {...@@ -279,7 +279,7 @@ test "expectApproxEqRel" {
279/// This function is intended to be used only in tests. When the two slices are not279/// This function is intended to be used only in tests. When the two slices are not
280/// equal, prints diagnostics to stderr to show exactly how they are not equal (with280/// equal, prints diagnostics to stderr to show exactly how they are not equal (with
281/// the differences highlighted in red), then returns a test failure error.281/// the differences highlighted in red), then returns a test failure error.
282/// The colorized output is optional and controlled by the return of `std.debug.detectTTYConfig()`.282/// The colorized output is optional and controlled by the return of `std.io.tty.detectConfig()`.
283/// If your inputs are UTF-8 encoded strings, consider calling `expectEqualStrings` instead.283/// If your inputs are UTF-8 encoded strings, consider calling `expectEqualStrings` instead.
284pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) !void {284pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) !void {
285 if (expected.ptr == actual.ptr and expected.len == actual.len) {285 if (expected.ptr == actual.ptr and expected.len == actual.len) {
...@@ -312,7 +312,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const...@@ -312,7 +312,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
312 const actual_window = actual[window_start..@min(actual.len, window_start + max_window_size)];312 const actual_window = actual[window_start..@min(actual.len, window_start + max_window_size)];
313 const actual_truncated = window_start + actual_window.len < actual.len;313 const actual_truncated = window_start + actual_window.len < actual.len;
314314
315 const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());315 const ttyconf = std.io.tty.detectConfig(std.io.getStdErr());
316 var differ = if (T == u8) BytesDiffer{316 var differ = if (T == u8) BytesDiffer{
317 .expected = expected_window,317 .expected = expected_window,
318 .actual = actual_window,318 .actual = actual_window,
...@@ -379,7 +379,7 @@ fn SliceDiffer(comptime T: type) type {...@@ -379,7 +379,7 @@ fn SliceDiffer(comptime T: type) type {
379 start_index: usize,379 start_index: usize,
380 expected: []const T,380 expected: []const T,
381 actual: []const T,381 actual: []const T,
382 ttyconf: std.debug.TTY.Config,382 ttyconf: std.io.tty.Config,
383383
384 const Self = @This();384 const Self = @This();
385385
...@@ -398,7 +398,7 @@ fn SliceDiffer(comptime T: type) type {...@@ -398,7 +398,7 @@ fn SliceDiffer(comptime T: type) type {
398const BytesDiffer = struct {398const BytesDiffer = struct {
399 expected: []const u8,399 expected: []const u8,
400 actual: []const u8,400 actual: []const u8,
401 ttyconf: std.debug.TTY.Config,401 ttyconf: std.io.tty.Config,
402402
403 pub fn write(self: BytesDiffer, writer: anytype) !void {403 pub fn write(self: BytesDiffer, writer: anytype) !void {
404 var expected_iterator = ChunkIterator{ .bytes = self.expected };404 var expected_iterator = ChunkIterator{ .bytes = self.expected };
lib/std/zig/ErrorBundle.zig+2-2
...@@ -148,7 +148,7 @@ pub fn nullTerminatedString(eb: ErrorBundle, index: usize) [:0]const u8 {...@@ -148,7 +148,7 @@ pub fn nullTerminatedString(eb: ErrorBundle, index: usize) [:0]const u8 {
148}148}
149149
150pub const RenderOptions = struct {150pub const RenderOptions = struct {
151 ttyconf: std.debug.TTY.Config,151 ttyconf: std.io.tty.Config,
152 include_reference_trace: bool = true,152 include_reference_trace: bool = true,
153 include_source_line: bool = true,153 include_source_line: bool = true,
154 include_log_text: bool = true,154 include_log_text: bool = true,
...@@ -181,7 +181,7 @@ fn renderErrorMessageToWriter(...@@ -181,7 +181,7 @@ fn renderErrorMessageToWriter(
181 err_msg_index: MessageIndex,181 err_msg_index: MessageIndex,
182 stderr: anytype,182 stderr: anytype,
183 kind: []const u8,183 kind: []const u8,
184 color: std.debug.TTY.Color,184 color: std.io.tty.Color,
185 indent: usize,185 indent: usize,
186) anyerror!void {186) anyerror!void {
187 const ttyconf = options.ttyconf;187 const ttyconf = options.ttyconf;
src/main.zig+2-2
...@@ -6044,9 +6044,9 @@ const ClangSearchSanitizer = struct {...@@ -6044,9 +6044,9 @@ const ClangSearchSanitizer = struct {
6044 };6044 };
6045};6045};
60466046
6047fn get_tty_conf(color: Color) std.debug.TTY.Config {6047fn get_tty_conf(color: Color) std.io.tty.Config {
6048 return switch (color) {6048 return switch (color) {
6049 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),6049 .auto => std.io.tty.detectConfig(std.io.getStdErr()),
6050 .on => .escape_codes,6050 .on => .escape_codes,
6051 .off => .no_color,6051 .off => .no_color,
6052 };6052 };
test/src/Cases.zig+1-1
...@@ -1354,7 +1354,7 @@ fn runOneCase(...@@ -1354,7 +1354,7 @@ fn runOneCase(
1354 defer all_errors.deinit(allocator);1354 defer all_errors.deinit(allocator);
1355 if (all_errors.errorMessageCount() > 0) {1355 if (all_errors.errorMessageCount() > 0) {
1356 all_errors.renderToStdErr(.{1356 all_errors.renderToStdErr(.{
1357 .ttyconf = std.debug.detectTTYConfig(std.io.getStdErr()),1357 .ttyconf = std.io.tty.detectConfig(std.io.getStdErr()),
1358 });1358 });
1359 // TODO print generated C code1359 // TODO print generated C code
1360 return error.UnexpectedCompileErrors;1360 return error.UnexpectedCompileErrors;