authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-05-24 16:03:44+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-05-24 16:03:44+03:00
log7cb2e653a20698b4b8050705bcb72afeea9df63b
treee8d6161a0258448cd6fcb6bad9f81fc31ad56c8a
parentb2a514b3d2d2d880a41a26e798fb3c9ee014c229
parent93d9c9bf319e78045c70d1e6260b15e3319c82b9
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15806 from linusg/std-io-tty

std: Move TTY from std.debug to std.io and add missing colors

11 files changed, 221 insertions(+), 208 deletions(-)

lib/build_runner.zig+36-36
...@@ -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
...@@ -476,9 +476,9 @@ fn runStepNames(...@@ -476,9 +476,9 @@ fn runStepNames(
476476
477 if (run.enable_summary != false) {477 if (run.enable_summary != false) {
478 const total_count = success_count + failure_count + pending_count + skipped_count;478 const total_count = success_count + failure_count + pending_count + skipped_count;
479 ttyconf.setColor(stderr, .Cyan) catch {};479 ttyconf.setColor(stderr, .cyan) catch {};
480 stderr.writeAll("Build Summary:") catch {};480 stderr.writeAll("Build Summary:") catch {};
481 ttyconf.setColor(stderr, .Reset) catch {};481 ttyconf.setColor(stderr, .reset) catch {};
482 stderr.writer().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};482 stderr.writer().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
483 if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {};483 if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {};
484 if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {};484 if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {};
...@@ -489,9 +489,9 @@ fn runStepNames(...@@ -489,9 +489,9 @@ fn runStepNames(
489 if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_count}) catch {};489 if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_count}) catch {};
490490
491 if (run.enable_summary == null) {491 if (run.enable_summary == null) {
492 ttyconf.setColor(stderr, .Dim) catch {};492 ttyconf.setColor(stderr, .dim) catch {};
493 stderr.writeAll(" (disable with -fno-summary)") catch {};493 stderr.writeAll(" (disable with -fno-summary)") catch {};
494 ttyconf.setColor(stderr, .Reset) catch {};494 ttyconf.setColor(stderr, .reset) catch {};
495 }495 }
496 stderr.writeAll("\n") catch {};496 stderr.writeAll("\n") catch {};
497497
...@@ -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,14 +553,14 @@ fn printTreeStep(...@@ -553,14 +553,14 @@ 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 {
560 const first = step_stack.swapRemove(s);560 const first = step_stack.swapRemove(s);
561 try printPrefix(parent_node, stderr, ttyconf);561 try printPrefix(parent_node, stderr, ttyconf);
562562
563 if (!first) try ttyconf.setColor(stderr, .Dim);563 if (!first) try ttyconf.setColor(stderr, .dim);
564 if (parent_node.parent != null) {564 if (parent_node.parent != null) {
565 if (parent_node.last) {565 if (parent_node.last) {
566 try stderr.writeAll(switch (ttyconf) {566 try stderr.writeAll(switch (ttyconf) {
...@@ -586,28 +586,28 @@ fn printTreeStep(...@@ -586,28 +586,28 @@ fn printTreeStep(
586 .running => unreachable,586 .running => unreachable,
587587
588 .dependency_failure => {588 .dependency_failure => {
589 try ttyconf.setColor(stderr, .Dim);589 try ttyconf.setColor(stderr, .dim);
590 try stderr.writeAll(" transitive failure\n");590 try stderr.writeAll(" transitive failure\n");
591 try ttyconf.setColor(stderr, .Reset);591 try ttyconf.setColor(stderr, .reset);
592 },592 },
593593
594 .success => {594 .success => {
595 try ttyconf.setColor(stderr, .Green);595 try ttyconf.setColor(stderr, .green);
596 if (s.result_cached) {596 if (s.result_cached) {
597 try stderr.writeAll(" cached");597 try stderr.writeAll(" cached");
598 } else if (s.test_results.test_count > 0) {598 } else if (s.test_results.test_count > 0) {
599 const pass_count = s.test_results.passCount();599 const pass_count = s.test_results.passCount();
600 try stderr.writer().print(" {d} passed", .{pass_count});600 try stderr.writer().print(" {d} passed", .{pass_count});
601 if (s.test_results.skip_count > 0) {601 if (s.test_results.skip_count > 0) {
602 try ttyconf.setColor(stderr, .Yellow);602 try ttyconf.setColor(stderr, .yellow);
603 try stderr.writer().print(" {d} skipped", .{s.test_results.skip_count});603 try stderr.writer().print(" {d} skipped", .{s.test_results.skip_count});
604 }604 }
605 } else {605 } else {
606 try stderr.writeAll(" success");606 try stderr.writeAll(" success");
607 }607 }
608 try ttyconf.setColor(stderr, .Reset);608 try ttyconf.setColor(stderr, .reset);
609 if (s.result_duration_ns) |ns| {609 if (s.result_duration_ns) |ns| {
610 try ttyconf.setColor(stderr, .Dim);610 try ttyconf.setColor(stderr, .dim);
611 if (ns >= std.time.ns_per_min) {611 if (ns >= std.time.ns_per_min) {
612 try stderr.writer().print(" {d}m", .{ns / std.time.ns_per_min});612 try stderr.writer().print(" {d}m", .{ns / std.time.ns_per_min});
613 } else if (ns >= std.time.ns_per_s) {613 } else if (ns >= std.time.ns_per_s) {
...@@ -619,11 +619,11 @@ fn printTreeStep(...@@ -619,11 +619,11 @@ fn printTreeStep(
619 } else {619 } else {
620 try stderr.writer().print(" {d}ns", .{ns});620 try stderr.writer().print(" {d}ns", .{ns});
621 }621 }
622 try ttyconf.setColor(stderr, .Reset);622 try ttyconf.setColor(stderr, .reset);
623 }623 }
624 if (s.result_peak_rss != 0) {624 if (s.result_peak_rss != 0) {
625 const rss = s.result_peak_rss;625 const rss = s.result_peak_rss;
626 try ttyconf.setColor(stderr, .Dim);626 try ttyconf.setColor(stderr, .dim);
627 if (rss >= 1000_000_000) {627 if (rss >= 1000_000_000) {
628 try stderr.writer().print(" MaxRSS:{d}G", .{rss / 1000_000_000});628 try stderr.writer().print(" MaxRSS:{d}G", .{rss / 1000_000_000});
629 } else if (rss >= 1000_000) {629 } else if (rss >= 1000_000) {
...@@ -633,57 +633,57 @@ fn printTreeStep(...@@ -633,57 +633,57 @@ fn printTreeStep(
633 } else {633 } else {
634 try stderr.writer().print(" MaxRSS:{d}B", .{rss});634 try stderr.writer().print(" MaxRSS:{d}B", .{rss});
635 }635 }
636 try ttyconf.setColor(stderr, .Reset);636 try ttyconf.setColor(stderr, .reset);
637 }637 }
638 try stderr.writeAll("\n");638 try stderr.writeAll("\n");
639 },639 },
640640
641 .skipped => {641 .skipped => {
642 try ttyconf.setColor(stderr, .Yellow);642 try ttyconf.setColor(stderr, .yellow);
643 try stderr.writeAll(" skipped\n");643 try stderr.writeAll(" skipped\n");
644 try ttyconf.setColor(stderr, .Reset);644 try ttyconf.setColor(stderr, .reset);
645 },645 },
646646
647 .failure => {647 .failure => {
648 if (s.result_error_bundle.errorMessageCount() > 0) {648 if (s.result_error_bundle.errorMessageCount() > 0) {
649 try ttyconf.setColor(stderr, .Red);649 try ttyconf.setColor(stderr, .red);
650 try stderr.writer().print(" {d} errors\n", .{650 try stderr.writer().print(" {d} errors\n", .{
651 s.result_error_bundle.errorMessageCount(),651 s.result_error_bundle.errorMessageCount(),
652 });652 });
653 try ttyconf.setColor(stderr, .Reset);653 try ttyconf.setColor(stderr, .reset);
654 } else if (!s.test_results.isSuccess()) {654 } else if (!s.test_results.isSuccess()) {
655 try stderr.writer().print(" {d}/{d} passed", .{655 try stderr.writer().print(" {d}/{d} passed", .{
656 s.test_results.passCount(), s.test_results.test_count,656 s.test_results.passCount(), s.test_results.test_count,
657 });657 });
658 if (s.test_results.fail_count > 0) {658 if (s.test_results.fail_count > 0) {
659 try stderr.writeAll(", ");659 try stderr.writeAll(", ");
660 try ttyconf.setColor(stderr, .Red);660 try ttyconf.setColor(stderr, .red);
661 try stderr.writer().print("{d} failed", .{661 try stderr.writer().print("{d} failed", .{
662 s.test_results.fail_count,662 s.test_results.fail_count,
663 });663 });
664 try ttyconf.setColor(stderr, .Reset);664 try ttyconf.setColor(stderr, .reset);
665 }665 }
666 if (s.test_results.skip_count > 0) {666 if (s.test_results.skip_count > 0) {
667 try stderr.writeAll(", ");667 try stderr.writeAll(", ");
668 try ttyconf.setColor(stderr, .Yellow);668 try ttyconf.setColor(stderr, .yellow);
669 try stderr.writer().print("{d} skipped", .{669 try stderr.writer().print("{d} skipped", .{
670 s.test_results.skip_count,670 s.test_results.skip_count,
671 });671 });
672 try ttyconf.setColor(stderr, .Reset);672 try ttyconf.setColor(stderr, .reset);
673 }673 }
674 if (s.test_results.leak_count > 0) {674 if (s.test_results.leak_count > 0) {
675 try stderr.writeAll(", ");675 try stderr.writeAll(", ");
676 try ttyconf.setColor(stderr, .Red);676 try ttyconf.setColor(stderr, .red);
677 try stderr.writer().print("{d} leaked", .{677 try stderr.writer().print("{d} leaked", .{
678 s.test_results.leak_count,678 s.test_results.leak_count,
679 });679 });
680 try ttyconf.setColor(stderr, .Reset);680 try ttyconf.setColor(stderr, .reset);
681 }681 }
682 try stderr.writeAll("\n");682 try stderr.writeAll("\n");
683 } else {683 } else {
684 try ttyconf.setColor(stderr, .Red);684 try ttyconf.setColor(stderr, .red);
685 try stderr.writeAll(" failure\n");685 try stderr.writeAll(" failure\n");
686 try ttyconf.setColor(stderr, .Reset);686 try ttyconf.setColor(stderr, .reset);
687 }687 }
688 },688 },
689 }689 }
...@@ -703,7 +703,7 @@ fn printTreeStep(...@@ -703,7 +703,7 @@ fn printTreeStep(
703 s.dependencies.items.len,703 s.dependencies.items.len,
704 });704 });
705 }705 }
706 try ttyconf.setColor(stderr, .Reset);706 try ttyconf.setColor(stderr, .reset);
707 }707 }
708}708}
709709
...@@ -819,13 +819,13 @@ fn workerMakeOneStep(...@@ -819,13 +819,13 @@ fn workerMakeOneStep(
819 for (s.result_error_msgs.items) |msg| {819 for (s.result_error_msgs.items) |msg| {
820 // Sometimes it feels like you just can't catch a break. Finally,820 // Sometimes it feels like you just can't catch a break. Finally,
821 // with Zig, you can.821 // with Zig, you can.
822 ttyconf.setColor(stderr, .Bold) catch break;822 ttyconf.setColor(stderr, .bold) catch break;
823 stderr.writeAll(s.owner.dep_prefix) catch break;823 stderr.writeAll(s.owner.dep_prefix) catch break;
824 stderr.writeAll(s.name) catch break;824 stderr.writeAll(s.name) catch break;
825 stderr.writeAll(": ") catch break;825 stderr.writeAll(": ") catch break;
826 ttyconf.setColor(stderr, .Red) catch break;826 ttyconf.setColor(stderr, .red) catch break;
827 stderr.writeAll("error: ") catch break;827 stderr.writeAll("error: ") catch break;
828 ttyconf.setColor(stderr, .Reset) catch break;828 ttyconf.setColor(stderr, .reset) catch break;
829 stderr.writeAll(msg) catch break;829 stderr.writeAll(msg) catch break;
830 stderr.writeAll("\n") catch break;830 stderr.writeAll("\n") catch break;
831 }831 }
...@@ -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+7-7
...@@ -1712,10 +1712,10 @@ fn dumpBadGetPathHelp(...@@ -1712,10 +1712,10 @@ 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 {};
17191719
1720 const debug_info = std.debug.getSelfDebugInfo() catch |err| {1720 const debug_info = std.debug.getSelfDebugInfo() catch |err| {
1721 try w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)});1721 try w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)});
...@@ -1727,9 +1727,9 @@ fn dumpBadGetPathHelp(...@@ -1727,9 +1727,9 @@ fn dumpBadGetPathHelp(
1727 return;1727 return;
1728 };1728 };
1729 if (asking_step) |as| {1729 if (asking_step) |as| {
1730 tty_config.setColor(w, .Red) catch {};1730 tty_config.setColor(w, .red) catch {};
1731 try stderr.writeAll(" The step that is missing a dependency on the above step was created by this stack trace:\n");1731 try stderr.writeAll(" The step that is missing a dependency on the above step was created by this stack trace:\n");
1732 tty_config.setColor(w, .Reset) catch {};1732 tty_config.setColor(w, .reset) catch {};
17331733
1734 std.debug.writeStackTrace(as.getStackTrace(), w, ally, debug_info, tty_config) catch |err| {1734 std.debug.writeStackTrace(as.getStackTrace(), w, ally, debug_info, tty_config) catch |err| {
1735 try stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)});1735 try stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)});
...@@ -1737,9 +1737,9 @@ fn dumpBadGetPathHelp(...@@ -1737,9 +1737,9 @@ fn dumpBadGetPathHelp(
1737 };1737 };
1738 }1738 }
17391739
1740 tty_config.setColor(w, .Red) catch {};1740 tty_config.setColor(w, .red) catch {};
1741 try stderr.writeAll(" Hope that helps. Proceeding to panic.\n");1741 try stderr.writeAll(" Hope that helps. Proceeding to panic.\n");
1742 tty_config.setColor(w, .Reset) catch {};1742 tty_config.setColor(w, .reset) catch {};
1743}1743}
17441744
1745/// Allocates a new string for assigning a value to a named macro.1745/// Allocates a new string for assigning a value to a named macro.
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+19-134
...@@ -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;
...@@ -421,9 +395,9 @@ pub fn writeStackTrace(...@@ -421,9 +395,9 @@ pub fn writeStackTrace(
421 if (stack_trace.index > stack_trace.instruction_addresses.len) {395 if (stack_trace.index > stack_trace.instruction_addresses.len) {
422 const dropped_frames = stack_trace.index - stack_trace.instruction_addresses.len;396 const dropped_frames = stack_trace.index - stack_trace.instruction_addresses.len;
423397
424 tty_config.setColor(out_stream, .Bold) catch {};398 tty_config.setColor(out_stream, .bold) catch {};
425 try out_stream.print("({d} additional stack frames skipped...)\n", .{dropped_frames});399 try out_stream.print("({d} additional stack frames skipped...)\n", .{dropped_frames});
426 tty_config.setColor(out_stream, .Reset) catch {};400 tty_config.setColor(out_stream, .reset) catch {};
427 }401 }
428}402}
429403
...@@ -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,11 +712,11 @@ fn printLineInfo(...@@ -827,11 +712,11 @@ 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 {
834 try tty_config.setColor(out_stream, .Bold);719 try tty_config.setColor(out_stream, .bold);
835720
836 if (line_info) |*li| {721 if (line_info) |*li| {
837 try out_stream.print("{s}:{d}:{d}", .{ li.file_name, li.line, li.column });722 try out_stream.print("{s}:{d}:{d}", .{ li.file_name, li.line, li.column });
...@@ -839,11 +724,11 @@ fn printLineInfo(...@@ -839,11 +724,11 @@ fn printLineInfo(
839 try out_stream.writeAll("???:?:?");724 try out_stream.writeAll("???:?:?");
840 }725 }
841726
842 try tty_config.setColor(out_stream, .Reset);727 try tty_config.setColor(out_stream, .reset);
843 try out_stream.writeAll(": ");728 try out_stream.writeAll(": ");
844 try tty_config.setColor(out_stream, .Dim);729 try tty_config.setColor(out_stream, .dim);
845 try out_stream.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name });730 try out_stream.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name });
846 try tty_config.setColor(out_stream, .Reset);731 try tty_config.setColor(out_stream, .reset);
847 try out_stream.writeAll("\n");732 try out_stream.writeAll("\n");
848733
849 // Show the matching source code line if possible734 // Show the matching source code line if possible
...@@ -854,9 +739,9 @@ fn printLineInfo(...@@ -854,9 +739,9 @@ fn printLineInfo(
854 const space_needed = @intCast(usize, li.column - 1);739 const space_needed = @intCast(usize, li.column - 1);
855740
856 try out_stream.writeByteNTimes(' ', space_needed);741 try out_stream.writeByteNTimes(' ', space_needed);
857 try tty_config.setColor(out_stream, .Green);742 try tty_config.setColor(out_stream, .green);
858 try out_stream.writeAll("^");743 try out_stream.writeAll("^");
859 try tty_config.setColor(out_stream, .Reset);744 try tty_config.setColor(out_stream, .reset);
860 }745 }
861 try out_stream.writeAll("\n");746 try out_stream.writeAll("\n");
862 } else |err| switch (err) {747 } else |err| switch (err) {
...@@ -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+126
...@@ -0,0 +1,126 @@
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 black,
38 red,
39 green,
40 yellow,
41 blue,
42 magenta,
43 cyan,
44 white,
45 bright_black,
46 bright_red,
47 bright_green,
48 bright_yellow,
49 bright_blue,
50 bright_magenta,
51 bright_cyan,
52 bright_white,
53 dim,
54 bold,
55 reset,
56};
57
58/// Provides simple functionality for manipulating the terminal in some way,
59/// such as coloring text, etc.
60pub const Config = union(enum) {
61 no_color,
62 escape_codes,
63 windows_api: if (native_os == .windows) WindowsContext else void,
64
65 pub const WindowsContext = struct {
66 handle: File.Handle,
67 reset_attributes: u16,
68 };
69
70 pub fn setColor(conf: Config, out_stream: anytype, color: Color) !void {
71 nosuspend switch (conf) {
72 .no_color => return,
73 .escape_codes => {
74 const color_string = switch (color) {
75 .black => "\x1b[30m",
76 .red => "\x1b[31m",
77 .green => "\x1b[32m",
78 .yellow => "\x1b[33m",
79 .blue => "\x1b[34m",
80 .magenta => "\x1b[35m",
81 .cyan => "\x1b[36m",
82 .white => "\x1b[37m",
83 .bright_black => "\x1b[90m",
84 .bright_red => "\x1b[91m",
85 .bright_green => "\x1b[92m",
86 .bright_yellow => "\x1b[93m",
87 .bright_blue => "\x1b[94m",
88 .bright_magenta => "\x1b[95m",
89 .bright_cyan => "\x1b[96m",
90 .bright_white => "\x1b[97m",
91 .bold => "\x1b[1m",
92 .dim => "\x1b[2m",
93 .reset => "\x1b[0m",
94 };
95 try out_stream.writeAll(color_string);
96 },
97 .windows_api => |ctx| if (native_os == .windows) {
98 const attributes = switch (color) {
99 .black => 0,
100 .red => windows.FOREGROUND_RED,
101 .green => windows.FOREGROUND_GREEN,
102 .yellow => windows.FOREGROUND_RED | windows.FOREGROUND_GREEN,
103 .blue => windows.FOREGROUND_BLUE,
104 .magenta => windows.FOREGROUND_RED | windows.FOREGROUND_BLUE,
105 .cyan => windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE,
106 .white => windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE,
107 .bright_black => windows.FOREGROUND_INTENSITY,
108 .bright_red => windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY,
109 .bright_green => windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY,
110 .bright_yellow => windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY,
111 .bright_blue => windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
112 .bright_magenta => windows.FOREGROUND_RED | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
113 .bright_cyan => windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
114 .bright_white, .bold => windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
115 // "dim" is not supported using basic character attributes, but let's still make it do *something*.
116 // This matches the old behavior of TTY.Color before the bright variants were added.
117 .dim => windows.FOREGROUND_INTENSITY,
118 .reset => ctx.reset_attributes,
119 };
120 try windows.SetConsoleTextAttribute(ctx.handle, attributes);
121 } else {
122 unreachable;
123 },
124 };
125 }
126};
lib/std/testing.zig+8-8
...@@ -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
...@@ -387,9 +387,9 @@ fn SliceDiffer(comptime T: type) type {...@@ -387,9 +387,9 @@ fn SliceDiffer(comptime T: type) type {
387 for (self.expected, 0..) |value, i| {387 for (self.expected, 0..) |value, i| {
388 var full_index = self.start_index + i;388 var full_index = self.start_index + i;
389 const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;389 const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;
390 if (diff) try self.ttyconf.setColor(writer, .Red);390 if (diff) try self.ttyconf.setColor(writer, .red);
391 try writer.print("[{}]: {any}\n", .{ full_index, value });391 try writer.print("[{}]: {any}\n", .{ full_index, value });
392 if (diff) try self.ttyconf.setColor(writer, .Reset);392 if (diff) try self.ttyconf.setColor(writer, .reset);
393 }393 }
394 }394 }
395 };395 };
...@@ -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 };
...@@ -427,9 +427,9 @@ const BytesDiffer = struct {...@@ -427,9 +427,9 @@ const BytesDiffer = struct {
427 }427 }
428428
429 fn writeByteDiff(self: BytesDiffer, writer: anytype, comptime fmt: []const u8, byte: u8, diff: bool) !void {429 fn writeByteDiff(self: BytesDiffer, writer: anytype, comptime fmt: []const u8, byte: u8, diff: bool) !void {
430 if (diff) try self.ttyconf.setColor(writer, .Red);430 if (diff) try self.ttyconf.setColor(writer, .red);
431 try writer.print(fmt, .{byte});431 try writer.print(fmt, .{byte});
432 if (diff) try self.ttyconf.setColor(writer, .Reset);432 if (diff) try self.ttyconf.setColor(writer, .reset);
433 }433 }
434434
435 const ChunkIterator = struct {435 const ChunkIterator = struct {
lib/std/zig/ErrorBundle.zig+18-18
...@@ -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,
...@@ -163,7 +163,7 @@ pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void {...@@ -163,7 +163,7 @@ pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void {
163163
164pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, writer: anytype) anyerror!void {164pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, writer: anytype) anyerror!void {
165 for (eb.getMessages()) |err_msg| {165 for (eb.getMessages()) |err_msg| {
166 try renderErrorMessageToWriter(eb, options, err_msg, writer, "error", .Red, 0);166 try renderErrorMessageToWriter(eb, options, err_msg, writer, "error", .red, 0);
167 }167 }
168168
169 if (options.include_log_text) {169 if (options.include_log_text) {
...@@ -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;
...@@ -191,7 +191,7 @@ fn renderErrorMessageToWriter(...@@ -191,7 +191,7 @@ fn renderErrorMessageToWriter(
191 if (err_msg.src_loc != .none) {191 if (err_msg.src_loc != .none) {
192 const src = eb.extraData(SourceLocation, @enumToInt(err_msg.src_loc));192 const src = eb.extraData(SourceLocation, @enumToInt(err_msg.src_loc));
193 try counting_stderr.writeByteNTimes(' ', indent);193 try counting_stderr.writeByteNTimes(' ', indent);
194 try ttyconf.setColor(stderr, .Bold);194 try ttyconf.setColor(stderr, .bold);
195 try counting_stderr.print("{s}:{d}:{d}: ", .{195 try counting_stderr.print("{s}:{d}:{d}: ", .{
196 eb.nullTerminatedString(src.data.src_path),196 eb.nullTerminatedString(src.data.src_path),
197 src.data.line + 1,197 src.data.line + 1,
...@@ -203,17 +203,17 @@ fn renderErrorMessageToWriter(...@@ -203,17 +203,17 @@ fn renderErrorMessageToWriter(
203 // This is the length of the part before the error message:203 // This is the length of the part before the error message:
204 // e.g. "file.zig:4:5: error: "204 // e.g. "file.zig:4:5: error: "
205 const prefix_len = @intCast(usize, counting_stderr.context.bytes_written);205 const prefix_len = @intCast(usize, counting_stderr.context.bytes_written);
206 try ttyconf.setColor(stderr, .Reset);206 try ttyconf.setColor(stderr, .reset);
207 try ttyconf.setColor(stderr, .Bold);207 try ttyconf.setColor(stderr, .bold);
208 if (err_msg.count == 1) {208 if (err_msg.count == 1) {
209 try writeMsg(eb, err_msg, stderr, prefix_len);209 try writeMsg(eb, err_msg, stderr, prefix_len);
210 try stderr.writeByte('\n');210 try stderr.writeByte('\n');
211 } else {211 } else {
212 try writeMsg(eb, err_msg, stderr, prefix_len);212 try writeMsg(eb, err_msg, stderr, prefix_len);
213 try ttyconf.setColor(stderr, .Dim);213 try ttyconf.setColor(stderr, .dim);
214 try stderr.print(" ({d} times)\n", .{err_msg.count});214 try stderr.print(" ({d} times)\n", .{err_msg.count});
215 }215 }
216 try ttyconf.setColor(stderr, .Reset);216 try ttyconf.setColor(stderr, .reset);
217 if (src.data.source_line != 0 and options.include_source_line) {217 if (src.data.source_line != 0 and options.include_source_line) {
218 const line = eb.nullTerminatedString(src.data.source_line);218 const line = eb.nullTerminatedString(src.data.source_line);
219 for (line) |b| switch (b) {219 for (line) |b| switch (b) {
...@@ -226,19 +226,19 @@ fn renderErrorMessageToWriter(...@@ -226,19 +226,19 @@ fn renderErrorMessageToWriter(
226 // -1 since span.main includes the caret226 // -1 since span.main includes the caret
227 const after_caret = src.data.span_end - src.data.span_main -| 1;227 const after_caret = src.data.span_end - src.data.span_main -| 1;
228 try stderr.writeByteNTimes(' ', src.data.column - before_caret);228 try stderr.writeByteNTimes(' ', src.data.column - before_caret);
229 try ttyconf.setColor(stderr, .Green);229 try ttyconf.setColor(stderr, .green);
230 try stderr.writeByteNTimes('~', before_caret);230 try stderr.writeByteNTimes('~', before_caret);
231 try stderr.writeByte('^');231 try stderr.writeByte('^');
232 try stderr.writeByteNTimes('~', after_caret);232 try stderr.writeByteNTimes('~', after_caret);
233 try stderr.writeByte('\n');233 try stderr.writeByte('\n');
234 try ttyconf.setColor(stderr, .Reset);234 try ttyconf.setColor(stderr, .reset);
235 }235 }
236 for (eb.getNotes(err_msg_index)) |note| {236 for (eb.getNotes(err_msg_index)) |note| {
237 try renderErrorMessageToWriter(eb, options, note, stderr, "note", .Cyan, indent);237 try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent);
238 }238 }
239 if (src.data.reference_trace_len > 0 and options.include_reference_trace) {239 if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
240 try ttyconf.setColor(stderr, .Reset);240 try ttyconf.setColor(stderr, .reset);
241 try ttyconf.setColor(stderr, .Dim);241 try ttyconf.setColor(stderr, .dim);
242 try stderr.print("referenced by:\n", .{});242 try stderr.print("referenced by:\n", .{});
243 var ref_index = src.end;243 var ref_index = src.end;
244 for (0..src.data.reference_trace_len) |_| {244 for (0..src.data.reference_trace_len) |_| {
...@@ -266,25 +266,25 @@ fn renderErrorMessageToWriter(...@@ -266,25 +266,25 @@ fn renderErrorMessageToWriter(
266 }266 }
267 }267 }
268 try stderr.writeByte('\n');268 try stderr.writeByte('\n');
269 try ttyconf.setColor(stderr, .Reset);269 try ttyconf.setColor(stderr, .reset);
270 }270 }
271 } else {271 } else {
272 try ttyconf.setColor(stderr, color);272 try ttyconf.setColor(stderr, color);
273 try stderr.writeByteNTimes(' ', indent);273 try stderr.writeByteNTimes(' ', indent);
274 try stderr.writeAll(kind);274 try stderr.writeAll(kind);
275 try stderr.writeAll(": ");275 try stderr.writeAll(": ");
276 try ttyconf.setColor(stderr, .Reset);276 try ttyconf.setColor(stderr, .reset);
277 const msg = eb.nullTerminatedString(err_msg.msg);277 const msg = eb.nullTerminatedString(err_msg.msg);
278 if (err_msg.count == 1) {278 if (err_msg.count == 1) {
279 try stderr.print("{s}\n", .{msg});279 try stderr.print("{s}\n", .{msg});
280 } else {280 } else {
281 try stderr.print("{s}", .{msg});281 try stderr.print("{s}", .{msg});
282 try ttyconf.setColor(stderr, .Dim);282 try ttyconf.setColor(stderr, .dim);
283 try stderr.print(" ({d} times)\n", .{err_msg.count});283 try stderr.print(" ({d} times)\n", .{err_msg.count});
284 }284 }
285 try ttyconf.setColor(stderr, .Reset);285 try ttyconf.setColor(stderr, .reset);
286 for (eb.getNotes(err_msg_index)) |note| {286 for (eb.getNotes(err_msg_index)) |note| {
287 try renderErrorMessageToWriter(eb, options, note, stderr, "note", .Cyan, indent + 4);287 try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent + 4);
288 }288 }
289 }289 }
290}290}
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;