authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-17 17:00:41-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:10-08:00
log608145c2f07d90c46cdaa8bc2013f31b965a5b8b
treea8704744b3808887c25ecf7b674eed030b2f6c7d
parentaa57793b680b3da05f1d888b4df15807905e57c8

fix more fallout from locking stderr


35 files changed, 446 insertions(+), 458 deletions(-)

lib/compiler/aro/aro/Diagnostics.zig+13-15
......@@ -24,20 +24,21 @@ pub const Message = struct {
2424 @"fatal error",
2525 };
2626
27 pub fn write(msg: Message, w: *std.Io.Writer, config: std.Io.File.Writer.Mode, details: bool) std.Io.tty.Config.SetColorError!void {
28 try config.setColor(w, .bold);
27 pub fn write(msg: Message, t: std.Io.Terminal, details: bool) std.Io.Terminal.SetColorError!void {
28 const w = t.writer;
29 try t.setColor(.bold);
2930 if (msg.location) |loc| {
3031 try w.print("{s}:{d}:{d}: ", .{ loc.path, loc.line_no, loc.col });
3132 }
3233 switch (msg.effective_kind) {
33 .@"fatal error", .@"error" => try config.setColor(w, .bright_red),
34 .note => try config.setColor(w, .bright_cyan),
35 .warning => try config.setColor(w, .bright_magenta),
34 .@"fatal error", .@"error" => try t.setColor(.bright_red),
35 .note => try t.setColor(.bright_cyan),
36 .warning => try t.setColor(.bright_magenta),
3637 .off => unreachable,
3738 }
3839 try w.print("{s}: ", .{@tagName(msg.effective_kind)});
3940
40 try config.setColor(w, .white);
41 try t.setColor(.white);
4142 try w.writeAll(msg.text);
4243 if (msg.opt) |some| {
4344 if (msg.effective_kind == .@"error" and msg.kind != .@"error") {
......@@ -55,17 +56,17 @@ pub const Message = struct {
5556
5657 if (!details or msg.location == null) {
5758 try w.writeAll("\n");
58 try config.setColor(w, .reset);
59 try t.setColor(.reset);
5960 } else {
6061 const loc = msg.location.?;
6162 const trailer = if (loc.end_with_splice) "\\ " else "";
62 try config.setColor(w, .reset);
63 try t.setColor(.reset);
6364 try w.print("\n{s}{s}\n", .{ loc.line, trailer });
6465 try w.splatByteAll(' ', loc.width);
65 try config.setColor(w, .bold);
66 try config.setColor(w, .bright_green);
66 try t.setColor(.bold);
67 try t.setColor(.bright_green);
6768 try w.writeAll("^\n");
68 try config.setColor(w, .reset);
69 try t.setColor(.reset);
6970 }
7071 try w.flush();
7172 }
......@@ -290,10 +291,7 @@ pub const State = struct {
290291const Diagnostics = @This();
291292
292293output: union(enum) {
293 to_writer: struct {
294 writer: *std.Io.Writer,
295 color: std.Io.File.Writer.Mode,
296 },
294 to_writer: std.Io.Terminal,
297295 to_list: struct {
298296 messages: std.ArrayList(Message) = .empty,
299297 arena: std.heap.ArenaAllocator,
lib/compiler/build_runner.zig+169-169
......@@ -286,8 +286,8 @@ pub fn main() !void {
286286 const next_arg = nextArg(args, &arg_idx) orelse
287287 fatalWithHint("expected u16 after '{s}'", .{arg});
288288 debounce_interval_ms = std.fmt.parseUnsigned(u16, next_arg, 0) catch |err| {
289 fatal("unable to parse debounce interval '{s}' as unsigned 16-bit integer: {s}\n", .{
290 next_arg, @errorName(err),
289 fatal("unable to parse debounce interval '{s}' as unsigned 16-bit integer: {t}\n", .{
290 next_arg, err,
291291 });
292292 };
293293 } else if (mem.eql(u8, arg, "--webui")) {
......@@ -429,6 +429,12 @@ pub fn main() !void {
429429 }
430430 }
431431
432 graph.stderr_mode = switch (color) {
433 .auto => try .detect(io, .stderr()),
434 .on => .escape_codes,
435 .off => .no_color,
436 };
437
432438 if (webui_listen != null) {
433439 if (watch) fatal("using '--webui' and '--watch' together is not yet supported; consider omitting '--watch' in favour of the web UI \"Rebuild\" button", .{});
434440 if (builtin.single_threaded) fatal("'--webui' is not yet supported on single-threaded hosts", .{});
......@@ -522,7 +528,7 @@ pub fn main() !void {
522528 // Perhaps in the future there could be an Advanced Options flag
523529 // such as --debug-build-runner-leaks which would make this code
524530 // return instead of calling exit.
525 _ = io.lockStderrWriter(&.{}) catch {};
531 _ = io.lockStderr(&.{}, graph.stderr_mode) catch {};
526532 process.exit(1);
527533 },
528534 else => |e| return e,
......@@ -554,9 +560,9 @@ pub fn main() !void {
554560 }
555561
556562 rebuild: while (true) : (if (run.error_style.clearOnUpdate()) {
557 const stderr = try io.lockStderrWriter(&stdio_buffer_allocation);
558 defer io.unlockStderrWriter();
559 try stderr.writeAllUnescaped("\x1B[2J\x1B[3J\x1B[H");
563 const stderr = try io.lockStderr(&stdio_buffer_allocation, graph.stderr_mode);
564 defer io.unlockStderr();
565 try stderr.file_writer.interface.writeAll("\x1B[2J\x1B[3J\x1B[H");
560566 }) {
561567 if (run.web_server) |*ws| ws.startBuild();
562568
......@@ -730,7 +736,8 @@ fn runStepNames(
730736 fuzz: ?std.Build.Fuzz.Mode,
731737) !void {
732738 const gpa = run.gpa;
733 const io = b.graph.io;
739 const graph = b.graph;
740 const io = graph.io;
734741 const step_stack = &run.step_stack;
735742
736743 {
......@@ -856,20 +863,19 @@ fn runStepNames(
856863 .none => break :summary,
857864 }
858865
859 const stderr = try io.lockStderrWriter(&stdio_buffer_allocation);
860 defer io.unlockStderrWriter();
861
862 const w = &stderr.interface;
863 const fwm = stderr.mode;
866 const stderr = try io.lockStderr(&stdio_buffer_allocation, graph.stderr_mode);
867 defer io.unlockStderr();
868 const t = stderr.terminal();
869 const w = &stderr.file_writer.interface;
864870
865871 const total_count = success_count + failure_count + pending_count + skipped_count;
866 fwm.setColor(w, .cyan) catch {};
867 fwm.setColor(w, .bold) catch {};
872 t.setColor(.cyan) catch {};
873 t.setColor(.bold) catch {};
868874 w.writeAll("Build Summary: ") catch {};
869 fwm.setColor(w, .reset) catch {};
875 t.setColor(.reset) catch {};
870876 w.print("{d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
871877 {
872 fwm.setColor(w, .dim) catch {};
878 t.setColor(.dim) catch {};
873879 var first = true;
874880 if (skipped_count > 0) {
875881 w.print("{s}{d} skipped", .{ if (first) " (" else ", ", skipped_count }) catch {};
......@@ -880,12 +886,12 @@ fn runStepNames(
880886 first = false;
881887 }
882888 if (!first) w.writeByte(')') catch {};
883 fwm.setColor(w, .reset) catch {};
889 t.setColor(.reset) catch {};
884890 }
885891
886892 if (test_count > 0) {
887893 w.print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
888 fwm.setColor(w, .dim) catch {};
894 t.setColor(.dim) catch {};
889895 var first = true;
890896 if (test_skip_count > 0) {
891897 w.print("{s}{d} skipped", .{ if (first) " (" else ", ", test_skip_count }) catch {};
......@@ -904,7 +910,7 @@ fn runStepNames(
904910 first = false;
905911 }
906912 if (!first) w.writeByte(')') catch {};
907 fwm.setColor(w, .reset) catch {};
913 t.setColor(.reset) catch {};
908914 }
909915
910916 w.writeAll("\n") catch {};
......@@ -918,7 +924,7 @@ fn runStepNames(
918924 var print_node: PrintNode = .{ .parent = null };
919925 if (step_names.len == 0) {
920926 print_node.last = true;
921 printTreeStep(b, b.default_step, run, w, fwm, &print_node, &step_stack_copy) catch {};
927 printTreeStep(b, b.default_step, run, t, &print_node, &step_stack_copy) catch {};
922928 } else {
923929 const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {
924930 var i: usize = step_names.len;
......@@ -937,7 +943,7 @@ fn runStepNames(
937943 for (step_names, 0..) |step_name, i| {
938944 const tls = b.top_level_steps.get(step_name).?;
939945 print_node.last = i + 1 == last_index;
940 printTreeStep(b, &tls.step, run, w, fwm, &print_node, &step_stack_copy) catch {};
946 printTreeStep(b, &tls.step, run, t, &print_node, &step_stack_copy) catch {};
941947 }
942948 }
943949 w.writeByte('\n') catch {};
......@@ -954,7 +960,7 @@ fn runStepNames(
954960 if (run.error_style.verboseContext()) break :code 1; // failure; print build command
955961 break :code 2; // failure; do not print build command
956962 };
957 _ = io.lockStderrWriter(&.{}) catch {};
963 _ = io.lockStderr(&.{}, graph.stderr_mode) catch {};
958964 process.exit(code);
959965}
960966
......@@ -963,33 +969,30 @@ const PrintNode = struct {
963969 last: bool = false,
964970};
965971
966fn printPrefix(node: *PrintNode, w: *Writer, fwm: File.Writer.Mode) !void {
972fn printPrefix(node: *PrintNode, stderr: Io.Terminal) !void {
967973 const parent = node.parent orelse return;
974 const writer = stderr.writer;
968975 if (parent.parent == null) return;
969 try printPrefix(parent, w, fwm);
976 try printPrefix(parent, stderr);
970977 if (parent.last) {
971 try w.writeAll(" ");
978 try writer.writeAll(" ");
972979 } else {
973 try w.writeAll(switch (fwm) {
974 .terminal_escaped => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │
980 try writer.writeAll(switch (stderr.mode) {
981 .escape_codes => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │
975982 else => "| ",
976983 });
977984 }
978985}
979986
980fn printChildNodePrefix(w: *Writer, fwm: File.Writer.Mode) !void {
981 try w.writeAll(switch (fwm) {
982 .terminal_escaped => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
987fn printChildNodePrefix(stderr: Io.Terminal) !void {
988 try stderr.writer.writeAll(switch (stderr.mode) {
989 .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
983990 else => "+- ",
984991 });
985992}
986993
987fn printStepStatus(
988 s: *Step,
989 stderr: *Writer,
990 fwm: File.Writer.Mode,
991 run: *const Run,
992) !void {
994fn printStepStatus(s: *Step, stderr: Io.Terminal, run: *const Run) !void {
995 const writer = stderr.writer;
993996 switch (s.state) {
994997 .precheck_unstarted => unreachable,
995998 .precheck_started => unreachable,
......@@ -997,139 +1000,135 @@ fn printStepStatus(
9971000 .running => unreachable,
9981001
9991002 .dependency_failure => {
1000 try fwm.setColor(stderr, .dim);
1001 try stderr.writeAll(" transitive failure\n");
1002 try fwm.setColor(stderr, .reset);
1003 try stderr.setColor(.dim);
1004 try writer.writeAll(" transitive failure\n");
1005 try stderr.setColor(.reset);
10031006 },
10041007
10051008 .success => {
1006 try fwm.setColor(stderr, .green);
1009 try stderr.setColor(.green);
10071010 if (s.result_cached) {
1008 try stderr.writeAll(" cached");
1011 try writer.writeAll(" cached");
10091012 } else if (s.test_results.test_count > 0) {
10101013 const pass_count = s.test_results.passCount();
10111014 assert(s.test_results.test_count == pass_count + s.test_results.skip_count);
1012 try stderr.print(" {d} pass", .{pass_count});
1015 try writer.print(" {d} pass", .{pass_count});
10131016 if (s.test_results.skip_count > 0) {
1014 try fwm.setColor(stderr, .reset);
1015 try stderr.writeAll(", ");
1016 try fwm.setColor(stderr, .yellow);
1017 try stderr.print("{d} skip", .{s.test_results.skip_count});
1017 try stderr.setColor(.reset);
1018 try writer.writeAll(", ");
1019 try stderr.setColor(.yellow);
1020 try writer.print("{d} skip", .{s.test_results.skip_count});
10181021 }
1019 try fwm.setColor(stderr, .reset);
1020 try stderr.print(" ({d} total)", .{s.test_results.test_count});
1022 try stderr.setColor(.reset);
1023 try writer.print(" ({d} total)", .{s.test_results.test_count});
10211024 } else {
1022 try stderr.writeAll(" success");
1025 try writer.writeAll(" success");
10231026 }
1024 try fwm.setColor(stderr, .reset);
1027 try stderr.setColor(.reset);
10251028 if (s.result_duration_ns) |ns| {
1026 try fwm.setColor(stderr, .dim);
1029 try stderr.setColor(.dim);
10271030 if (ns >= std.time.ns_per_min) {
1028 try stderr.print(" {d}m", .{ns / std.time.ns_per_min});
1031 try writer.print(" {d}m", .{ns / std.time.ns_per_min});
10291032 } else if (ns >= std.time.ns_per_s) {
1030 try stderr.print(" {d}s", .{ns / std.time.ns_per_s});
1033 try writer.print(" {d}s", .{ns / std.time.ns_per_s});
10311034 } else if (ns >= std.time.ns_per_ms) {
1032 try stderr.print(" {d}ms", .{ns / std.time.ns_per_ms});
1035 try writer.print(" {d}ms", .{ns / std.time.ns_per_ms});
10331036 } else if (ns >= std.time.ns_per_us) {
1034 try stderr.print(" {d}us", .{ns / std.time.ns_per_us});
1037 try writer.print(" {d}us", .{ns / std.time.ns_per_us});
10351038 } else {
1036 try stderr.print(" {d}ns", .{ns});
1039 try writer.print(" {d}ns", .{ns});
10371040 }
1038 try fwm.setColor(stderr, .reset);
1041 try stderr.setColor(.reset);
10391042 }
10401043 if (s.result_peak_rss != 0) {
10411044 const rss = s.result_peak_rss;
1042 try fwm.setColor(stderr, .dim);
1045 try stderr.setColor(.dim);
10431046 if (rss >= 1000_000_000) {
1044 try stderr.print(" MaxRSS:{d}G", .{rss / 1000_000_000});
1047 try writer.print(" MaxRSS:{d}G", .{rss / 1000_000_000});
10451048 } else if (rss >= 1000_000) {
1046 try stderr.print(" MaxRSS:{d}M", .{rss / 1000_000});
1049 try writer.print(" MaxRSS:{d}M", .{rss / 1000_000});
10471050 } else if (rss >= 1000) {
1048 try stderr.print(" MaxRSS:{d}K", .{rss / 1000});
1051 try writer.print(" MaxRSS:{d}K", .{rss / 1000});
10491052 } else {
1050 try stderr.print(" MaxRSS:{d}B", .{rss});
1053 try writer.print(" MaxRSS:{d}B", .{rss});
10511054 }
1052 try fwm.setColor(stderr, .reset);
1055 try stderr.setColor(.reset);
10531056 }
1054 try stderr.writeAll("\n");
1057 try writer.writeAll("\n");
10551058 },
10561059 .skipped, .skipped_oom => |skip| {
1057 try fwm.setColor(stderr, .yellow);
1058 try stderr.writeAll(" skipped");
1060 try stderr.setColor(.yellow);
1061 try writer.writeAll(" skipped");
10591062 if (skip == .skipped_oom) {
1060 try stderr.writeAll(" (not enough memory)");
1061 try fwm.setColor(stderr, .dim);
1062 try stderr.print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
1063 try fwm.setColor(stderr, .yellow);
1063 try writer.writeAll(" (not enough memory)");
1064 try stderr.setColor(.dim);
1065 try writer.print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
1066 try stderr.setColor(.yellow);
10641067 }
1065 try stderr.writeAll("\n");
1066 try fwm.setColor(stderr, .reset);
1068 try writer.writeAll("\n");
1069 try stderr.setColor(.reset);
10671070 },
10681071 .failure => {
1069 try printStepFailure(s, stderr, fwm, false);
1070 try fwm.setColor(stderr, .reset);
1072 try printStepFailure(s, stderr, false);
1073 try stderr.setColor(.reset);
10711074 },
10721075 }
10731076}
10741077
1075fn printStepFailure(
1076 s: *Step,
1077 stderr: *Writer,
1078 fwm: File.Writer.Mode,
1079 dim: bool,
1080) !void {
1078fn printStepFailure(s: *Step, stderr: Io.Terminal, dim: bool) !void {
1079 const w = stderr.writer;
10811080 if (s.result_error_bundle.errorMessageCount() > 0) {
1082 try fwm.setColor(stderr, .red);
1083 try stderr.print(" {d} errors\n", .{
1081 try stderr.setColor(.red);
1082 try w.print(" {d} errors\n", .{
10841083 s.result_error_bundle.errorMessageCount(),
10851084 });
10861085 } else if (!s.test_results.isSuccess()) {
10871086 // These first values include all of the test "statuses". Every test is either passsed,
10881087 // skipped, failed, crashed, or timed out.
1089 try fwm.setColor(stderr, .green);
1090 try stderr.print(" {d} pass", .{s.test_results.passCount()});
1091 try fwm.setColor(stderr, .reset);
1092 if (dim) try fwm.setColor(stderr, .dim);
1088 try stderr.setColor(.green);
1089 try w.print(" {d} pass", .{s.test_results.passCount()});
1090 try stderr.setColor(.reset);
1091 if (dim) try stderr.setColor(.dim);
10931092 if (s.test_results.skip_count > 0) {
1094 try stderr.writeAll(", ");
1095 try fwm.setColor(stderr, .yellow);
1096 try stderr.print("{d} skip", .{s.test_results.skip_count});
1097 try fwm.setColor(stderr, .reset);
1098 if (dim) try fwm.setColor(stderr, .dim);
1093 try w.writeAll(", ");
1094 try stderr.setColor(.yellow);
1095 try w.print("{d} skip", .{s.test_results.skip_count});
1096 try stderr.setColor(.reset);
1097 if (dim) try stderr.setColor(.dim);
10991098 }
11001099 if (s.test_results.fail_count > 0) {
1101 try stderr.writeAll(", ");
1102 try fwm.setColor(stderr, .red);
1103 try stderr.print("{d} fail", .{s.test_results.fail_count});
1104 try fwm.setColor(stderr, .reset);
1105 if (dim) try fwm.setColor(stderr, .dim);
1100 try w.writeAll(", ");
1101 try stderr.setColor(.red);
1102 try w.print("{d} fail", .{s.test_results.fail_count});
1103 try stderr.setColor(.reset);
1104 if (dim) try stderr.setColor(.dim);
11061105 }
11071106 if (s.test_results.crash_count > 0) {
1108 try stderr.writeAll(", ");
1109 try fwm.setColor(stderr, .red);
1110 try stderr.print("{d} crash", .{s.test_results.crash_count});
1111 try fwm.setColor(stderr, .reset);
1112 if (dim) try fwm.setColor(stderr, .dim);
1107 try w.writeAll(", ");
1108 try stderr.setColor(.red);
1109 try w.print("{d} crash", .{s.test_results.crash_count});
1110 try stderr.setColor(.reset);
1111 if (dim) try stderr.setColor(.dim);
11131112 }
11141113 if (s.test_results.timeout_count > 0) {
1115 try stderr.writeAll(", ");
1116 try fwm.setColor(stderr, .red);
1117 try stderr.print("{d} timeout", .{s.test_results.timeout_count});
1118 try fwm.setColor(stderr, .reset);
1119 if (dim) try fwm.setColor(stderr, .dim);
1114 try w.writeAll(", ");
1115 try stderr.setColor(.red);
1116 try w.print("{d} timeout", .{s.test_results.timeout_count});
1117 try stderr.setColor(.reset);
1118 if (dim) try stderr.setColor(.dim);
11201119 }
1121 try stderr.print(" ({d} total)", .{s.test_results.test_count});
1120 try w.print(" ({d} total)", .{s.test_results.test_count});
11221121
11231122 // Memory leaks are intentionally written after the total, because is isn't a test *status*,
11241123 // but just a flag that any tests -- even passed ones -- can have. We also use a different
11251124 // separator, so it looks like:
11261125 // 2 pass, 1 skip, 2 fail (5 total); 2 leaks
11271126 if (s.test_results.leak_count > 0) {
1128 try stderr.writeAll("; ");
1129 try fwm.setColor(stderr, .red);
1130 try stderr.print("{d} leaks", .{s.test_results.leak_count});
1131 try fwm.setColor(stderr, .reset);
1132 if (dim) try fwm.setColor(stderr, .dim);
1127 try w.writeAll("; ");
1128 try stderr.setColor(.red);
1129 try w.print("{d} leaks", .{s.test_results.leak_count});
1130 try stderr.setColor(.reset);
1131 if (dim) try stderr.setColor(.dim);
11331132 }
11341133
11351134 // It's usually not helpful to know how many error logs there were because they tend to
......@@ -1142,21 +1141,21 @@ fn printStepFailure(
11421141 break :show alt_results.isSuccess();
11431142 };
11441143 if (show_err_logs) {
1145 try stderr.writeAll("; ");
1146 try fwm.setColor(stderr, .red);
1147 try stderr.print("{d} error logs", .{s.test_results.log_err_count});
1148 try fwm.setColor(stderr, .reset);
1149 if (dim) try fwm.setColor(stderr, .dim);
1144 try w.writeAll("; ");
1145 try stderr.setColor(.red);
1146 try w.print("{d} error logs", .{s.test_results.log_err_count});
1147 try stderr.setColor(.reset);
1148 if (dim) try stderr.setColor(.dim);
11501149 }
11511150
1152 try stderr.writeAll("\n");
1151 try w.writeAll("\n");
11531152 } else if (s.result_error_msgs.items.len > 0) {
1154 try fwm.setColor(stderr, .red);
1155 try stderr.writeAll(" failure\n");
1153 try stderr.setColor(.red);
1154 try w.writeAll(" failure\n");
11561155 } else {
11571156 assert(s.result_stderr.len > 0);
1158 try fwm.setColor(stderr, .red);
1159 try stderr.writeAll(" stderr\n");
1157 try stderr.setColor(.red);
1158 try w.writeAll(" w\n");
11601159 }
11611160}
11621161
......@@ -1164,11 +1163,11 @@ fn printTreeStep(
11641163 b: *std.Build,
11651164 s: *Step,
11661165 run: *const Run,
1167 stderr: *Writer,
1168 fwm: File.Writer.Mode,
1166 stderr: Io.Terminal,
11691167 parent_node: *PrintNode,
11701168 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
11711169) !void {
1170 const writer = stderr.writer;
11721171 const first = step_stack.swapRemove(s);
11731172 const summary = run.summary;
11741173 const skip = switch (summary) {
......@@ -1178,26 +1177,26 @@ fn printTreeStep(
11781177 .failures => s.state == .success,
11791178 };
11801179 if (skip) return;
1181 try printPrefix(parent_node, stderr, fwm);
1180 try printPrefix(parent_node, stderr);
11821181
11831182 if (parent_node.parent != null) {
11841183 if (parent_node.last) {
1185 try printChildNodePrefix(stderr, fwm);
1184 try printChildNodePrefix(stderr);
11861185 } else {
1187 try stderr.writeAll(switch (fwm) {
1188 .terminal_escaped => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─
1186 try writer.writeAll(switch (stderr.mode) {
1187 .escape_codes => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─
11891188 else => "+- ",
11901189 });
11911190 }
11921191 }
11931192
1194 if (!first) try fwm.setColor(stderr, .dim);
1193 if (!first) try stderr.setColor(.dim);
11951194
11961195 // dep_prefix omitted here because it is redundant with the tree.
1197 try stderr.writeAll(s.name);
1196 try writer.writeAll(s.name);
11981197
11991198 if (first) {
1200 try printStepStatus(s, stderr, fwm, run);
1199 try printStepStatus(s, stderr, run);
12011200
12021201 const last_index = if (summary == .all) s.dependencies.items.len -| 1 else blk: {
12031202 var i: usize = s.dependencies.items.len;
......@@ -1219,17 +1218,17 @@ fn printTreeStep(
12191218 .parent = parent_node,
12201219 .last = i == last_index,
12211220 };
1222 try printTreeStep(b, dep, run, stderr, fwm, &print_node, step_stack);
1221 try printTreeStep(b, dep, run, stderr, &print_node, step_stack);
12231222 }
12241223 } else {
12251224 if (s.dependencies.items.len == 0) {
1226 try stderr.writeAll(" (reused)\n");
1225 try writer.writeAll(" (reused)\n");
12271226 } else {
1228 try stderr.print(" (+{d} more reused dependencies)\n", .{
1227 try writer.print(" (+{d} more reused dependencies)\n", .{
12291228 s.dependencies.items.len,
12301229 });
12311230 }
1232 try fwm.setColor(stderr, .reset);
1231 try stderr.setColor(.reset);
12331232 }
12341233}
12351234
......@@ -1300,7 +1299,8 @@ fn workerMakeOneStep(
13001299 prog_node: std.Progress.Node,
13011300 run: *Run,
13021301) void {
1303 const io = b.graph.io;
1302 const graph = b.graph;
1303 const io = graph.io;
13041304 const gpa = run.gpa;
13051305
13061306 // First, check the conditions for running this step. If they are not met,
......@@ -1369,11 +1369,11 @@ fn workerMakeOneStep(
13691369 const show_error_msgs = s.result_error_msgs.items.len > 0;
13701370 const show_stderr = s.result_stderr.len > 0;
13711371 if (show_error_msgs or show_compile_errors or show_stderr) {
1372 const stderr = io.lockStderrWriter(&stdio_buffer_allocation) catch |err| switch (err) {
1372 const stderr = io.lockStderr(&stdio_buffer_allocation, graph.stderr_mode) catch |err| switch (err) {
13731373 error.Canceled => return,
13741374 };
1375 defer io.unlockStderrWriter();
1376 printErrorMessages(gpa, s, .{}, &stderr.interface, stderr.mode, run.error_style, run.multiline_errors) catch {};
1375 defer io.unlockStderr();
1376 printErrorMessages(gpa, s, .{}, stderr.terminal(), run.error_style, run.multiline_errors) catch {};
13771377 }
13781378
13791379 handle_result: {
......@@ -1440,11 +1440,11 @@ pub fn printErrorMessages(
14401440 gpa: Allocator,
14411441 failing_step: *Step,
14421442 options: std.zig.ErrorBundle.RenderOptions,
1443 stderr: *Writer,
1444 fwm: File.Writer.Mode,
1443 stderr: Io.Terminal,
14451444 error_style: ErrorStyle,
14461445 multiline_errors: MultilineErrors,
14471446) !void {
1447 const writer = stderr.writer;
14481448 if (error_style.verboseContext()) {
14491449 // Provide context for where these error messages are coming from by
14501450 // printing the corresponding Step subtree.
......@@ -1456,70 +1456,70 @@ pub fn printErrorMessages(
14561456 }
14571457
14581458 // Now, `step_stack` has the subtree that we want to print, in reverse order.
1459 try fwm.setColor(stderr, .dim);
1459 try stderr.setColor(.dim);
14601460 var indent: usize = 0;
14611461 while (step_stack.pop()) |s| : (indent += 1) {
14621462 if (indent > 0) {
1463 try stderr.splatByteAll(' ', (indent - 1) * 3);
1464 try printChildNodePrefix(stderr, fwm);
1463 try writer.splatByteAll(' ', (indent - 1) * 3);
1464 try printChildNodePrefix(stderr);
14651465 }
14661466
1467 try stderr.writeAll(s.name);
1467 try writer.writeAll(s.name);
14681468
14691469 if (s == failing_step) {
1470 try printStepFailure(s, stderr, fwm, true);
1470 try printStepFailure(s, stderr, true);
14711471 } else {
1472 try stderr.writeAll("\n");
1472 try writer.writeAll("\n");
14731473 }
14741474 }
1475 try fwm.setColor(stderr, .reset);
1475 try stderr.setColor(.reset);
14761476 } else {
14771477 // Just print the failing step itself.
1478 try fwm.setColor(stderr, .dim);
1479 try stderr.writeAll(failing_step.name);
1480 try printStepFailure(failing_step, stderr, fwm, true);
1481 try fwm.setColor(stderr, .reset);
1478 try stderr.setColor(.dim);
1479 try writer.writeAll(failing_step.name);
1480 try printStepFailure(failing_step, stderr, true);
1481 try stderr.setColor(.reset);
14821482 }
14831483
14841484 if (failing_step.result_stderr.len > 0) {
1485 try stderr.writeAll(failing_step.result_stderr);
1485 try writer.writeAll(failing_step.result_stderr);
14861486 if (!mem.endsWith(u8, failing_step.result_stderr, "\n")) {
1487 try stderr.writeAll("\n");
1487 try writer.writeAll("\n");
14881488 }
14891489 }
14901490
1491 try failing_step.result_error_bundle.renderToWriter(options, stderr, fwm);
1491 try failing_step.result_error_bundle.renderToTerminal(options, stderr);
14921492
14931493 for (failing_step.result_error_msgs.items) |msg| {
1494 try fwm.setColor(stderr, .red);
1495 try stderr.writeAll("error:");
1496 try fwm.setColor(stderr, .reset);
1494 try stderr.setColor(.red);
1495 try writer.writeAll("error:");
1496 try stderr.setColor(.reset);
14971497 if (std.mem.indexOfScalar(u8, msg, '\n') == null) {
1498 try stderr.print(" {s}\n", .{msg});
1498 try writer.print(" {s}\n", .{msg});
14991499 } else switch (multiline_errors) {
15001500 .indent => {
15011501 var it = std.mem.splitScalar(u8, msg, '\n');
1502 try stderr.print(" {s}\n", .{it.first()});
1502 try writer.print(" {s}\n", .{it.first()});
15031503 while (it.next()) |line| {
1504 try stderr.print(" {s}\n", .{line});
1504 try writer.print(" {s}\n", .{line});
15051505 }
15061506 },
1507 .newline => try stderr.print("\n{s}\n", .{msg}),
1508 .none => try stderr.print(" {s}\n", .{msg}),
1507 .newline => try writer.print("\n{s}\n", .{msg}),
1508 .none => try writer.print(" {s}\n", .{msg}),
15091509 }
15101510 }
15111511
15121512 if (error_style.verboseContext()) {
15131513 if (failing_step.result_failed_command) |cmd_str| {
1514 try fwm.setColor(stderr, .red);
1515 try stderr.writeAll("failed command: ");
1516 try fwm.setColor(stderr, .reset);
1517 try stderr.writeAll(cmd_str);
1518 try stderr.writeByte('\n');
1514 try stderr.setColor(.red);
1515 try writer.writeAll("failed command: ");
1516 try stderr.setColor(.reset);
1517 try writer.writeAll(cmd_str);
1518 try writer.writeByte('\n');
15191519 }
15201520 }
15211521
1522 try stderr.writeByte('\n');
1522 try writer.writeByte('\n');
15231523}
15241524
15251525fn printSteps(builder: *std.Build, w: *Writer) !void {
lib/compiler/resinator/cli.zig+5-5
......@@ -126,14 +126,14 @@ pub const Diagnostics = struct {
126126 }
127127
128128 pub fn renderToStderr(self: *Diagnostics, io: Io, args: []const []const u8) void {
129 const stderr = io.lockStderrWriter(&.{});
130 defer io.unlockStderrWriter();
131 self.renderToWriter(args, &stderr.interface, stderr.mode) catch return;
129 const stderr = io.lockStderr(&.{}, null);
130 defer io.unlockStderr();
131 self.renderToWriter(args, stderr.terminal()) catch return;
132132 }
133133
134 pub fn renderToWriter(self: *Diagnostics, args: []const []const u8, writer: *std.Io.Writer, config: std.Io.tty.Config) !void {
134 pub fn renderToWriter(self: *Diagnostics, args: []const []const u8, t: Io.Terminal) !void {
135135 for (self.errors.items) |err_details| {
136 try renderErrorMessage(writer, config, err_details, args);
136 try renderErrorMessage(t, err_details, args);
137137 }
138138 }
139139
lib/compiler/resinator/errors.zig+3-3
......@@ -69,10 +69,10 @@ pub const Diagnostics = struct {
6969
7070 pub fn renderToStderr(self: *Diagnostics, cwd: Io.Dir, source: []const u8, source_mappings: ?SourceMappings) void {
7171 const io = self.io;
72 const stderr = io.lockStderrWriter(&.{});
73 defer io.unlockStderrWriter();
72 const stderr = io.lockStderr(&.{}, null);
73 defer io.unlockStderr();
7474 for (self.errors.items) |err_details| {
75 renderErrorMessage(io, &stderr.interface, stderr.mode, cwd, err_details, source, self.strings.items, source_mappings) catch return;
75 renderErrorMessage(io, stderr.terminal(), cwd, err_details, source, self.strings.items, source_mappings) catch return;
7676 }
7777 }
7878
lib/compiler/resinator/main.zig+14-17
......@@ -35,8 +35,8 @@ pub fn main() !void {
3535 const args = try std.process.argsAlloc(arena);
3636
3737 if (args.len < 2) {
38 const stderr = io.lockStderrWriter(&.{});
39 try renderErrorMessage(&stderr.interface, stderr.mode, .err, "expected zig lib dir as first argument", .{});
38 const stderr = try io.lockStderr(&.{}, null);
39 try renderErrorMessage(stderr.terminal(), .err, "expected zig lib dir as first argument", .{});
4040 std.process.exit(1);
4141 }
4242 const zig_lib_dir = args[1];
......@@ -80,9 +80,9 @@ pub fn main() !void {
8080 // so that there is a clear separation between the cli diagnostics and whatever
8181 // gets printed after
8282 if (cli_diagnostics.errors.items.len > 0) {
83 const stderr = io.lockStderrWriter(&.{});
84 defer io.unlockStderrWriter();
85 try stderr.interface.writeByte('\n');
83 const stderr = try io.lockStderr(&.{}, null);
84 defer io.unlockStderr();
85 try stderr.file_writer.interface.writeByte('\n');
8686 }
8787 }
8888 break :options options;
......@@ -130,15 +130,12 @@ pub fn main() !void {
130130 var stderr_buf: [512]u8 = undefined;
131131 var diagnostics: aro.Diagnostics = .{ .output = output: {
132132 if (zig_integration) break :output .{ .to_list = .{ .arena = .init(gpa) } };
133 const stderr = io.lockStderrWriter(&stderr_buf);
134 break :output .{ .to_writer = .{
135 .writer = &stderr.interface,
136 .color = stderr.mode,
137 } };
133 const stderr = try io.lockStderr(&stderr_buf, null);
134 break :output .{ .to_writer = stderr.terminal() };
138135 } };
139136 defer {
140137 diagnostics.deinit();
141 if (!zig_integration) std.debug.unlockStderrWriter();
138 if (!zig_integration) std.debug.unlockStderr();
142139 }
143140
144141 var comp = aro.Compilation.init(aro_arena, aro_arena, io, &diagnostics, Io.Dir.cwd());
......@@ -699,9 +696,9 @@ const ErrorHandler = union(enum) {
699696 },
700697 .stderr => {
701698 // aro errors have already been emitted
702 const stderr = io.lockStderrWriter(&.{});
703 defer io.unlockStderrWriter();
704 try renderErrorMessage(&stderr.interface, stderr.mode, .err, "{s}", .{fail_msg});
699 const stderr = io.lockStderr(&.{}, null);
700 defer io.unlockStderr();
701 try renderErrorMessage(stderr.terminal(), .err, "{s}", .{fail_msg});
705702 },
706703 }
707704 }
......@@ -745,9 +742,9 @@ const ErrorHandler = union(enum) {
745742 try server.serveErrorBundle(error_bundle);
746743 },
747744 .stderr => {
748 const stderr = io.lockStderrWriter(&.{});
749 defer io.unlockStderrWriter();
750 try renderErrorMessage(&stderr.interface, stderr.mode, msg_type, format, args);
745 const stderr = try io.lockStderr(&.{}, null);
746 defer io.unlockStderr();
747 try renderErrorMessage(stderr.terminal(), msg_type, format, args);
751748 },
752749 }
753750 }
lib/compiler/test_runner.zig+4-4
......@@ -405,18 +405,18 @@ pub fn fuzz(
405405 testOne(ctx, input.toSlice()) catch |err| switch (err) {
406406 error.SkipZigTest => return,
407407 else => {
408 const stderr = std.debug.lockStderrWriter(&.{});
408 const stderr = std.debug.lockStderr(&.{}, null).terminal();
409409 p: {
410410 if (@errorReturnTrace()) |trace| {
411 std.debug.writeStackTrace(trace, &stderr.interface, stderr.mode) catch break :p;
411 std.debug.writeStackTrace(trace, stderr) catch break :p;
412412 }
413 stderr.interface.print("failed with error.{t}\n", .{err}) catch break :p;
413 stderr.writer.print("failed with error.{t}\n", .{err}) catch break :p;
414414 }
415415 std.process.exit(1);
416416 },
417417 };
418418 if (log_err_count != 0) {
419 const stderr = std.debug.lockStderrWriter(&.{});
419 const stderr = std.debug.lockStderr(&.{}, .no_color);
420420 stderr.interface.print("error logs detected\n", .{}) catch {};
421421 std.process.exit(1);
422422 }
lib/std/Build.zig+36-37
......@@ -129,6 +129,9 @@ pub const Graph = struct {
129129 dependency_cache: InitializedDepMap = .empty,
130130 allow_so_scripts: ?bool = null,
131131 time_report: bool,
132 /// Similar to the `Io.Terminal.Mode` returned by `Io.lockStderr`, but also
133 /// respects the '--color' flag.
134 stderr_mode: ?Io.Terminal.Mode = null,
132135};
133136
134137const AvailableDeps = []const struct { []const u8, []const u8 };
......@@ -2255,9 +2258,10 @@ pub const GeneratedFile = struct {
22552258
22562259 pub fn getPath3(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) Io.Cancelable![]const u8 {
22572260 return gen.path orelse {
2258 const io = gen.step.owner.graph.io;
2259 const stderr = try io.lockStderrWriter(&.{});
2260 dumpBadGetPathHelp(gen.step, &stderr.interface, stderr.mode, src_builder, asking_step) catch {};
2261 const graph = gen.step.owner.graph;
2262 const io = graph.io;
2263 const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
2264 dumpBadGetPathHelp(gen.step, stderr.terminal(), src_builder, asking_step) catch {};
22612265 @panic("misconfigured build script");
22622266 };
22632267 }
......@@ -2468,13 +2472,15 @@ pub const LazyPath = union(enum) {
24682472 // TODO make gen.file.path not be absolute and use that as the
24692473 // basis for not traversing up too many directories.
24702474
2475 const graph = src_builder.graph;
2476
24712477 var file_path: Cache.Path = .{
24722478 .root_dir = Cache.Directory.cwd(),
24732479 .sub_path = gen.file.path orelse {
2474 const io = src_builder.graph.io;
2475 const stderr = try io.lockStderrWriter(&.{});
2476 dumpBadGetPathHelp(gen.file.step, &stderr.interface, stderr.mode, src_builder, asking_step) catch {};
2477 io.unlockStderrWriter();
2480 const io = graph.io;
2481 const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
2482 dumpBadGetPathHelp(gen.file.step, stderr.terminal(), src_builder, asking_step) catch {};
2483 io.unlockStderr();
24782484 @panic("misconfigured build script");
24792485 },
24802486 };
......@@ -2564,43 +2570,36 @@ fn dumpBadDirnameHelp(
25642570 comptime msg: []const u8,
25652571 args: anytype,
25662572) anyerror!void {
2567 const stderr = std.debug.lockStderrWriter(&.{});
2568 defer std.debug.unlockStderrWriter();
2569
2570 const w = &stderr.interface;
2571 const fwm = stderr.mode;
2573 const stderr = std.debug.lockStderr(&.{}).terminal();
2574 defer std.debug.unlockStderr();
2575 const w = stderr.writer;
25722576
25732577 try w.print(msg, args);
25742578
25752579 if (fail_step) |s| {
2576 fwm.setColor(w, .red) catch {};
2580 stderr.setColor(.red) catch {};
25772581 try w.writeAll(" The step was created by this stack trace:\n");
2578 fwm.setColor(w, .reset) catch {};
2582 stderr.setColor(.reset) catch {};
25792583
2580 s.dump(w, fwm);
2584 s.dump(stderr);
25812585 }
25822586
25832587 if (asking_step) |as| {
2584 fwm.setColor(w, .red) catch {};
2588 stderr.setColor(.red) catch {};
25852589 try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
2586 fwm.setColor(w, .reset) catch {};
2590 stderr.setColor(.reset) catch {};
25872591
2588 as.dump(w, fwm);
2592 as.dump(stderr);
25892593 }
25902594
2591 fwm.setColor(w, .red) catch {};
2592 try w.writeAll(" Hope that helps. Proceeding to panic.\n");
2593 fwm.setColor(w, .reset) catch {};
2595 stderr.setColor(.red) catch {};
2596 try w.writeAll(" Proceeding to panic.\n");
2597 stderr.setColor(.reset) catch {};
25942598}
25952599
25962600/// In this function the stderr mutex has already been locked.
2597pub fn dumpBadGetPathHelp(
2598 s: *Step,
2599 w: *Io.Writer,
2600 fwm: File.Writer.Mode,
2601 src_builder: *Build,
2602 asking_step: ?*Step,
2603) anyerror!void {
2601pub fn dumpBadGetPathHelp(s: *Step, t: Io.Terminal, src_builder: *Build, asking_step: ?*Step) anyerror!void {
2602 const w = t.writer;
26042603 try w.print(
26052604 \\getPath() was called on a GeneratedFile that wasn't built yet.
26062605 \\ source package path: {s}
......@@ -2611,21 +2610,21 @@ pub fn dumpBadGetPathHelp(
26112610 s.name,
26122611 });
26132612
2614 fwm.setColor(w, .red) catch {};
2613 t.setColor(.red) catch {};
26152614 try w.writeAll(" The step was created by this stack trace:\n");
2616 fwm.setColor(w, .reset) catch {};
2615 t.setColor(.reset) catch {};
26172616
2618 s.dump(w, fwm);
2617 s.dump(t);
26192618 if (asking_step) |as| {
2620 fwm.setColor(w, .red) catch {};
2619 t.setColor(.red) catch {};
26212620 try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
2622 fwm.setColor(w, .reset) catch {};
2621 t.setColor(.reset) catch {};
26232622
2624 as.dump(w, fwm);
2623 as.dump(t);
26252624 }
2626 fwm.setColor(w, .red) catch {};
2627 try w.writeAll(" Hope that helps. Proceeding to panic.\n");
2628 fwm.setColor(w, .reset) catch {};
2625 t.setColor(.red) catch {};
2626 try w.writeAll(" Proceeding to panic.\n");
2627 t.setColor(.reset) catch {};
26292628}
26302629
26312630pub const InstallDir = union(enum) {
lib/std/Build/Fuzz.zig+10-8
......@@ -158,7 +158,8 @@ fn rebuildTestsWorkerRun(run: *Step.Run, gpa: Allocator, parent_prog_node: std.P
158158}
159159
160160fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, parent_prog_node: std.Progress.Node) !void {
161 const io = run.step.owner.graph.io;
161 const graph = run.step.owner.graph;
162 const io = graph.io;
162163 const compile = run.producer.?;
163164 const prog_node = parent_prog_node.start(compile.step.name, 0);
164165 defer prog_node.end();
......@@ -171,9 +172,9 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, parent_prog_nod
171172
172173 if (show_error_msgs or show_compile_errors or show_stderr) {
173174 var buf: [256]u8 = undefined;
174 const stderr = try io.lockStderrWriter(&buf);
175 defer io.unlockStderrWriter();
176 build_runner.printErrorMessages(gpa, &compile.step, .{}, &stderr.interface, stderr.mode, .verbose, .indent) catch {};
175 const stderr = try io.lockStderr(&buf, graph.stderr_mode);
176 defer io.unlockStderr();
177 build_runner.printErrorMessages(gpa, &compile.step, .{}, stderr.terminal(), .verbose, .indent) catch {};
177178 }
178179
179180 const rebuilt_bin_path = result catch |err| switch (err) {
......@@ -186,7 +187,8 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, parent_prog_nod
186187fn fuzzWorkerRun(fuzz: *Fuzz, run: *Step.Run, unit_test_index: u32) void {
187188 const owner = run.step.owner;
188189 const gpa = owner.allocator;
189 const io = owner.graph.io;
190 const graph = owner.graph;
191 const io = graph.io;
190192 const test_name = run.cached_test_metadata.?.testName(unit_test_index);
191193
192194 const prog_node = fuzz.prog_node.start(test_name, 0);
......@@ -195,11 +197,11 @@ fn fuzzWorkerRun(fuzz: *Fuzz, run: *Step.Run, unit_test_index: u32) void {
195197 run.rerunInFuzzMode(fuzz, unit_test_index, prog_node) catch |err| switch (err) {
196198 error.MakeFailed => {
197199 var buf: [256]u8 = undefined;
198 const stderr = io.lockStderrWriter(&buf) catch |e| switch (e) {
200 const stderr = io.lockStderr(&buf, graph.stderr_mode) catch |e| switch (e) {
199201 error.Canceled => return,
200202 };
201 defer io.unlockStderrWriter();
202 build_runner.printErrorMessages(gpa, &run.step, .{}, &stderr.interface, stderr.mode, .verbose, .indent) catch {};
203 defer io.unlockStderr();
204 build_runner.printErrorMessages(gpa, &run.step, .{}, stderr.terminal(), .verbose, .indent) catch {};
203205 return;
204206 },
205207 else => {
lib/std/Build/Step.zig+5-4
......@@ -328,16 +328,17 @@ pub fn cast(step: *Step, comptime T: type) ?*T {
328328}
329329
330330/// For debugging purposes, prints identifying information about this Step.
331pub fn dump(step: *Step, w: *Io.Writer, fwm: Io.File.Writer.Mode) void {
331pub fn dump(step: *Step, t: Io.Terminal) void {
332 const w = t.writer;
332333 if (step.debug_stack_trace.instruction_addresses.len > 0) {
333334 w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};
334 std.debug.writeStackTrace(&step.debug_stack_trace, w, fwm) catch {};
335 std.debug.writeStackTrace(&step.debug_stack_trace, t) catch {};
335336 } else {
336337 const field = "debug_stack_frames_count";
337338 comptime assert(@hasField(Build, field));
338 fwm.setColor(w, .yellow) catch {};
339 t.setColor(.yellow) catch {};
339340 w.print("name: '{s}'. no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{step.name}) catch {};
340 fwm.setColor(w, .reset) catch {};
341 t.setColor(.reset) catch {};
341342 }
342343}
343344
lib/std/Build/Step/Compile.zig+9-8
......@@ -925,20 +925,21 @@ const CliNamedModules = struct {
925925fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking_step: ?*Step) ![]const u8 {
926926 const step = &compile.step;
927927 const b = step.owner;
928 const io = b.graph.io;
928 const graph = b.graph;
929 const io = graph.io;
929930 const maybe_path: ?*GeneratedFile = @field(compile, tag_name);
930931
931932 const generated_file = maybe_path orelse {
932 const stderr = try io.lockStderrWriter(&.{});
933 std.Build.dumpBadGetPathHelp(&compile.step, &stderr.interface, stderr.mode, compile.step.owner, asking_step) catch {};
934 io.unlockStderrWriter();
933 const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
934 std.Build.dumpBadGetPathHelp(&compile.step, stderr.terminal(), compile.step.owner, asking_step) catch {};
935 io.unlockStderr();
935936 @panic("missing emit option for " ++ tag_name);
936937 };
937938
938939 const path = generated_file.path orelse {
939 const stderr = try io.lockStderrWriter(&.{});
940 std.Build.dumpBadGetPathHelp(&compile.step, &stderr.interface, stderr.mode, compile.step.owner, asking_step) catch {};
941 io.unlockStderrWriter();
940 const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
941 std.Build.dumpBadGetPathHelp(&compile.step, stderr.terminal(), compile.step.owner, asking_step) catch {};
942 io.unlockStderr();
942943 @panic(tag_name ++ " is null. Is there a missing step dependency?");
943944 };
944945
......@@ -1907,7 +1908,7 @@ fn checkCompileErrors(compile: *Compile) !void {
19071908 try actual_eb.renderToWriter(.{
19081909 .include_reference_trace = false,
19091910 .include_source_line = false,
1910 }, &aw.writer, .streaming);
1911 }, &aw.writer);
19111912 break :ae try aw.toOwnedSlice();
19121913 };
19131914
lib/std/Build/Step/Run.zig+12-10
......@@ -1559,7 +1559,8 @@ fn spawnChildAndCollect(
15591559) !?EvalGenericResult {
15601560 const b = run.step.owner;
15611561 const arena = b.allocator;
1562 const io = b.graph.io;
1562 const graph = b.graph;
1563 const io = graph.io;
15631564
15641565 if (fuzz_context != null) {
15651566 assert(!has_side_effects);
......@@ -1625,11 +1626,12 @@ fn spawnChildAndCollect(
16251626 if (!run.disable_zig_progress and !inherit) {
16261627 child.progress_node = options.progress_node;
16271628 }
1628 if (inherit) {
1629 const stderr = try io.lockStderrWriter(&.{});
1630 try setColorEnvironmentVariables(run, env_map, stderr.mode);
1631 }
1632 defer if (inherit) io.unlockStderrWriter();
1629 const terminal_mode: Io.Terminal.Mode = if (inherit) m: {
1630 const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
1631 break :m stderr.terminal_mode;
1632 } else .no_color;
1633 defer if (inherit) io.unlockStderr();
1634 try setColorEnvironmentVariables(run, env_map, terminal_mode);
16331635 var timer = try std.time.Timer.start();
16341636 const res = try evalGeneric(run, &child);
16351637 run.step.result_duration_ns = timer.read();
......@@ -1637,7 +1639,7 @@ fn spawnChildAndCollect(
16371639 }
16381640}
16391641
1640fn setColorEnvironmentVariables(run: *Run, env_map: *EnvMap, fwm: Io.File.Writer.Mode) !void {
1642fn setColorEnvironmentVariables(run: *Run, env_map: *EnvMap, terminal_mode: Io.Terminal.Mode) !void {
16411643 color: switch (run.color) {
16421644 .manual => {},
16431645 .enable => {
......@@ -1648,9 +1650,9 @@ fn setColorEnvironmentVariables(run: *Run, env_map: *EnvMap, fwm: Io.File.Writer
16481650 try env_map.put("NO_COLOR", "1");
16491651 env_map.remove("CLICOLOR_FORCE");
16501652 },
1651 .inherit => switch (fwm) {
1652 .terminal_escaped => continue :color .enable,
1653 else => continue :color .disable,
1653 .inherit => switch (terminal_mode) {
1654 .no_color, .windows_api => continue :color .disable,
1655 .escape_codes => continue :color .enable,
16541656 },
16551657 .auto => {
16561658 const capture_stderr = run.captured_stderr != null or switch (run.stdio) {
lib/std/Io.zig+1-1
......@@ -713,7 +713,7 @@ pub const VTable = struct {
713713 processExecutableOpen: *const fn (?*anyopaque, File.OpenFlags) std.process.OpenExecutableError!File,
714714 processExecutablePath: *const fn (?*anyopaque, buffer: []u8) std.process.ExecutablePathError!usize,
715715 lockStderr: *const fn (?*anyopaque, buffer: []u8, ?Terminal.Mode) Cancelable!LockedStderr,
716 tryLockStderr: *const fn (?*anyopaque, buffer: []u8) Cancelable!?LockedStderr,
716 tryLockStderr: *const fn (?*anyopaque, buffer: []u8, ?Terminal.Mode) Cancelable!?LockedStderr,
717717 unlockStderr: *const fn (?*anyopaque) void,
718718
719719 now: *const fn (?*anyopaque, Clock) Clock.Error!Timestamp,
lib/std/Io/File/Writer.zig+1-1
......@@ -229,7 +229,7 @@ pub fn seekToUnbuffered(w: *Writer, offset: u64) SeekError!void {
229229 .positional, .positional_simple => {
230230 w.pos = offset;
231231 },
232 .streaming, .streaming_simple, .terminal_escaped, .terminal_winapi => {
232 .streaming, .streaming_simple => {
233233 if (w.seek_err) |err| return err;
234234 io.vtable.fileSeekTo(io.userdata, w.file, offset) catch |err| {
235235 w.seek_err = err;
lib/std/Io/Terminal.zig-22
......@@ -130,25 +130,3 @@ pub fn setColor(t: Terminal, color: Color) Io.Writer.Error!void {
130130 },
131131 }
132132}
133
134pub fn disableEscape(t: *Terminal) Mode {
135 const prev = t.mode;
136 t.mode = t.mode.toUnescaped();
137 return prev;
138}
139
140pub fn restoreEscape(t: *Terminal, mode: Mode) void {
141 t.mode = mode;
142}
143
144pub fn writeAllUnescaped(t: *Terminal, bytes: []const u8) Io.Writer.Error!void {
145 const prev_mode = t.disableEscape();
146 defer t.restoreEscape(prev_mode);
147 return t.interface.writeAll(bytes);
148}
149
150pub fn printUnescaped(t: *Terminal, comptime fmt: []const u8, args: anytype) Io.Writer.Error!void {
151 const prev_mode = t.disableEscape();
152 defer t.restoreEscape(prev_mode);
153 return t.interface.print(fmt, args);
154}
lib/std/Io/Threaded.zig+3-3
......@@ -7178,7 +7178,7 @@ fn fileWriteFileStreaming(
71787178 break :o .{ &off, @min(@intFromEnum(limit), size - file_reader.pos, max_count) };
71797179 },
71807180 .streaming => .{ null, limit.minInt(max_count) },
7181 .streaming_reading, .positional_reading => break :sf,
7181 .streaming_simple, .positional_simple => break :sf,
71827182 .failure => return error.ReadFailed,
71837183 };
71847184 const current_thread = Thread.getCurrent(t);
......@@ -7251,7 +7251,7 @@ fn fileWriteFileStreaming(
72517251 }
72527252 var off_in: i64 = undefined;
72537253 const off_in_ptr: ?*i64 = switch (file_reader.mode) {
7254 .positional_reading, .streaming_reading => return error.Unimplemented,
7254 .positional_simple, .streaming_simple => return error.Unimplemented,
72557255 .positional => p: {
72567256 off_in = @intCast(file_reader.pos);
72577257 break :p &off_in;
......@@ -7427,7 +7427,7 @@ fn fileWriteFilePositional(
74277427 }
74287428 var off_in: i64 = undefined;
74297429 const off_in_ptr: ?*i64 = switch (file_reader.mode) {
7430 .positional_reading, .streaming_reading => return error.Unimplemented,
7430 .positional_simple, .streaming_simple => return error.Unimplemented,
74317431 .positional => p: {
74327432 off_in = @intCast(file_reader.pos);
74337433 break :p &off_in;
lib/std/debug.zig+12-12
......@@ -283,12 +283,12 @@ var static_single_threaded_io: Io.Threaded = .init_single_threaded;
283283///
284284/// Alternatively, use the higher-level `Io.lockStderr` to integrate with the
285285/// application's chosen `Io` implementation.
286pub fn lockStderr(buffer: []u8) Io.Terminal {
287 return (static_single_threaded_io.ioBasic().lockStderr(buffer, null) catch |err| switch (err) {
286pub fn lockStderr(buffer: []u8) Io.LockedStderr {
287 return static_single_threaded_io.ioBasic().lockStderr(buffer, null) catch |err| switch (err) {
288288 // Impossible to cancel because no calls to cancel using
289289 // `static_single_threaded_io` exist.
290290 error.Canceled => unreachable,
291 }).terminal();
291 };
292292}
293293
294294pub fn unlockStderr() void {
......@@ -311,7 +311,7 @@ pub fn print(comptime fmt: []const u8, args: anytype) void {
311311 var buffer: [64]u8 = undefined;
312312 const stderr = lockStderr(&buffer);
313313 defer unlockStderr();
314 stderr.writer.print(fmt, args) catch return;
314 stderr.file_writer.interface.print(fmt, args) catch return;
315315 }
316316}
317317
......@@ -327,7 +327,7 @@ pub inline fn getSelfDebugInfo() !*SelfInfo {
327327/// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned.
328328/// Obtains the stderr mutex while dumping.
329329pub fn dumpHex(bytes: []const u8) void {
330 const stderr = lockStderr(&.{});
330 const stderr = lockStderr(&.{}).terminal();
331331 defer unlockStderr();
332332 dumpHexFallible(stderr, bytes) catch {};
333333}
......@@ -551,7 +551,7 @@ pub fn defaultPanic(
551551 _ = panicking.fetchAdd(1, .seq_cst);
552552
553553 trace: {
554 const stderr = lockStderr(&.{});
554 const stderr = lockStderr(&.{}).terminal();
555555 defer unlockStderr();
556556 const writer = stderr.writer;
557557
......@@ -581,7 +581,7 @@ pub fn defaultPanic(
581581 // A panic happened while trying to print a previous panic message.
582582 // We're still holding the mutex but that's fine as we're going to
583583 // call abort().
584 const stderr = lockStderr(&.{});
584 const stderr = lockStderr(&.{}).terminal();
585585 stderr.writer.writeAll("aborting due to recursive panic\n") catch {};
586586 },
587587 else => {}, // Panicked while printing the recursive panic message.
......@@ -751,7 +751,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin
751751}
752752/// A thin wrapper around `writeCurrentStackTrace` which writes to stderr and ignores write errors.
753753pub fn dumpCurrentStackTrace(options: StackUnwindOptions) void {
754 const stderr = lockStderr(&.{});
754 const stderr = lockStderr(&.{}).terminal();
755755 defer unlockStderr();
756756 writeCurrentStackTrace(.{
757757 .first_address = a: {
......@@ -814,7 +814,7 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void
814814}
815815/// A thin wrapper around `writeStackTrace` which writes to stderr and ignores write errors.
816816pub fn dumpStackTrace(st: *const StackTrace) void {
817 const stderr = lockStderr(&.{});
817 const stderr = lockStderr(&.{}).terminal();
818818 defer unlockStderr();
819819 writeStackTrace(st, stderr) catch |err| switch (err) {
820820 error.WriteFailed => {},
......@@ -1550,7 +1550,7 @@ pub fn defaultHandleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?CpuContex
15501550 _ = panicking.fetchAdd(1, .seq_cst);
15511551
15521552 trace: {
1553 const stderr = lockStderr(&.{});
1553 const stderr = lockStderr(&.{}).terminal();
15541554 defer unlockStderr();
15551555
15561556 if (addr) |a| {
......@@ -1571,7 +1571,7 @@ pub fn defaultHandleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?CpuContex
15711571 // A segfault happened while trying to print a previous panic message.
15721572 // We're still holding the mutex but that's fine as we're going to
15731573 // call abort().
1574 const stderr = lockStderr(&.{});
1574 const stderr = lockStderr(&.{}).terminal();
15751575 stderr.writer.writeAll("aborting due to recursive panic\n") catch {};
15761576 },
15771577 else => {}, // Panicked while printing the recursive panic message.
......@@ -1678,7 +1678,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
16781678 pub fn dump(t: @This()) void {
16791679 if (!enabled) return;
16801680
1681 const stderr = lockStderr(&.{});
1681 const stderr = lockStderr(&.{}).terminal();
16821682 defer unlockStderr();
16831683 const end = @min(t.index, size);
16841684 for (t.addrs[0..end], 0..) |frames_array, i| {
lib/std/debug/simple_panic.zig+3-3
......@@ -14,9 +14,9 @@ const std = @import("../std.zig");
1414pub fn call(msg: []const u8, ra: ?usize) noreturn {
1515 @branchHint(.cold);
1616 _ = ra;
17 const stderr = std.debug.lockStderrWriter(&.{});
18 stderr.interface.writeAll(msg) catch {};
19 stderr.interface.flush(msg) catch {};
17 const stderr_writer = std.debug.lockStderr(&.{}, null).terminal().writer;
18 stderr_writer.writeAll(msg) catch {};
19 stderr_writer.flush(msg) catch {};
2020 @trap();
2121}
2222
lib/std/json/dynamic.zig+3-3
......@@ -47,9 +47,9 @@ pub const Value = union(enum) {
4747 }
4848
4949 pub fn dump(v: Value) void {
50 const stderr = std.debug.lockStderrWriter(&.{});
51 defer std.debug.unlockStderrWriter();
52 json.Stringify.value(v, .{}, &stderr.interface) catch return;
50 const stderr = std.debug.lockStderr(&.{}, null);
51 defer std.debug.unlockStderr();
52 json.Stringify.value(v, .{}, &stderr.file_writer.interface) catch return;
5353 }
5454
5555 pub fn jsonStringify(value: @This(), jws: anytype) !void {
lib/std/log.zig+1-1
......@@ -92,7 +92,7 @@ pub fn defaultLog(
9292 args: anytype,
9393) void {
9494 var buffer: [64]u8 = undefined;
95 const stderr = std.debug.lockStderr(&buffer);
95 const stderr = std.debug.lockStderr(&buffer).terminal();
9696 defer std.debug.unlockStderr();
9797 return defaultLogFileTerminal(level, scope, format, args, stderr) catch {};
9898}
lib/std/process.zig+1-1
......@@ -1856,7 +1856,7 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 {
18561856/// and does not return.
18571857pub fn cleanExit(io: Io) void {
18581858 if (builtin.mode == .Debug) return;
1859 _ = io.lockStderrWriter(&.{}) catch {};
1859 _ = io.lockStderr(&.{}, .no_color) catch {};
18601860 exit(0);
18611861}
18621862
lib/std/testing.zig+11-10
......@@ -368,8 +368,8 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
368368 break :diff_index if (expected.len == actual.len) return else shortest;
369369 };
370370 if (!backend_can_print) return error.TestExpectedEqual;
371 if (io.lockStderrWriter(&.{})) |stderr| {
372 defer io.unlockStderrWriter();
371 if (io.lockStderr(&.{}, null)) |stderr| {
372 defer io.unlockStderr();
373373 failEqualSlices(T, expected, actual, diff_index, &stderr.interface, stderr.mode) catch {};
374374 } else |_| {}
375375 return error.TestExpectedEqual;
......@@ -381,7 +381,7 @@ fn failEqualSlices(
381381 actual: []const T,
382382 diff_index: usize,
383383 w: *Io.Writer,
384 fwm: Io.File.Writer.Mode,
384 terminal_mode: Io.Terminal.Mode,
385385) !void {
386386 try w.print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index });
387387
......@@ -404,12 +404,12 @@ fn failEqualSlices(
404404 var differ = if (T == u8) BytesDiffer{
405405 .expected = expected_window,
406406 .actual = actual_window,
407 .file_writer_mode = fwm,
407 .terminal_mode = terminal_mode,
408408 } else SliceDiffer(T){
409409 .start_index = window_start,
410410 .expected = expected_window,
411411 .actual = actual_window,
412 .file_writer_mode = fwm,
412 .terminal_mode = terminal_mode,
413413 };
414414
415415 // Print indexes as hex for slices of u8 since it's more likely to be binary data where
......@@ -466,21 +466,22 @@ fn SliceDiffer(comptime T: type) type {
466466 start_index: usize,
467467 expected: []const T,
468468 actual: []const T,
469 file_writer_mode: Io.File.Writer.Mode,
469 terminal_mode: Io.Terminal.Mode,
470470
471471 const Self = @This();
472472
473473 pub fn write(self: Self, writer: *Io.Writer) !void {
474 const t: Io.Terminal = .{ .writer = writer, .mode = self.terminal_mode };
474475 for (self.expected, 0..) |value, i| {
475476 const full_index = self.start_index + i;
476477 const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;
477 if (diff) try self.file_writer_mode.setColor(writer, .red);
478 if (diff) try t.setColor(writer, .red);
478479 if (@typeInfo(T) == .pointer) {
479480 try writer.print("[{}]{*}: {any}\n", .{ full_index, value, value });
480481 } else {
481482 try writer.print("[{}]: {any}\n", .{ full_index, value });
482483 }
483 if (diff) try self.file_writer_mode.setColor(writer, .reset);
484 if (diff) try t.setColor(writer, .reset);
484485 }
485486 }
486487 };
......@@ -489,7 +490,7 @@ fn SliceDiffer(comptime T: type) type {
489490const BytesDiffer = struct {
490491 expected: []const u8,
491492 actual: []const u8,
492 file_writer_mode: Io.File.Writer.Mode,
493 terminal_mode: Io.Terminal.Mode,
493494
494495 pub fn write(self: BytesDiffer, writer: *Io.Writer) !void {
495496 var expected_iterator = std.mem.window(u8, self.expected, 16, 16);
......@@ -516,7 +517,7 @@ const BytesDiffer = struct {
516517 try self.writeDiff(writer, "{c}", .{byte}, diff);
517518 } else {
518519 // TODO: remove this `if` when https://github.com/ziglang/zig/issues/7600 is fixed
519 if (self.file_writer_mode == .terminal_winapi) {
520 if (self.terminal_mode == .windows_api) {
520521 try self.writeDiff(writer, ".", .{}, diff);
521522 continue;
522523 }
lib/std/zig.zig+7-14
......@@ -46,25 +46,18 @@ pub const SrcHasher = std.crypto.hash.Blake3;
4646pub const SrcHash = [16]u8;
4747
4848pub const Color = enum {
49 /// Determine whether stderr is a terminal or not automatically.
49 /// Auto-detect whether stream supports terminal colors.
5050 auto,
51 /// Assume stderr is not a terminal.
51 /// Force-enable colors.
5252 off,
53 /// Assume stderr is a terminal.
53 /// Suppress colors.
5454 on,
5555
56 pub fn getTtyConf(color: Color, detected: Io.File.Writer.Mode) Io.File.Writer.Mode {
56 pub fn terminalMode(color: Color) ?Io.Terminal.Mode {
5757 return switch (color) {
58 .auto => detected,
59 .on => .terminal_escaped,
60 .off => .streaming,
61 };
62 }
63 pub fn detectTtyConf(color: Color, io: Io) Io.File.Writer.Mode {
64 return switch (color) {
65 .auto => .detect(io, .stderr()),
66 .on => .terminal_escaped,
67 .off => .streaming,
58 .auto => null,
59 .on => .escape_codes,
60 .off => .no_color,
6861 };
6962 }
7063};
lib/std/zig/ErrorBundle.zig+37-35
......@@ -166,51 +166,53 @@ pub const RenderToStderrError = Io.Cancelable || Io.File.Writer.Error;
166166
167167pub fn renderToStderr(eb: ErrorBundle, io: Io, options: RenderOptions, color: std.zig.Color) RenderToStderrError!void {
168168 var buffer: [256]u8 = undefined;
169 const stderr = try io.lockStderrWriter(&buffer);
170 defer io.unlockStderrWriter();
171 renderToWriter(eb, options, &stderr.interface, color.getTtyConf(stderr.mode)) catch |err| switch (err) {
172 error.WriteFailed => return stderr.err.?,
169 const stderr = try io.lockStderr(&buffer, color.terminalMode());
170 defer io.unlockStderr();
171 renderToTerminal(eb, options, stderr.terminal()) catch |err| switch (err) {
172 error.WriteFailed => return stderr.file_writer.err.?,
173173 else => |e| return e,
174174 };
175175}
176176
177pub fn renderToWriter(
178 eb: ErrorBundle,
179 options: RenderOptions,
180 w: *Writer,
181 fwm: Io.File.Writer.Mode,
182) Io.File.Writer.Mode.SetColorError!void {
177pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, w: *Writer) Writer.Error!void {
178 return renderToTerminal(eb, options, .{ .writer = w, .mode = .no_color }) catch |err| switch (err) {
179 error.WriteFailed => |e| return e,
180 else => unreachable,
181 };
182}
183
184pub fn renderToTerminal(eb: ErrorBundle, options: RenderOptions, t: Io.Terminal) Io.Terminal.SetColorError!void {
183185 if (eb.extra.len == 0) return;
184186 for (eb.getMessages()) |err_msg| {
185 try renderErrorMessageToWriter(eb, options, err_msg, w, fwm, "error", .red, 0);
187 try renderErrorMessage(eb, options, err_msg, t, "error", .red, 0);
186188 }
187189
188190 if (options.include_log_text) {
189191 const log_text = eb.getCompileLogOutput();
190192 if (log_text.len != 0) {
191 try w.writeAll("\nCompile Log Output:\n");
192 try w.writeAll(log_text);
193 try t.writer.writeAll("\nCompile Log Output:\n");
194 try t.writer.writeAll(log_text);
193195 }
194196 }
195197}
196198
197fn renderErrorMessageToWriter(
199fn renderErrorMessage(
198200 eb: ErrorBundle,
199201 options: RenderOptions,
200202 err_msg_index: MessageIndex,
201 w: *Writer,
202 fwm: Io.File.Writer.Mode,
203 t: Io.Terminal,
203204 kind: []const u8,
204 color: Io.File.Writer.Color,
205 color: Io.Terminal.Color,
205206 indent: usize,
206) Io.File.Writer.Mode.SetColorError!void {
207) Io.Terminal.SetColorError!void {
208 const w = t.writer;
207209 const err_msg = eb.getErrorMessage(err_msg_index);
208210 if (err_msg.src_loc != .none) {
209211 const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
210212 var prefix: Writer.Discarding = .init(&.{});
211213 try w.splatByteAll(' ', indent);
212214 prefix.count += indent;
213 try fwm.setColor(w, .bold);
215 try t.setColor(.bold);
214216 try w.print("{s}:{d}:{d}: ", .{
215217 eb.nullTerminatedString(src.data.src_path),
216218 src.data.line + 1,
......@@ -221,7 +223,7 @@ fn renderErrorMessageToWriter(
221223 src.data.line + 1,
222224 src.data.column + 1,
223225 });
224 try fwm.setColor(w, color);
226 try t.setColor(color);
225227 try w.writeAll(kind);
226228 prefix.count += kind.len;
227229 try w.writeAll(": ");
......@@ -229,17 +231,17 @@ fn renderErrorMessageToWriter(
229231 // This is the length of the part before the error message:
230232 // e.g. "file.zig:4:5: error: "
231233 const prefix_len: usize = @intCast(prefix.count);
232 try fwm.setColor(w, .reset);
233 try fwm.setColor(w, .bold);
234 try t.setColor(.reset);
235 try t.setColor(.bold);
234236 if (err_msg.count == 1) {
235237 try writeMsg(eb, err_msg, w, prefix_len);
236238 try w.writeByte('\n');
237239 } else {
238240 try writeMsg(eb, err_msg, w, prefix_len);
239 try fwm.setColor(w, .dim);
241 try t.setColor(.dim);
240242 try w.print(" ({d} times)\n", .{err_msg.count});
241243 }
242 try fwm.setColor(w, .reset);
244 try t.setColor(.reset);
243245 if (src.data.source_line != 0 and options.include_source_line) {
244246 const line = eb.nullTerminatedString(src.data.source_line);
245247 for (line) |b| switch (b) {
......@@ -252,19 +254,19 @@ fn renderErrorMessageToWriter(
252254 // -1 since span.main includes the caret
253255 const after_caret = src.data.span_end -| src.data.span_main -| 1;
254256 try w.splatByteAll(' ', src.data.column - before_caret);
255 try fwm.setColor(w, .green);
257 try t.setColor(.green);
256258 try w.splatByteAll('~', before_caret);
257259 try w.writeByte('^');
258260 try w.splatByteAll('~', after_caret);
259261 try w.writeByte('\n');
260 try fwm.setColor(w, .reset);
262 try t.setColor(.reset);
261263 }
262264 for (eb.getNotes(err_msg_index)) |note| {
263 try renderErrorMessageToWriter(eb, options, note, w, fwm, "note", .cyan, indent);
265 try renderErrorMessage(eb, options, note, t, "note", .cyan, indent);
264266 }
265267 if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
266 try fwm.setColor(w, .reset);
267 try fwm.setColor(w, .dim);
268 try t.setColor(.reset);
269 try t.setColor(.dim);
268270 try w.print("referenced by:\n", .{});
269271 var ref_index = src.end;
270272 for (0..src.data.reference_trace_len) |_| {
......@@ -291,25 +293,25 @@ fn renderErrorMessageToWriter(
291293 );
292294 }
293295 }
294 try fwm.setColor(w, .reset);
296 try t.setColor(.reset);
295297 }
296298 } else {
297 try fwm.setColor(w, color);
299 try t.setColor(color);
298300 try w.splatByteAll(' ', indent);
299301 try w.writeAll(kind);
300302 try w.writeAll(": ");
301 try fwm.setColor(w, .reset);
303 try t.setColor(.reset);
302304 const msg = eb.nullTerminatedString(err_msg.msg);
303305 if (err_msg.count == 1) {
304306 try w.print("{s}\n", .{msg});
305307 } else {
306308 try w.print("{s}", .{msg});
307 try fwm.setColor(w, .dim);
309 try t.setColor(.dim);
308310 try w.print(" ({d} times)\n", .{err_msg.count});
309311 }
310 try fwm.setColor(w, .reset);
312 try t.setColor(.reset);
311313 for (eb.getNotes(err_msg_index)) |note| {
312 try renderErrorMessageToWriter(eb, options, note, w, fwm, "note", .cyan, indent + 4);
314 try renderErrorMessage(eb, options, note, t, "note", .cyan, indent + 4);
313315 }
314316 }
315317}
lib/std/zig/parser_test.zig+8-8
......@@ -6333,25 +6333,25 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined;
63336333
63346334fn testParse(io: Io, source: [:0]const u8, allocator: Allocator, anything_changed: *bool) ![]u8 {
63356335 var buffer: [64]u8 = undefined;
6336 const stderr = try io.lockStderrWriter(&buffer);
6337 defer io.unlockStderrWriter();
6336 const stderr = try io.lockStderr(&buffer, null);
6337 defer io.unlockStderr();
63386338
63396339 var tree = try std.zig.Ast.parse(allocator, source, .zig);
63406340 defer tree.deinit(allocator);
63416341
63426342 for (tree.errors) |parse_error| {
63436343 const loc = tree.tokenLocation(0, parse_error.token);
6344 try stderr.printUnescaped("(memory buffer):{d}:{d}: error: ", .{ loc.line + 1, loc.column + 1 });
6345 try tree.renderError(parse_error, &stderr.interface);
6346 try stderr.interface.print("\n{s}\n", .{source[loc.line_start..loc.line_end]});
6344 try stderr.writer.print("(memory buffer):{d}:{d}: error: ", .{ loc.line + 1, loc.column + 1 });
6345 try tree.renderError(parse_error, stderr.writer);
6346 try stderr.writer.print("\n{s}\n", .{source[loc.line_start..loc.line_end]});
63476347 {
63486348 var i: usize = 0;
63496349 while (i < loc.column) : (i += 1) {
6350 try stderr.writeAllUnescaped(" ");
6350 try stderr.writer.writeAll(" ");
63516351 }
6352 try stderr.writeAllUnescaped("^");
6352 try stderr.writer.writeAll("^");
63536353 }
6354 try stderr.writeAllUnescaped("\n");
6354 try stderr.writer.writeAll("\n");
63556355 }
63566356 if (tree.errors.len != 0) {
63576357 return error.ParseError;
src/Air/print.zig+6-6
......@@ -76,9 +76,9 @@ pub fn dump(air: Air, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
7676 const comp = pt.zcu.comp;
7777 const io = comp.io;
7878 var buffer: [512]u8 = undefined;
79 const stderr = try io.lockStderrWriter(&buffer);
80 defer io.unlockStderrWriter();
81 const w = &stderr.interface;
79 const stderr = try io.lockStderr(&buffer, null);
80 defer io.unlockStderr();
81 const w = &stderr.file_writer.interface;
8282 air.write(w, pt, liveness);
8383}
8484
......@@ -86,9 +86,9 @@ pub fn dumpInst(air: Air, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Ai
8686 const comp = pt.zcu.comp;
8787 const io = comp.io;
8888 var buffer: [512]u8 = undefined;
89 const stderr = try io.lockStderrWriter(&buffer);
90 defer io.unlockStderrWriter();
91 const w = &stderr.interface;
89 const stderr = try io.lockStderr(&buffer, null);
90 defer io.unlockStderr();
91 const w = &stderr.file_writer.interface;
9292 air.writeInst(w, inst, pt, liveness);
9393}
9494
src/Compilation.zig+30-15
......@@ -2092,14 +2092,16 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
20922092 }
20932093
20942094 if (options.verbose_llvm_cpu_features) {
2095 if (options.root_mod.resolved_target.llvm_cpu_features) |cf| print: {
2096 const stderr = try io.lockStderrWriter(&.{});
2097 defer io.unlockStderrWriter();
2098 const w = &stderr.interface;
2099 w.print("compilation: {s}\n", .{options.root_name}) catch break :print;
2100 w.print(" target: {s}\n", .{try target.zigTriple(arena)}) catch break :print;
2101 w.print(" cpu: {s}\n", .{target.cpu.model.name}) catch break :print;
2102 w.print(" features: {s}\n", .{cf}) catch {};
2095 if (options.root_mod.resolved_target.llvm_cpu_features) |cf| {
2096 const stderr = try io.lockStderr(&.{}, null);
2097 defer io.unlockStderr();
2098 const w = &stderr.file_writer.interface;
2099 printVerboseLlvmCpuFeatures(w, arena, options.root_name, target, cf) catch |err| switch (err) {
2100 error.WriteFailed => switch (stderr.file_writer.err.?) {
2101 error.Canceled => |e| return e,
2102 else => {},
2103 },
2104 };
21032105 }
21042106 }
21052107
......@@ -2700,6 +2702,19 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
27002702 return comp;
27012703}
27022704
2705fn printVerboseLlvmCpuFeatures(
2706 w: *Writer,
2707 arena: Allocator,
2708 root_name: []const u8,
2709 target: *const std.Target,
2710 cf: [*:0]const u8,
2711) Writer.Error!void {
2712 try w.print("compilation: {s}\n", .{root_name});
2713 try w.print(" target: {s}\n", .{try target.zigTriple(arena)});
2714 try w.print(" cpu: {s}\n", .{target.cpu.model.name});
2715 try w.print(" features: {s}\n", .{cf});
2716}
2717
27032718pub fn destroy(comp: *Compilation) void {
27042719 const gpa = comp.gpa;
27052720 const io = comp.io;
......@@ -4259,9 +4274,9 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
42594274 // However, we haven't reported any such error.
42604275 // This is a compiler bug.
42614276 print_ctx: {
4262 const stderr = std.debug.lockStderrWriter(&.{});
4263 defer std.debug.unlockStderrWriter();
4264 const w = &stderr.interface;
4277 const stderr = std.debug.lockStderr(&.{}).terminal();
4278 defer std.debug.unlockStderr();
4279 const w = stderr.writer;
42654280 w.writeAll("referenced transitive analysis errors, but none actually emitted\n") catch break :print_ctx;
42664281 w.print("{f} [transitive failure]\n", .{zcu.fmtAnalUnit(failed_unit)}) catch break :print_ctx;
42674282 while (ref) |r| {
......@@ -7772,11 +7787,11 @@ pub fn lockAndSetMiscFailure(
77727787
77737788pub fn dumpArgv(io: Io, argv: []const []const u8) Io.Cancelable!void {
77747789 var buffer: [64]u8 = undefined;
7775 const stderr = try io.lockStderrWriter(&buffer);
7776 defer io.unlockStderrWriter();
7777 const w = &stderr.interface;
7790 const stderr = try io.lockStderr(&buffer);
7791 defer io.unlockStderr();
7792 const w = &stderr.file_writer.interface;
77787793 return dumpArgvWriter(w, argv) catch |err| switch (err) {
7779 error.WriteFailed => switch (stderr.err.?) {
7794 error.WriteFailed => switch (stderr.file_writer.err.?) {
77807795 error.Canceled => return error.Canceled,
77817796 else => return,
77827797 },
src/InternPool.zig+5-5
......@@ -11169,9 +11169,9 @@ pub fn mutateVarInit(ip: *InternPool, io: Io, index: Index, init_index: Index) v
1116911169
1117011170pub fn dump(ip: *const InternPool, io: Io) Io.Cancelable!void {
1117111171 var buffer: [4096]u8 = undefined;
11172 const stderr_writer = try io.lockStderrWriter(&buffer);
11173 defer io.unlockStderrWriter();
11174 const w = &stderr_writer.interface;
11172 const stderr = try io.lockStderr(&buffer, null);
11173 defer io.unlockStderr();
11174 const w = &stderr.file_writer.interface;
1117511175 try dumpStatsFallible(ip, w, std.heap.page_allocator);
1117611176 try dumpAllFallible(ip, w);
1117711177}
......@@ -11536,8 +11536,8 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
1153611536
1153711537pub fn dumpGenericInstances(ip: *const InternPool, io: Io, allocator: Allocator) Io.Cancelable!void {
1153811538 var buffer: [4096]u8 = undefined;
11539 const stderr_writer = try io.lockStderrWriter(&buffer);
11540 defer io.unlockStderrWriter();
11539 const stderr_writer = try io.lockStderr(&buffer, null);
11540 defer io.unlockStderr();
1154111541 const w = &stderr_writer.interface;
1154211542 try ip.dumpGenericInstancesFallible(allocator, w);
1154311543}
src/Zcu/PerThread.zig+4-4
......@@ -4560,10 +4560,10 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
45604560
45614561 if (build_options.enable_debug_extensions and comp.verbose_air) p: {
45624562 const io = comp.io;
4563 const stderr = try io.lockStderrWriter(&.{});
4564 defer io.unlockStderrWriter();
4565 printVerboseAir(pt, liveness, fqn, air, &stderr.interface) catch |err| switch (err) {
4566 error.WriteFailed => switch (stderr.err.?) {
4563 const stderr = try io.lockStderr(&.{}, null);
4564 defer io.unlockStderr();
4565 printVerboseAir(pt, liveness, fqn, air, &stderr.file_writer.interface) catch |err| switch (err) {
4566 error.WriteFailed => switch (stderr.file_writer.err.?) {
45674567 error.Canceled => |e| return e,
45684568 else => break :p,
45694569 },
src/codegen/aarch64/Select.zig+3-4
......@@ -11274,16 +11274,15 @@ fn initValueAdvanced(
1127411274}
1127511275pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void {
1127611276 const zcu = isel.pt.zcu;
11277 const io = zcu.comp.io;
1127811277 const gpa = zcu.gpa;
1127911278 const ip = &zcu.intern_pool;
1128011279 const nav = ip.getNav(isel.nav_index);
1128111280
1128211281 errdefer |err| @panic(@errorName(err));
1128311282
11284 const stderr_writer = io.lockStderrWriter(&.{}) catch return;
11285 defer io.unlockStderrWriter();
11286 const stderr = &stderr_writer.interface;
11283 const locked_stderr = std.debug.lockStderr(&.{}, null);
11284 defer std.debug.unlockStderr();
11285 const stderr = &locked_stderr.file_writer.interface;
1128711286
1128811287 var reverse_live_values: std.AutoArrayHashMapUnmanaged(Value.Index, std.ArrayList(Air.Inst.Index)) = .empty;
1128911288 defer {
src/crash_report.zig+3-3
......@@ -95,9 +95,9 @@ fn dumpCrashContext() Io.Writer.Error!void {
9595
9696 // TODO: this does mean that a different thread could grab the stderr mutex between the context
9797 // and the actual panic printing, which would be quite confusing.
98 const stderr = std.debug.lockStderrWriter(&.{});
99 defer std.debug.unlockStderrWriter();
100 const w = &stderr.interface;
98 const stderr = std.debug.lockStderr(&.{});
99 defer std.debug.unlockStderr();
100 const w = &stderr.file_writer.interface;
101101
102102 try w.writeAll("Compiler crash context:\n");
103103
src/libs/mingw.zig+12-12
......@@ -314,14 +314,14 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
314314
315315 if (comp.verbose_cc) {
316316 var buffer: [256]u8 = undefined;
317 const stderr = try io.lockStderrWriter(&buffer);
318 defer io.unlockStderrWriter();
319 const w = &stderr.interface;
317 const stderr = try io.lockStderr(&buffer, null);
318 defer io.unlockStderr();
319 const w = &stderr.file_writer.interface;
320320 w.print("def file: {s}\n", .{def_file_path}) catch |err| switch (err) {
321 error.WriteFailed => return stderr.err.?,
321 error.WriteFailed => return stderr.file_writer.err.?,
322322 };
323323 w.print("include dir: {s}\n", .{include_dir}) catch |err| switch (err) {
324 error.WriteFailed => return stderr.err.?,
324 error.WriteFailed => return stderr.file_writer.err.?,
325325 };
326326 }
327327
......@@ -339,12 +339,12 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
339339
340340 if (aro_comp.diagnostics.output.to_list.messages.items.len != 0) {
341341 var buffer: [64]u8 = undefined;
342 const stderr = try io.lockStderrWriter(&buffer);
343 defer io.unlockStderrWriter();
342 const stderr = try io.lockStderr(&buffer, null);
343 defer io.unlockStderr();
344344 for (aro_comp.diagnostics.output.to_list.messages.items) |msg| {
345345 if (msg.kind == .@"fatal error" or msg.kind == .@"error") {
346 msg.write(&stderr.interface, stderr.mode, true) catch |err| switch (err) {
347 error.WriteFailed => return stderr.err.?,
346 msg.write(stderr.terminal(), true) catch |err| switch (err) {
347 error.WriteFailed => return stderr.file_writer.err.?,
348348 };
349349 return error.AroPreprocessorFailed;
350350 }
......@@ -365,9 +365,9 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
365365 error.OutOfMemory => |e| return e,
366366 error.ParseError => {
367367 var buffer: [64]u8 = undefined;
368 const stderr = try io.lockStderrWriter(&buffer);
369 defer io.unlockStderrWriter();
370 const w = &stderr.interface;
368 const stderr = try io.lockStderr(&buffer, null);
369 defer io.unlockStderr();
370 const w = &stderr.file_writer.interface;
371371 try w.writeAll("error: ");
372372 try def_diagnostics.writeMsg(w, input);
373373 try w.writeByte('\n');
src/libs/mingw/def.zig+3-3
......@@ -1039,9 +1039,9 @@ fn testParse(
10391039 const module = parse(std.testing.allocator, source, machine_type, .mingw, &diagnostics) catch |err| switch (err) {
10401040 error.OutOfMemory => |e| return e,
10411041 error.ParseError => {
1042 const stderr = try io.lockStderrWriter(&.{});
1043 defer io.unlockStderrWriter();
1044 const w = &stderr.interface;
1042 const stderr = try io.lockStderr(&.{}, null);
1043 defer io.unlockStderr();
1044 const w = &stderr.file_writer.interface;
10451045 try diagnostics.writeMsg(w, source);
10461046 try w.writeByte('\n');
10471047 return err;
src/link/Coff.zig+3-3
......@@ -2382,9 +2382,9 @@ pub fn dump(coff: *Coff, tid: Zcu.PerThread.Id) Io.Cancelable!void {
23822382 const comp = coff.base.comp;
23832383 const io = comp.io;
23842384 var buffer: [512]u8 = undefined;
2385 const stderr = try io.lockStderrWriter(&buffer);
2386 defer io.unlockStderrWriter();
2387 const w = &stderr.interface;
2385 const stderr = try io.lockStderr(&buffer, null);
2386 defer io.unlockStderr();
2387 const w = &stderr.file_writer.interface;
23882388 coff.printNode(tid, w, .root, 0) catch |err| switch (err) {
23892389 error.WriteFailed => return stderr.err.?,
23902390 };
src/link/Elf2.zig+3-3
......@@ -3733,9 +3733,9 @@ pub fn dump(elf: *Elf, tid: Zcu.PerThread.Id) Io.Cancelable!void {
37333733 const comp = elf.base.comp;
37343734 const io = comp.io;
37353735 var buffer: [512]u8 = undefined;
3736 const stderr = try io.lockStderrWriter(&buffer);
3737 defer io.unlockStderrWriter();
3738 const w = &stderr.interface;
3736 const stderr = try io.lockStderr(&buffer, null);
3737 defer io.lockStderr();
3738 const w = &stderr.file_writer.interface;
37393739 elf.printNode(tid, w, .root, 0) catch |err| switch (err) {
37403740 error.WriteFailed => return stderr.err.?,
37413741 };
src/main.zig+6-6
......@@ -4429,9 +4429,9 @@ fn runOrTest(
44294429 // the error message and invocation below.
44304430 if (process.can_execv and arg_mode == .run) {
44314431 // execv releases the locks; no need to destroy the Compilation here.
4432 _ = try io.lockStderrWriter(&.{});
4432 _ = try io.lockStderr(&.{}, .no_color);
44334433 const err = process.execve(gpa, argv.items, &env_map);
4434 io.unlockStderrWriter();
4434 io.unlockStderr();
44354435 try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc);
44364436 const cmd = try std.mem.join(arena, " ", argv.items);
44374437 fatal("the following command failed to execve with '{t}':\n{s}", .{ err, cmd });
......@@ -4448,8 +4448,8 @@ fn runOrTest(
44484448 comp_destroyed.* = true;
44494449
44504450 const term_result = t: {
4451 _ = try io.lockStderrWriter(&.{});
4452 defer io.unlockStderrWriter();
4451 _ = try io.lockStderr(&.{}, .no_color);
4452 defer io.unlockStderr();
44534453 break :t child.spawnAndWait(io);
44544454 };
44554455 const term = term_result catch |err| {
......@@ -5418,8 +5418,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
54185418 child.stderr_behavior = .Inherit;
54195419
54205420 const term = t: {
5421 _ = try io.lockStderrWriter(&.{});
5422 defer io.unlockStderrWriter();
5421 _ = try io.lockStderr(&.{}, .no_color);
5422 defer io.unlockStderr();
54235423 break :t child.spawnAndWait(io) catch |err|
54245424 fatal("failed to spawn build runner {s}: {t}", .{ child_argv.items[0], err });
54255425 };