authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-10 20:55:11-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:09-08:00
logb042e935228db5d46271d4d3d17afeb9ba5d7ce3
treefd02941ee06e6abed96f0f1193a27ce1dfe41cc3
parent7837d975dcaa17ff22f536607c4ff6db7b697b04

std: update tty config references in the build system


13 files changed, 271 insertions(+), 294 deletions(-)

lib/compiler/build_runner.zig+99-109
...@@ -14,7 +14,6 @@ const WebServer = std.Build.WebServer;...@@ -14,7 +14,6 @@ const WebServer = std.Build.WebServer;
14const Allocator = std.mem.Allocator;14const Allocator = std.mem.Allocator;
15const fatal = std.process.fatal;15const fatal = std.process.fatal;
16const Writer = std.Io.Writer;16const Writer = std.Io.Writer;
17const tty = std.Io.tty;
1817
19pub const root = @import("@build");18pub const root = @import("@build");
20pub const dependencies = @import("@dependencies");19pub const dependencies = @import("@dependencies");
...@@ -435,9 +434,7 @@ pub fn main() !void {...@@ -435,9 +434,7 @@ pub fn main() !void {
435 if (builtin.single_threaded) fatal("'--webui' is not yet supported on single-threaded hosts", .{});434 if (builtin.single_threaded) fatal("'--webui' is not yet supported on single-threaded hosts", .{});
436 }435 }
437436
438 const ttyconf = color.detectTtyConf(io);437 const main_progress_node = std.Progress.start(io, .{
439
440 const main_progress_node = std.Progress.start(.{
441 .disable_printing = (color == .off),438 .disable_printing = (color == .off),
442 });439 });
443 defer main_progress_node.end();440 defer main_progress_node.end();
...@@ -509,8 +506,6 @@ pub fn main() !void {...@@ -509,8 +506,6 @@ pub fn main() !void {
509 .error_style = error_style,506 .error_style = error_style,
510 .multiline_errors = multiline_errors,507 .multiline_errors = multiline_errors,
511 .summary = summary orelse if (watch or webui_listen != null) .line else .failures,508 .summary = summary orelse if (watch or webui_listen != null) .line else .failures,
512
513 .ttyconf = ttyconf,
514 };509 };
515 defer {510 defer {
516 run.memory_blocked_steps.deinit(gpa);511 run.memory_blocked_steps.deinit(gpa);
...@@ -524,10 +519,10 @@ pub fn main() !void {...@@ -524,10 +519,10 @@ pub fn main() !void {
524519
525 prepare(arena, builder, targets.items, &run, graph.random_seed) catch |err| switch (err) {520 prepare(arena, builder, targets.items, &run, graph.random_seed) catch |err| switch (err) {
526 error.DependencyLoopDetected => {521 error.DependencyLoopDetected => {
527 // Perhaps in the future there could be an Advanced Options flag such as522 // Perhaps in the future there could be an Advanced Options flag
528 // --debug-build-runner-leaks which would make this code return instead of523 // such as --debug-build-runner-leaks which would make this code
529 // calling exit.524 // return instead of calling exit.
530 std.debug.lockStdErr();525 _ = std.debug.lockStderrWriter(&.{});
531 process.exit(1);526 process.exit(1);
532 },527 },
533 else => |e| return e,528 else => |e| return e,
...@@ -545,7 +540,6 @@ pub fn main() !void {...@@ -545,7 +540,6 @@ pub fn main() !void {
545 if (builtin.single_threaded) unreachable; // `fatal` above540 if (builtin.single_threaded) unreachable; // `fatal` above
546 break :ws .init(.{541 break :ws .init(.{
547 .gpa = gpa,542 .gpa = gpa,
548 .ttyconf = ttyconf,
549 .graph = &graph,543 .graph = &graph,
550 .all_steps = run.step_stack.keys(),544 .all_steps = run.step_stack.keys(),
551 .root_prog_node = main_progress_node,545 .root_prog_node = main_progress_node,
...@@ -560,9 +554,9 @@ pub fn main() !void {...@@ -560,9 +554,9 @@ pub fn main() !void {
560 }554 }
561555
562 rebuild: while (true) : (if (run.error_style.clearOnUpdate()) {556 rebuild: while (true) : (if (run.error_style.clearOnUpdate()) {
563 const bw, _ = std.debug.lockStderrWriter(&stdio_buffer_allocation);557 const stderr = std.debug.lockStderrWriter(&stdio_buffer_allocation);
564 defer std.debug.unlockStderrWriter();558 defer std.debug.unlockStderrWriter();
565 try bw.writeAll("\x1B[2J\x1B[3J\x1B[H");559 try stderr.writeAllUnescaped("\x1B[2J\x1B[3J\x1B[H");
566 }) {560 }) {
567 if (run.web_server) |*ws| ws.startBuild();561 if (run.web_server) |*ws| ws.startBuild();
568562
...@@ -663,9 +657,6 @@ const Run = struct {...@@ -663,9 +657,6 @@ const Run = struct {
663 memory_blocked_steps: std.ArrayList(*Step),657 memory_blocked_steps: std.ArrayList(*Step),
664 /// Allocated into `gpa`.658 /// Allocated into `gpa`.
665 step_stack: std.AutoArrayHashMapUnmanaged(*Step, void),659 step_stack: std.AutoArrayHashMapUnmanaged(*Step, void),
666 /// Similar to the `tty.Config` returned by `std.debug.lockStderrWriter`,
667 /// but also respects the '--color' flag.
668 ttyconf: tty.Config,
669660
670 claimed_rss: usize,661 claimed_rss: usize,
671 error_style: ErrorStyle,662 error_style: ErrorStyle,
...@@ -839,7 +830,6 @@ fn runStepNames(...@@ -839,7 +830,6 @@ fn runStepNames(
839 var f = std.Build.Fuzz.init(830 var f = std.Build.Fuzz.init(
840 gpa,831 gpa,
841 io,832 io,
842 run.ttyconf,
843 step_stack.keys(),833 step_stack.keys(),
844 parent_prog_node,834 parent_prog_node,
845 mode,835 mode,
...@@ -866,18 +856,20 @@ fn runStepNames(...@@ -866,18 +856,20 @@ fn runStepNames(
866 .none => break :summary,856 .none => break :summary,
867 }857 }
868858
869 const w, _ = std.debug.lockStderrWriter(&stdio_buffer_allocation);859 const stderr = std.debug.lockStderrWriter(&stdio_buffer_allocation);
870 defer std.debug.unlockStderrWriter();860 defer std.debug.unlockStderrWriter();
871 const ttyconf = run.ttyconf;861
862 const w = &stderr.interface;
863 const fwm = stderr.mode;
872864
873 const total_count = success_count + failure_count + pending_count + skipped_count;865 const total_count = success_count + failure_count + pending_count + skipped_count;
874 ttyconf.setColor(w, .cyan) catch {};866 fwm.setColor(w, .cyan) catch {};
875 ttyconf.setColor(w, .bold) catch {};867 fwm.setColor(w, .bold) catch {};
876 w.writeAll("Build Summary: ") catch {};868 w.writeAll("Build Summary: ") catch {};
877 ttyconf.setColor(w, .reset) catch {};869 fwm.setColor(w, .reset) catch {};
878 w.print("{d}/{d} steps succeeded", .{ success_count, total_count }) catch {};870 w.print("{d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
879 {871 {
880 ttyconf.setColor(w, .dim) catch {};872 fwm.setColor(w, .dim) catch {};
881 var first = true;873 var first = true;
882 if (skipped_count > 0) {874 if (skipped_count > 0) {
883 w.print("{s}{d} skipped", .{ if (first) " (" else ", ", skipped_count }) catch {};875 w.print("{s}{d} skipped", .{ if (first) " (" else ", ", skipped_count }) catch {};
...@@ -888,12 +880,12 @@ fn runStepNames(...@@ -888,12 +880,12 @@ fn runStepNames(
888 first = false;880 first = false;
889 }881 }
890 if (!first) w.writeByte(')') catch {};882 if (!first) w.writeByte(')') catch {};
891 ttyconf.setColor(w, .reset) catch {};883 fwm.setColor(w, .reset) catch {};
892 }884 }
893885
894 if (test_count > 0) {886 if (test_count > 0) {
895 w.print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};887 w.print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
896 ttyconf.setColor(w, .dim) catch {};888 fwm.setColor(w, .dim) catch {};
897 var first = true;889 var first = true;
898 if (test_skip_count > 0) {890 if (test_skip_count > 0) {
899 w.print("{s}{d} skipped", .{ if (first) " (" else ", ", test_skip_count }) catch {};891 w.print("{s}{d} skipped", .{ if (first) " (" else ", ", test_skip_count }) catch {};
...@@ -912,7 +904,7 @@ fn runStepNames(...@@ -912,7 +904,7 @@ fn runStepNames(
912 first = false;904 first = false;
913 }905 }
914 if (!first) w.writeByte(')') catch {};906 if (!first) w.writeByte(')') catch {};
915 ttyconf.setColor(w, .reset) catch {};907 fwm.setColor(w, .reset) catch {};
916 }908 }
917909
918 w.writeAll("\n") catch {};910 w.writeAll("\n") catch {};
...@@ -926,7 +918,7 @@ fn runStepNames(...@@ -926,7 +918,7 @@ fn runStepNames(
926 var print_node: PrintNode = .{ .parent = null };918 var print_node: PrintNode = .{ .parent = null };
927 if (step_names.len == 0) {919 if (step_names.len == 0) {
928 print_node.last = true;920 print_node.last = true;
929 printTreeStep(b, b.default_step, run, w, ttyconf, &print_node, &step_stack_copy) catch {};921 printTreeStep(b, b.default_step, run, w, fwm, &print_node, &step_stack_copy) catch {};
930 } else {922 } else {
931 const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {923 const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {
932 var i: usize = step_names.len;924 var i: usize = step_names.len;
...@@ -945,7 +937,7 @@ fn runStepNames(...@@ -945,7 +937,7 @@ fn runStepNames(
945 for (step_names, 0..) |step_name, i| {937 for (step_names, 0..) |step_name, i| {
946 const tls = b.top_level_steps.get(step_name).?;938 const tls = b.top_level_steps.get(step_name).?;
947 print_node.last = i + 1 == last_index;939 print_node.last = i + 1 == last_index;
948 printTreeStep(b, &tls.step, run, w, ttyconf, &print_node, &step_stack_copy) catch {};940 printTreeStep(b, &tls.step, run, w, fwm, &print_node, &step_stack_copy) catch {};
949 }941 }
950 }942 }
951 w.writeByte('\n') catch {};943 w.writeByte('\n') catch {};
...@@ -962,7 +954,7 @@ fn runStepNames(...@@ -962,7 +954,7 @@ fn runStepNames(
962 if (run.error_style.verboseContext()) break :code 1; // failure; print build command954 if (run.error_style.verboseContext()) break :code 1; // failure; print build command
963 break :code 2; // failure; do not print build command955 break :code 2; // failure; do not print build command
964 };956 };
965 std.debug.lockStdErr();957 _ = std.debug.lockStderrWriter(&.{});
966 process.exit(code);958 process.exit(code);
967}959}
968960
...@@ -971,31 +963,31 @@ const PrintNode = struct {...@@ -971,31 +963,31 @@ const PrintNode = struct {
971 last: bool = false,963 last: bool = false,
972};964};
973965
974fn printPrefix(node: *PrintNode, stderr: *Writer, ttyconf: tty.Config) !void {966fn printPrefix(node: *PrintNode, w: *Writer, fwm: File.Writer.Mode) !void {
975 const parent = node.parent orelse return;967 const parent = node.parent orelse return;
976 if (parent.parent == null) return;968 if (parent.parent == null) return;
977 try printPrefix(parent, stderr, ttyconf);969 try printPrefix(parent, w, fwm);
978 if (parent.last) {970 if (parent.last) {
979 try stderr.writeAll(" ");971 try w.writeAll(" ");
980 } else {972 } else {
981 try stderr.writeAll(switch (ttyconf) {973 try w.writeAll(switch (fwm) {
982 .no_color, .windows_api => "| ",974 .terminal_escaped => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │
983 .escape_codes => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │975 else => "| ",
984 });976 });
985 }977 }
986}978}
987979
988fn printChildNodePrefix(stderr: *Writer, ttyconf: tty.Config) !void {980fn printChildNodePrefix(w: *Writer, fwm: File.Writer.Mode) !void {
989 try stderr.writeAll(switch (ttyconf) {981 try w.writeAll(switch (fwm) {
990 .no_color, .windows_api => "+- ",982 .terminal_escaped => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
991 .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─983 else => "+- ",
992 });984 });
993}985}
994986
995fn printStepStatus(987fn printStepStatus(
996 s: *Step,988 s: *Step,
997 stderr: *Writer,989 stderr: *Writer,
998 ttyconf: tty.Config,990 fwm: File.Writer.Mode,
999 run: *const Run,991 run: *const Run,
1000) !void {992) !void {
1001 switch (s.state) {993 switch (s.state) {
...@@ -1005,13 +997,13 @@ fn printStepStatus(...@@ -1005,13 +997,13 @@ fn printStepStatus(
1005 .running => unreachable,997 .running => unreachable,
1006998
1007 .dependency_failure => {999 .dependency_failure => {
1008 try ttyconf.setColor(stderr, .dim);1000 try fwm.setColor(stderr, .dim);
1009 try stderr.writeAll(" transitive failure\n");1001 try stderr.writeAll(" transitive failure\n");
1010 try ttyconf.setColor(stderr, .reset);1002 try fwm.setColor(stderr, .reset);
1011 },1003 },
10121004
1013 .success => {1005 .success => {
1014 try ttyconf.setColor(stderr, .green);1006 try fwm.setColor(stderr, .green);
1015 if (s.result_cached) {1007 if (s.result_cached) {
1016 try stderr.writeAll(" cached");1008 try stderr.writeAll(" cached");
1017 } else if (s.test_results.test_count > 0) {1009 } else if (s.test_results.test_count > 0) {
...@@ -1019,19 +1011,19 @@ fn printStepStatus(...@@ -1019,19 +1011,19 @@ fn printStepStatus(
1019 assert(s.test_results.test_count == pass_count + s.test_results.skip_count);1011 assert(s.test_results.test_count == pass_count + s.test_results.skip_count);
1020 try stderr.print(" {d} pass", .{pass_count});1012 try stderr.print(" {d} pass", .{pass_count});
1021 if (s.test_results.skip_count > 0) {1013 if (s.test_results.skip_count > 0) {
1022 try ttyconf.setColor(stderr, .reset);1014 try fwm.setColor(stderr, .reset);
1023 try stderr.writeAll(", ");1015 try stderr.writeAll(", ");
1024 try ttyconf.setColor(stderr, .yellow);1016 try fwm.setColor(stderr, .yellow);
1025 try stderr.print("{d} skip", .{s.test_results.skip_count});1017 try stderr.print("{d} skip", .{s.test_results.skip_count});
1026 }1018 }
1027 try ttyconf.setColor(stderr, .reset);1019 try fwm.setColor(stderr, .reset);
1028 try stderr.print(" ({d} total)", .{s.test_results.test_count});1020 try stderr.print(" ({d} total)", .{s.test_results.test_count});
1029 } else {1021 } else {
1030 try stderr.writeAll(" success");1022 try stderr.writeAll(" success");
1031 }1023 }
1032 try ttyconf.setColor(stderr, .reset);1024 try fwm.setColor(stderr, .reset);
1033 if (s.result_duration_ns) |ns| {1025 if (s.result_duration_ns) |ns| {
1034 try ttyconf.setColor(stderr, .dim);1026 try fwm.setColor(stderr, .dim);
1035 if (ns >= std.time.ns_per_min) {1027 if (ns >= std.time.ns_per_min) {
1036 try stderr.print(" {d}m", .{ns / std.time.ns_per_min});1028 try stderr.print(" {d}m", .{ns / std.time.ns_per_min});
1037 } else if (ns >= std.time.ns_per_s) {1029 } else if (ns >= std.time.ns_per_s) {
...@@ -1043,11 +1035,11 @@ fn printStepStatus(...@@ -1043,11 +1035,11 @@ fn printStepStatus(
1043 } else {1035 } else {
1044 try stderr.print(" {d}ns", .{ns});1036 try stderr.print(" {d}ns", .{ns});
1045 }1037 }
1046 try ttyconf.setColor(stderr, .reset);1038 try fwm.setColor(stderr, .reset);
1047 }1039 }
1048 if (s.result_peak_rss != 0) {1040 if (s.result_peak_rss != 0) {
1049 const rss = s.result_peak_rss;1041 const rss = s.result_peak_rss;
1050 try ttyconf.setColor(stderr, .dim);1042 try fwm.setColor(stderr, .dim);
1051 if (rss >= 1000_000_000) {1043 if (rss >= 1000_000_000) {
1052 try stderr.print(" MaxRSS:{d}G", .{rss / 1000_000_000});1044 try stderr.print(" MaxRSS:{d}G", .{rss / 1000_000_000});
1053 } else if (rss >= 1000_000) {1045 } else if (rss >= 1000_000) {
...@@ -1057,25 +1049,25 @@ fn printStepStatus(...@@ -1057,25 +1049,25 @@ fn printStepStatus(
1057 } else {1049 } else {
1058 try stderr.print(" MaxRSS:{d}B", .{rss});1050 try stderr.print(" MaxRSS:{d}B", .{rss});
1059 }1051 }
1060 try ttyconf.setColor(stderr, .reset);1052 try fwm.setColor(stderr, .reset);
1061 }1053 }
1062 try stderr.writeAll("\n");1054 try stderr.writeAll("\n");
1063 },1055 },
1064 .skipped, .skipped_oom => |skip| {1056 .skipped, .skipped_oom => |skip| {
1065 try ttyconf.setColor(stderr, .yellow);1057 try fwm.setColor(stderr, .yellow);
1066 try stderr.writeAll(" skipped");1058 try stderr.writeAll(" skipped");
1067 if (skip == .skipped_oom) {1059 if (skip == .skipped_oom) {
1068 try stderr.writeAll(" (not enough memory)");1060 try stderr.writeAll(" (not enough memory)");
1069 try ttyconf.setColor(stderr, .dim);1061 try fwm.setColor(stderr, .dim);
1070 try stderr.print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });1062 try stderr.print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
1071 try ttyconf.setColor(stderr, .yellow);1063 try fwm.setColor(stderr, .yellow);
1072 }1064 }
1073 try stderr.writeAll("\n");1065 try stderr.writeAll("\n");
1074 try ttyconf.setColor(stderr, .reset);1066 try fwm.setColor(stderr, .reset);
1075 },1067 },
1076 .failure => {1068 .failure => {
1077 try printStepFailure(s, stderr, ttyconf, false);1069 try printStepFailure(s, stderr, fwm, false);
1078 try ttyconf.setColor(stderr, .reset);1070 try fwm.setColor(stderr, .reset);
1079 },1071 },
1080 }1072 }
1081}1073}
...@@ -1083,48 +1075,48 @@ fn printStepStatus(...@@ -1083,48 +1075,48 @@ fn printStepStatus(
1083fn printStepFailure(1075fn printStepFailure(
1084 s: *Step,1076 s: *Step,
1085 stderr: *Writer,1077 stderr: *Writer,
1086 ttyconf: tty.Config,1078 fwm: File.Writer.Mode,
1087 dim: bool,1079 dim: bool,
1088) !void {1080) !void {
1089 if (s.result_error_bundle.errorMessageCount() > 0) {1081 if (s.result_error_bundle.errorMessageCount() > 0) {
1090 try ttyconf.setColor(stderr, .red);1082 try fwm.setColor(stderr, .red);
1091 try stderr.print(" {d} errors\n", .{1083 try stderr.print(" {d} errors\n", .{
1092 s.result_error_bundle.errorMessageCount(),1084 s.result_error_bundle.errorMessageCount(),
1093 });1085 });
1094 } else if (!s.test_results.isSuccess()) {1086 } else if (!s.test_results.isSuccess()) {
1095 // These first values include all of the test "statuses". Every test is either passsed,1087 // These first values include all of the test "statuses". Every test is either passsed,
1096 // skipped, failed, crashed, or timed out.1088 // skipped, failed, crashed, or timed out.
1097 try ttyconf.setColor(stderr, .green);1089 try fwm.setColor(stderr, .green);
1098 try stderr.print(" {d} pass", .{s.test_results.passCount()});1090 try stderr.print(" {d} pass", .{s.test_results.passCount()});
1099 try ttyconf.setColor(stderr, .reset);1091 try fwm.setColor(stderr, .reset);
1100 if (dim) try ttyconf.setColor(stderr, .dim);1092 if (dim) try fwm.setColor(stderr, .dim);
1101 if (s.test_results.skip_count > 0) {1093 if (s.test_results.skip_count > 0) {
1102 try stderr.writeAll(", ");1094 try stderr.writeAll(", ");
1103 try ttyconf.setColor(stderr, .yellow);1095 try fwm.setColor(stderr, .yellow);
1104 try stderr.print("{d} skip", .{s.test_results.skip_count});1096 try stderr.print("{d} skip", .{s.test_results.skip_count});
1105 try ttyconf.setColor(stderr, .reset);1097 try fwm.setColor(stderr, .reset);
1106 if (dim) try ttyconf.setColor(stderr, .dim);1098 if (dim) try fwm.setColor(stderr, .dim);
1107 }1099 }
1108 if (s.test_results.fail_count > 0) {1100 if (s.test_results.fail_count > 0) {
1109 try stderr.writeAll(", ");1101 try stderr.writeAll(", ");
1110 try ttyconf.setColor(stderr, .red);1102 try fwm.setColor(stderr, .red);
1111 try stderr.print("{d} fail", .{s.test_results.fail_count});1103 try stderr.print("{d} fail", .{s.test_results.fail_count});
1112 try ttyconf.setColor(stderr, .reset);1104 try fwm.setColor(stderr, .reset);
1113 if (dim) try ttyconf.setColor(stderr, .dim);1105 if (dim) try fwm.setColor(stderr, .dim);
1114 }1106 }
1115 if (s.test_results.crash_count > 0) {1107 if (s.test_results.crash_count > 0) {
1116 try stderr.writeAll(", ");1108 try stderr.writeAll(", ");
1117 try ttyconf.setColor(stderr, .red);1109 try fwm.setColor(stderr, .red);
1118 try stderr.print("{d} crash", .{s.test_results.crash_count});1110 try stderr.print("{d} crash", .{s.test_results.crash_count});
1119 try ttyconf.setColor(stderr, .reset);1111 try fwm.setColor(stderr, .reset);
1120 if (dim) try ttyconf.setColor(stderr, .dim);1112 if (dim) try fwm.setColor(stderr, .dim);
1121 }1113 }
1122 if (s.test_results.timeout_count > 0) {1114 if (s.test_results.timeout_count > 0) {
1123 try stderr.writeAll(", ");1115 try stderr.writeAll(", ");
1124 try ttyconf.setColor(stderr, .red);1116 try fwm.setColor(stderr, .red);
1125 try stderr.print("{d} timeout", .{s.test_results.timeout_count});1117 try stderr.print("{d} timeout", .{s.test_results.timeout_count});
1126 try ttyconf.setColor(stderr, .reset);1118 try fwm.setColor(stderr, .reset);
1127 if (dim) try ttyconf.setColor(stderr, .dim);1119 if (dim) try fwm.setColor(stderr, .dim);
1128 }1120 }
1129 try stderr.print(" ({d} total)", .{s.test_results.test_count});1121 try stderr.print(" ({d} total)", .{s.test_results.test_count});
11301122
...@@ -1134,10 +1126,10 @@ fn printStepFailure(...@@ -1134,10 +1126,10 @@ fn printStepFailure(
1134 // 2 pass, 1 skip, 2 fail (5 total); 2 leaks1126 // 2 pass, 1 skip, 2 fail (5 total); 2 leaks
1135 if (s.test_results.leak_count > 0) {1127 if (s.test_results.leak_count > 0) {
1136 try stderr.writeAll("; ");1128 try stderr.writeAll("; ");
1137 try ttyconf.setColor(stderr, .red);1129 try fwm.setColor(stderr, .red);
1138 try stderr.print("{d} leaks", .{s.test_results.leak_count});1130 try stderr.print("{d} leaks", .{s.test_results.leak_count});
1139 try ttyconf.setColor(stderr, .reset);1131 try fwm.setColor(stderr, .reset);
1140 if (dim) try ttyconf.setColor(stderr, .dim);1132 if (dim) try fwm.setColor(stderr, .dim);
1141 }1133 }
11421134
1143 // It's usually not helpful to know how many error logs there were because they tend to1135 // It's usually not helpful to know how many error logs there were because they tend to
...@@ -1151,19 +1143,19 @@ fn printStepFailure(...@@ -1151,19 +1143,19 @@ fn printStepFailure(
1151 };1143 };
1152 if (show_err_logs) {1144 if (show_err_logs) {
1153 try stderr.writeAll("; ");1145 try stderr.writeAll("; ");
1154 try ttyconf.setColor(stderr, .red);1146 try fwm.setColor(stderr, .red);
1155 try stderr.print("{d} error logs", .{s.test_results.log_err_count});1147 try stderr.print("{d} error logs", .{s.test_results.log_err_count});
1156 try ttyconf.setColor(stderr, .reset);1148 try fwm.setColor(stderr, .reset);
1157 if (dim) try ttyconf.setColor(stderr, .dim);1149 if (dim) try fwm.setColor(stderr, .dim);
1158 }1150 }
11591151
1160 try stderr.writeAll("\n");1152 try stderr.writeAll("\n");
1161 } else if (s.result_error_msgs.items.len > 0) {1153 } else if (s.result_error_msgs.items.len > 0) {
1162 try ttyconf.setColor(stderr, .red);1154 try fwm.setColor(stderr, .red);
1163 try stderr.writeAll(" failure\n");1155 try stderr.writeAll(" failure\n");
1164 } else {1156 } else {
1165 assert(s.result_stderr.len > 0);1157 assert(s.result_stderr.len > 0);
1166 try ttyconf.setColor(stderr, .red);1158 try fwm.setColor(stderr, .red);
1167 try stderr.writeAll(" stderr\n");1159 try stderr.writeAll(" stderr\n");
1168 }1160 }
1169}1161}
...@@ -1173,7 +1165,7 @@ fn printTreeStep(...@@ -1173,7 +1165,7 @@ fn printTreeStep(
1173 s: *Step,1165 s: *Step,
1174 run: *const Run,1166 run: *const Run,
1175 stderr: *Writer,1167 stderr: *Writer,
1176 ttyconf: tty.Config,1168 fwm: File.Writer.Mode,
1177 parent_node: *PrintNode,1169 parent_node: *PrintNode,
1178 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),1170 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
1179) !void {1171) !void {
...@@ -1186,26 +1178,26 @@ fn printTreeStep(...@@ -1186,26 +1178,26 @@ fn printTreeStep(
1186 .failures => s.state == .success,1178 .failures => s.state == .success,
1187 };1179 };
1188 if (skip) return;1180 if (skip) return;
1189 try printPrefix(parent_node, stderr, ttyconf);1181 try printPrefix(parent_node, stderr, fwm);
11901182
1191 if (parent_node.parent != null) {1183 if (parent_node.parent != null) {
1192 if (parent_node.last) {1184 if (parent_node.last) {
1193 try printChildNodePrefix(stderr, ttyconf);1185 try printChildNodePrefix(stderr, fwm);
1194 } else {1186 } else {
1195 try stderr.writeAll(switch (ttyconf) {1187 try stderr.writeAll(switch (fwm) {
1196 .no_color, .windows_api => "+- ",1188 .terminal_escaped => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─
1197 .escape_codes => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─1189 else => "+- ",
1198 });1190 });
1199 }1191 }
1200 }1192 }
12011193
1202 if (!first) try ttyconf.setColor(stderr, .dim);1194 if (!first) try fwm.setColor(stderr, .dim);
12031195
1204 // dep_prefix omitted here because it is redundant with the tree.1196 // dep_prefix omitted here because it is redundant with the tree.
1205 try stderr.writeAll(s.name);1197 try stderr.writeAll(s.name);
12061198
1207 if (first) {1199 if (first) {
1208 try printStepStatus(s, stderr, ttyconf, run);1200 try printStepStatus(s, stderr, fwm, run);
12091201
1210 const last_index = if (summary == .all) s.dependencies.items.len -| 1 else blk: {1202 const last_index = if (summary == .all) s.dependencies.items.len -| 1 else blk: {
1211 var i: usize = s.dependencies.items.len;1203 var i: usize = s.dependencies.items.len;
...@@ -1227,7 +1219,7 @@ fn printTreeStep(...@@ -1227,7 +1219,7 @@ fn printTreeStep(
1227 .parent = parent_node,1219 .parent = parent_node,
1228 .last = i == last_index,1220 .last = i == last_index,
1229 };1221 };
1230 try printTreeStep(b, dep, run, stderr, ttyconf, &print_node, step_stack);1222 try printTreeStep(b, dep, run, stderr, fwm, &print_node, step_stack);
1231 }1223 }
1232 } else {1224 } else {
1233 if (s.dependencies.items.len == 0) {1225 if (s.dependencies.items.len == 0) {
...@@ -1237,7 +1229,7 @@ fn printTreeStep(...@@ -1237,7 +1229,7 @@ fn printTreeStep(
1237 s.dependencies.items.len,1229 s.dependencies.items.len,
1238 });1230 });
1239 }1231 }
1240 try ttyconf.setColor(stderr, .reset);1232 try fwm.setColor(stderr, .reset);
1241 }1233 }
1242}1234}
12431235
...@@ -1368,7 +1360,6 @@ fn workerMakeOneStep(...@@ -1368,7 +1360,6 @@ fn workerMakeOneStep(
1368 .progress_node = sub_prog_node,1360 .progress_node = sub_prog_node,
1369 .watch = run.watch,1361 .watch = run.watch,
1370 .web_server = if (run.web_server) |*ws| ws else null,1362 .web_server = if (run.web_server) |*ws| ws else null,
1371 .ttyconf = run.ttyconf,
1372 .unit_test_timeout_ns = run.unit_test_timeout_ns,1363 .unit_test_timeout_ns = run.unit_test_timeout_ns,
1373 .gpa = gpa,1364 .gpa = gpa,
1374 });1365 });
...@@ -1378,10 +1369,9 @@ fn workerMakeOneStep(...@@ -1378,10 +1369,9 @@ fn workerMakeOneStep(
1378 const show_error_msgs = s.result_error_msgs.items.len > 0;1369 const show_error_msgs = s.result_error_msgs.items.len > 0;
1379 const show_stderr = s.result_stderr.len > 0;1370 const show_stderr = s.result_stderr.len > 0;
1380 if (show_error_msgs or show_compile_errors or show_stderr) {1371 if (show_error_msgs or show_compile_errors or show_stderr) {
1381 const bw, _ = std.debug.lockStderrWriter(&stdio_buffer_allocation);1372 const stderr = std.debug.lockStderrWriter(&stdio_buffer_allocation);
1382 defer std.debug.unlockStderrWriter();1373 defer std.debug.unlockStderrWriter();
1383 const ttyconf = run.ttyconf;1374 printErrorMessages(gpa, s, .{}, &stderr.interface, stderr.mode, run.error_style, run.multiline_errors) catch {};
1384 printErrorMessages(gpa, s, .{}, bw, ttyconf, run.error_style, run.multiline_errors) catch {};
1385 }1375 }
13861376
1387 handle_result: {1377 handle_result: {
...@@ -1449,7 +1439,7 @@ pub fn printErrorMessages(...@@ -1449,7 +1439,7 @@ pub fn printErrorMessages(
1449 failing_step: *Step,1439 failing_step: *Step,
1450 options: std.zig.ErrorBundle.RenderOptions,1440 options: std.zig.ErrorBundle.RenderOptions,
1451 stderr: *Writer,1441 stderr: *Writer,
1452 ttyconf: tty.Config,1442 fwm: File.Writer.Mode,
1453 error_style: ErrorStyle,1443 error_style: ErrorStyle,
1454 multiline_errors: MultilineErrors,1444 multiline_errors: MultilineErrors,
1455) !void {1445) !void {
...@@ -1464,29 +1454,29 @@ pub fn printErrorMessages(...@@ -1464,29 +1454,29 @@ pub fn printErrorMessages(
1464 }1454 }
14651455
1466 // Now, `step_stack` has the subtree that we want to print, in reverse order.1456 // Now, `step_stack` has the subtree that we want to print, in reverse order.
1467 try ttyconf.setColor(stderr, .dim);1457 try fwm.setColor(stderr, .dim);
1468 var indent: usize = 0;1458 var indent: usize = 0;
1469 while (step_stack.pop()) |s| : (indent += 1) {1459 while (step_stack.pop()) |s| : (indent += 1) {
1470 if (indent > 0) {1460 if (indent > 0) {
1471 try stderr.splatByteAll(' ', (indent - 1) * 3);1461 try stderr.splatByteAll(' ', (indent - 1) * 3);
1472 try printChildNodePrefix(stderr, ttyconf);1462 try printChildNodePrefix(stderr, fwm);
1473 }1463 }
14741464
1475 try stderr.writeAll(s.name);1465 try stderr.writeAll(s.name);
14761466
1477 if (s == failing_step) {1467 if (s == failing_step) {
1478 try printStepFailure(s, stderr, ttyconf, true);1468 try printStepFailure(s, stderr, fwm, true);
1479 } else {1469 } else {
1480 try stderr.writeAll("\n");1470 try stderr.writeAll("\n");
1481 }1471 }
1482 }1472 }
1483 try ttyconf.setColor(stderr, .reset);1473 try fwm.setColor(stderr, .reset);
1484 } else {1474 } else {
1485 // Just print the failing step itself.1475 // Just print the failing step itself.
1486 try ttyconf.setColor(stderr, .dim);1476 try fwm.setColor(stderr, .dim);
1487 try stderr.writeAll(failing_step.name);1477 try stderr.writeAll(failing_step.name);
1488 try printStepFailure(failing_step, stderr, ttyconf, true);1478 try printStepFailure(failing_step, stderr, fwm, true);
1489 try ttyconf.setColor(stderr, .reset);1479 try fwm.setColor(stderr, .reset);
1490 }1480 }
14911481
1492 if (failing_step.result_stderr.len > 0) {1482 if (failing_step.result_stderr.len > 0) {
...@@ -1496,12 +1486,12 @@ pub fn printErrorMessages(...@@ -1496,12 +1486,12 @@ pub fn printErrorMessages(
1496 }1486 }
1497 }1487 }
14981488
1499 try failing_step.result_error_bundle.renderToWriter(options, stderr, ttyconf);1489 try failing_step.result_error_bundle.renderToWriter(options, stderr, fwm);
15001490
1501 for (failing_step.result_error_msgs.items) |msg| {1491 for (failing_step.result_error_msgs.items) |msg| {
1502 try ttyconf.setColor(stderr, .red);1492 try fwm.setColor(stderr, .red);
1503 try stderr.writeAll("error:");1493 try stderr.writeAll("error:");
1504 try ttyconf.setColor(stderr, .reset);1494 try fwm.setColor(stderr, .reset);
1505 if (std.mem.indexOfScalar(u8, msg, '\n') == null) {1495 if (std.mem.indexOfScalar(u8, msg, '\n') == null) {
1506 try stderr.print(" {s}\n", .{msg});1496 try stderr.print(" {s}\n", .{msg});
1507 } else switch (multiline_errors) {1497 } else switch (multiline_errors) {
...@@ -1519,9 +1509,9 @@ pub fn printErrorMessages(...@@ -1519,9 +1509,9 @@ pub fn printErrorMessages(
15191509
1520 if (error_style.verboseContext()) {1510 if (error_style.verboseContext()) {
1521 if (failing_step.result_failed_command) |cmd_str| {1511 if (failing_step.result_failed_command) |cmd_str| {
1522 try ttyconf.setColor(stderr, .red);1512 try fwm.setColor(stderr, .red);
1523 try stderr.writeAll("failed command: ");1513 try stderr.writeAll("failed command: ");
1524 try ttyconf.setColor(stderr, .reset);1514 try fwm.setColor(stderr, .reset);
1525 try stderr.writeAll(cmd_str);1515 try stderr.writeAll(cmd_str);
1526 try stderr.writeByte('\n');1516 try stderr.writeByte('\n');
1527 }1517 }
lib/std/Build.zig+31-29
...@@ -5,9 +5,8 @@ const std = @import("std.zig");...@@ -5,9 +5,8 @@ const std = @import("std.zig");
5const Io = std.Io;5const Io = std.Io;
6const fs = std.fs;6const fs = std.fs;
7const mem = std.mem;7const mem = std.mem;
8const debug = std.debug;
9const panic = std.debug.panic;8const panic = std.debug.panic;
10const assert = debug.assert;9const assert = std.debug.assert;
11const log = std.log;10const log = std.log;
12const StringHashMap = std.StringHashMap;11const StringHashMap = std.StringHashMap;
13const Allocator = std.mem.Allocator;12const Allocator = std.mem.Allocator;
...@@ -2090,7 +2089,7 @@ pub fn dependencyFromBuildZig(...@@ -2090,7 +2089,7 @@ pub fn dependencyFromBuildZig(
2090 }2089 }
20912090
2092 const full_path = b.pathFromRoot("build.zig.zon");2091 const full_path = b.pathFromRoot("build.zig.zon");
2093 debug.panic("'{}' is not a build.zig struct of a dependency in '{s}'", .{ build_zig, full_path });2092 std.debug.panic("'{}' is not a build.zig struct of a dependency in '{s}'", .{ build_zig, full_path });
2094}2093}
20952094
2096fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool {2095fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool {
...@@ -2249,9 +2248,9 @@ pub const GeneratedFile = struct {...@@ -2249,9 +2248,9 @@ pub const GeneratedFile = struct {
22492248
2250 pub fn getPath2(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) []const u8 {2249 pub fn getPath2(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) []const u8 {
2251 return gen.path orelse {2250 return gen.path orelse {
2252 const w, const ttyconf = debug.lockStderrWriter(&.{});2251 const stderr = std.debug.lockStderrWriter(&.{});
2253 dumpBadGetPathHelp(gen.step, w, ttyconf, src_builder, asking_step) catch {};2252 dumpBadGetPathHelp(gen.step, &stderr.interface, stderr.mode, src_builder, asking_step) catch {};
2254 debug.unlockStderrWriter();2253 std.debug.unlockStderrWriter();
2255 @panic("misconfigured build script");2254 @panic("misconfigured build script");
2256 };2255 };
2257 }2256 }
...@@ -2458,9 +2457,9 @@ pub const LazyPath = union(enum) {...@@ -2458,9 +2457,9 @@ pub const LazyPath = union(enum) {
2458 var file_path: Cache.Path = .{2457 var file_path: Cache.Path = .{
2459 .root_dir = Cache.Directory.cwd(),2458 .root_dir = Cache.Directory.cwd(),
2460 .sub_path = gen.file.path orelse {2459 .sub_path = gen.file.path orelse {
2461 const w, const ttyconf = debug.lockStderrWriter(&.{});2460 const stderr = std.debug.lockStderrWriter(&.{});
2462 dumpBadGetPathHelp(gen.file.step, w, ttyconf, src_builder, asking_step) catch {};2461 dumpBadGetPathHelp(gen.file.step, &stderr.interface, stderr.mode, src_builder, asking_step) catch {};
2463 debug.unlockStderrWriter();2462 std.debug.unlockStderrWriter();
2464 @panic("misconfigured build script");2463 @panic("misconfigured build script");
2465 },2464 },
2466 };2465 };
...@@ -2550,37 +2549,40 @@ fn dumpBadDirnameHelp(...@@ -2550,37 +2549,40 @@ fn dumpBadDirnameHelp(
2550 comptime msg: []const u8,2549 comptime msg: []const u8,
2551 args: anytype,2550 args: anytype,
2552) anyerror!void {2551) anyerror!void {
2553 const w, const tty_config = debug.lockStderrWriter(&.{});2552 const stderr = std.debug.lockStderrWriter(&.{});
2554 defer debug.unlockStderrWriter();2553 defer std.debug.unlockStderrWriter();
2554
2555 const w = &stderr.interface;
2556 const fwm = stderr.mode;
25552557
2556 try w.print(msg, args);2558 try w.print(msg, args);
25572559
2558 if (fail_step) |s| {2560 if (fail_step) |s| {
2559 tty_config.setColor(w, .red) catch {};2561 fwm.setColor(w, .red) catch {};
2560 try w.writeAll(" The step was created by this stack trace:\n");2562 try w.writeAll(" The step was created by this stack trace:\n");
2561 tty_config.setColor(w, .reset) catch {};2563 fwm.setColor(w, .reset) catch {};
25622564
2563 s.dump(w, tty_config);2565 s.dump(w, fwm);
2564 }2566 }
25652567
2566 if (asking_step) |as| {2568 if (asking_step) |as| {
2567 tty_config.setColor(w, .red) catch {};2569 fwm.setColor(w, .red) catch {};
2568 try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});2570 try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
2569 tty_config.setColor(w, .reset) catch {};2571 fwm.setColor(w, .reset) catch {};
25702572
2571 as.dump(w, tty_config);2573 as.dump(w, fwm);
2572 }2574 }
25732575
2574 tty_config.setColor(w, .red) catch {};2576 fwm.setColor(w, .red) catch {};
2575 try w.writeAll(" Hope that helps. Proceeding to panic.\n");2577 try w.writeAll(" Hope that helps. Proceeding to panic.\n");
2576 tty_config.setColor(w, .reset) catch {};2578 fwm.setColor(w, .reset) catch {};
2577}2579}
25782580
2579/// In this function the stderr mutex has already been locked.2581/// In this function the stderr mutex has already been locked.
2580pub fn dumpBadGetPathHelp(2582pub fn dumpBadGetPathHelp(
2581 s: *Step,2583 s: *Step,
2582 w: *std.Io.Writer,2584 w: *Io.Writer,
2583 tty_config: std.Io.tty.Config,2585 fwm: File.Writer.Mode,
2584 src_builder: *Build,2586 src_builder: *Build,
2585 asking_step: ?*Step,2587 asking_step: ?*Step,
2586) anyerror!void {2588) anyerror!void {
...@@ -2594,21 +2596,21 @@ pub fn dumpBadGetPathHelp(...@@ -2594,21 +2596,21 @@ pub fn dumpBadGetPathHelp(
2594 s.name,2596 s.name,
2595 });2597 });
25962598
2597 tty_config.setColor(w, .red) catch {};2599 fwm.setColor(w, .red) catch {};
2598 try w.writeAll(" The step was created by this stack trace:\n");2600 try w.writeAll(" The step was created by this stack trace:\n");
2599 tty_config.setColor(w, .reset) catch {};2601 fwm.setColor(w, .reset) catch {};
26002602
2601 s.dump(w, tty_config);2603 s.dump(w, fwm);
2602 if (asking_step) |as| {2604 if (asking_step) |as| {
2603 tty_config.setColor(w, .red) catch {};2605 fwm.setColor(w, .red) catch {};
2604 try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});2606 try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
2605 tty_config.setColor(w, .reset) catch {};2607 fwm.setColor(w, .reset) catch {};
26062608
2607 as.dump(w, tty_config);2609 as.dump(w, fwm);
2608 }2610 }
2609 tty_config.setColor(w, .red) catch {};2611 fwm.setColor(w, .red) catch {};
2610 try w.writeAll(" Hope that helps. Proceeding to panic.\n");2612 try w.writeAll(" Hope that helps. Proceeding to panic.\n");
2611 tty_config.setColor(w, .reset) catch {};2613 fwm.setColor(w, .reset) catch {};
2612}2614}
26132615
2614pub const InstallDir = union(enum) {2616pub const InstallDir = union(enum) {
lib/std/Build/Fuzz.zig+8-12
...@@ -9,14 +9,12 @@ const Allocator = std.mem.Allocator;...@@ -9,14 +9,12 @@ const Allocator = std.mem.Allocator;
9const log = std.log;9const log = std.log;
10const Coverage = std.debug.Coverage;10const Coverage = std.debug.Coverage;
11const abi = Build.abi.fuzz;11const abi = Build.abi.fuzz;
12const tty = std.Io.tty;
1312
14const Fuzz = @This();13const Fuzz = @This();
15const build_runner = @import("root");14const build_runner = @import("root");
1615
17gpa: Allocator,16gpa: Allocator,
18io: Io,17io: Io,
19ttyconf: tty.Config,
20mode: Mode,18mode: Mode,
2119
22/// Allocated into `gpa`.20/// Allocated into `gpa`.
...@@ -77,7 +75,6 @@ const CoverageMap = struct {...@@ -77,7 +75,6 @@ const CoverageMap = struct {
77pub fn init(75pub fn init(
78 gpa: Allocator,76 gpa: Allocator,
79 io: Io,77 io: Io,
80 ttyconf: tty.Config,
81 all_steps: []const *Build.Step,78 all_steps: []const *Build.Step,
82 root_prog_node: std.Progress.Node,79 root_prog_node: std.Progress.Node,
83 mode: Mode,80 mode: Mode,
...@@ -95,7 +92,7 @@ pub fn init(...@@ -95,7 +92,7 @@ pub fn init(
95 if (run.producer == null) continue;92 if (run.producer == null) continue;
96 if (run.fuzz_tests.items.len == 0) continue;93 if (run.fuzz_tests.items.len == 0) continue;
97 try steps.append(gpa, run);94 try steps.append(gpa, run);
98 rebuild_group.async(io, rebuildTestsWorkerRun, .{ run, gpa, ttyconf, rebuild_node });95 rebuild_group.async(io, rebuildTestsWorkerRun, .{ run, gpa, rebuild_node });
99 }96 }
10097
101 if (steps.items.len == 0) fatal("no fuzz tests found", .{});98 if (steps.items.len == 0) fatal("no fuzz tests found", .{});
...@@ -115,7 +112,6 @@ pub fn init(...@@ -115,7 +112,6 @@ pub fn init(
115 return .{112 return .{
116 .gpa = gpa,113 .gpa = gpa,
117 .io = io,114 .io = io,
118 .ttyconf = ttyconf,
119 .mode = mode,115 .mode = mode,
120 .run_steps = run_steps,116 .run_steps = run_steps,
121 .group = .init,117 .group = .init,
...@@ -154,14 +150,14 @@ pub fn deinit(fuzz: *Fuzz) void {...@@ -154,14 +150,14 @@ pub fn deinit(fuzz: *Fuzz) void {
154 fuzz.gpa.free(fuzz.run_steps);150 fuzz.gpa.free(fuzz.run_steps);
155}151}
156152
157fn rebuildTestsWorkerRun(run: *Step.Run, gpa: Allocator, ttyconf: tty.Config, parent_prog_node: std.Progress.Node) void {153fn rebuildTestsWorkerRun(run: *Step.Run, gpa: Allocator, parent_prog_node: std.Progress.Node) void {
158 rebuildTestsWorkerRunFallible(run, gpa, ttyconf, parent_prog_node) catch |err| {154 rebuildTestsWorkerRunFallible(run, gpa, parent_prog_node) catch |err| {
159 const compile = run.producer.?;155 const compile = run.producer.?;
160 log.err("step '{s}': failed to rebuild in fuzz mode: {t}", .{ compile.step.name, err });156 log.err("step '{s}': failed to rebuild in fuzz mode: {t}", .{ compile.step.name, err });
161 };157 };
162}158}
163159
164fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, ttyconf: tty.Config, parent_prog_node: std.Progress.Node) !void {160fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, parent_prog_node: std.Progress.Node) !void {
165 const compile = run.producer.?;161 const compile = run.producer.?;
166 const prog_node = parent_prog_node.start(compile.step.name, 0);162 const prog_node = parent_prog_node.start(compile.step.name, 0);
167 defer prog_node.end();163 defer prog_node.end();
...@@ -174,9 +170,9 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, ttyconf: tty.Co...@@ -174,9 +170,9 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, ttyconf: tty.Co
174170
175 if (show_error_msgs or show_compile_errors or show_stderr) {171 if (show_error_msgs or show_compile_errors or show_stderr) {
176 var buf: [256]u8 = undefined;172 var buf: [256]u8 = undefined;
177 const w, _ = std.debug.lockStderrWriter(&buf);173 const stderr = std.debug.lockStderrWriter(&buf);
178 defer std.debug.unlockStderrWriter();174 defer std.debug.unlockStderrWriter();
179 build_runner.printErrorMessages(gpa, &compile.step, .{}, w, ttyconf, .verbose, .indent) catch {};175 build_runner.printErrorMessages(gpa, &compile.step, .{}, &stderr.interface, stderr.mode, .verbose, .indent) catch {};
180 }176 }
181177
182 const rebuilt_bin_path = result catch |err| switch (err) {178 const rebuilt_bin_path = result catch |err| switch (err) {
...@@ -200,9 +196,9 @@ fn fuzzWorkerRun(...@@ -200,9 +196,9 @@ fn fuzzWorkerRun(
200 run.rerunInFuzzMode(fuzz, unit_test_index, prog_node) catch |err| switch (err) {196 run.rerunInFuzzMode(fuzz, unit_test_index, prog_node) catch |err| switch (err) {
201 error.MakeFailed => {197 error.MakeFailed => {
202 var buf: [256]u8 = undefined;198 var buf: [256]u8 = undefined;
203 const w, _ = std.debug.lockStderrWriter(&buf);199 const stderr = std.debug.lockStderrWriter(&buf);
204 defer std.debug.unlockStderrWriter();200 defer std.debug.unlockStderrWriter();
205 build_runner.printErrorMessages(gpa, &run.step, .{}, w, fuzz.ttyconf, .verbose, .indent) catch {};201 build_runner.printErrorMessages(gpa, &run.step, .{}, &stderr.interface, stderr.mode, .verbose, .indent) catch {};
206 return;202 return;
207 },203 },
208 else => {204 else => {
lib/std/Build/Step.zig+4-5
...@@ -117,7 +117,6 @@ pub const MakeOptions = struct {...@@ -117,7 +117,6 @@ pub const MakeOptions = struct {
117 // it currently breaks because `std.net.Address` doesn't work there. Work around for now.117 // it currently breaks because `std.net.Address` doesn't work there. Work around for now.
118 .wasm32 => void,118 .wasm32 => void,
119 },119 },
120 ttyconf: std.Io.tty.Config,
121 /// If set, this is a timeout to enforce on all individual unit tests, in nanoseconds.120 /// If set, this is a timeout to enforce on all individual unit tests, in nanoseconds.
122 unit_test_timeout_ns: ?u64,121 unit_test_timeout_ns: ?u64,
123 /// Not to be confused with `Build.allocator`, which is an alias of `Build.graph.arena`.122 /// Not to be confused with `Build.allocator`, which is an alias of `Build.graph.arena`.
...@@ -329,16 +328,16 @@ pub fn cast(step: *Step, comptime T: type) ?*T {...@@ -329,16 +328,16 @@ pub fn cast(step: *Step, comptime T: type) ?*T {
329}328}
330329
331/// For debugging purposes, prints identifying information about this Step.330/// For debugging purposes, prints identifying information about this Step.
332pub fn dump(step: *Step, w: *Io.Writer, tty_config: Io.tty.Config) void {331pub fn dump(step: *Step, w: *Io.Writer, fwm: Io.File.Writer.Mode) void {
333 if (step.debug_stack_trace.instruction_addresses.len > 0) {332 if (step.debug_stack_trace.instruction_addresses.len > 0) {
334 w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};333 w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};
335 std.debug.writeStackTrace(&step.debug_stack_trace, w, tty_config) catch {};334 std.debug.writeStackTrace(&step.debug_stack_trace, w, fwm) catch {};
336 } else {335 } else {
337 const field = "debug_stack_frames_count";336 const field = "debug_stack_frames_count";
338 comptime assert(@hasField(Build, field));337 comptime assert(@hasField(Build, field));
339 tty_config.setColor(w, .yellow) catch {};338 fwm.setColor(w, .yellow) catch {};
340 w.print("name: '{s}'. no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{step.name}) catch {};339 w.print("name: '{s}'. no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{step.name}) catch {};
341 tty_config.setColor(w, .reset) catch {};340 fwm.setColor(w, .reset) catch {};
342 }341 }
343}342}
344343
lib/std/Build/Step/Compile.zig+5-5
...@@ -926,15 +926,15 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking...@@ -926,15 +926,15 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking
926 const maybe_path: ?*GeneratedFile = @field(compile, tag_name);926 const maybe_path: ?*GeneratedFile = @field(compile, tag_name);
927927
928 const generated_file = maybe_path orelse {928 const generated_file = maybe_path orelse {
929 const w, const ttyconf = std.debug.lockStderrWriter(&.{});929 const stderr = std.debug.lockStderrWriter(&.{});
930 std.Build.dumpBadGetPathHelp(&compile.step, w, ttyconf, compile.step.owner, asking_step) catch {};930 std.Build.dumpBadGetPathHelp(&compile.step, &stderr.interface, stderr.mode, compile.step.owner, asking_step) catch {};
931 std.debug.unlockStderrWriter();931 std.debug.unlockStderrWriter();
932 @panic("missing emit option for " ++ tag_name);932 @panic("missing emit option for " ++ tag_name);
933 };933 };
934934
935 const path = generated_file.path orelse {935 const path = generated_file.path orelse {
936 const w, const ttyconf = std.debug.lockStderrWriter(&.{});936 const stderr = std.debug.lockStderrWriter(&.{});
937 std.Build.dumpBadGetPathHelp(&compile.step, w, ttyconf, compile.step.owner, asking_step) catch {};937 std.Build.dumpBadGetPathHelp(&compile.step, &stderr.interface, stderr.mode, compile.step.owner, asking_step) catch {};
938 std.debug.unlockStderrWriter();938 std.debug.unlockStderrWriter();
939 @panic(tag_name ++ " is null. Is there a missing step dependency?");939 @panic(tag_name ++ " is null. Is there a missing step dependency?");
940 };940 };
...@@ -1904,7 +1904,7 @@ fn checkCompileErrors(compile: *Compile) !void {...@@ -1904,7 +1904,7 @@ fn checkCompileErrors(compile: *Compile) !void {
1904 try actual_eb.renderToWriter(.{1904 try actual_eb.renderToWriter(.{
1905 .include_reference_trace = false,1905 .include_reference_trace = false,
1906 .include_source_line = false,1906 .include_source_line = false,
1907 }, &aw.writer, .no_color);1907 }, &aw.writer, .streaming);
1908 break :ae try aw.toOwnedSlice();1908 break :ae try aw.toOwnedSlice();
1909 };1909 };
19101910
lib/std/Build/Step/Run.zig+33-35
...@@ -5,7 +5,7 @@ const std = @import("std");...@@ -5,7 +5,7 @@ const std = @import("std");
5const Io = std.Io;5const Io = std.Io;
6const Build = std.Build;6const Build = std.Build;
7const Step = std.Build.Step;7const Step = std.Build.Step;
8const fs = std.fs;8const Dir = std.Io.Dir;
9const mem = std.mem;9const mem = std.mem;
10const process = std.process;10const process = std.process;
11const EnvMap = std.process.EnvMap;11const EnvMap = std.process.EnvMap;
...@@ -26,19 +26,7 @@ cwd: ?Build.LazyPath,...@@ -26,19 +26,7 @@ cwd: ?Build.LazyPath,
26env_map: ?*EnvMap,26env_map: ?*EnvMap,
2727
28/// Controls the `NO_COLOR` and `CLICOLOR_FORCE` environment variables.28/// Controls the `NO_COLOR` and `CLICOLOR_FORCE` environment variables.
29color: enum {29color: Color = .auto,
30 /// `CLICOLOR_FORCE` is set, and `NO_COLOR` is unset.
31 enable,
32 /// `NO_COLOR` is set, and `CLICOLOR_FORCE` is unset.
33 disable,
34 /// If the build runner is using color, equivalent to `.enable`. Otherwise, equivalent to `.disable`.
35 inherit,
36 /// If stderr is captured or checked, equivalent to `.disable`. Otherwise, equivalent to `.inherit`.
37 auto,
38 /// The build runner does not modify the `CLICOLOR_FORCE` or `NO_COLOR` environment variables.
39 /// They are treated like normal variables, so can be controlled through `setEnvironmentVariable`.
40 manual,
41} = .auto,
4230
43/// When `true` prevents `ZIG_PROGRESS` environment variable from being passed31/// When `true` prevents `ZIG_PROGRESS` environment variable from being passed
44/// to the child process, which otherwise would be used for the child to send32/// to the child process, which otherwise would be used for the child to send
...@@ -112,6 +100,20 @@ rebuilt_executable: ?Path,...@@ -112,6 +100,20 @@ rebuilt_executable: ?Path,
112/// If this Run step was produced by a Compile step, it is tracked here.100/// If this Run step was produced by a Compile step, it is tracked here.
113producer: ?*Step.Compile,101producer: ?*Step.Compile,
114102
103pub const Color = enum {
104 /// `CLICOLOR_FORCE` is set, and `NO_COLOR` is unset.
105 enable,
106 /// `NO_COLOR` is set, and `CLICOLOR_FORCE` is unset.
107 disable,
108 /// If the build runner is using color, equivalent to `.enable`. Otherwise, equivalent to `.disable`.
109 inherit,
110 /// If stderr is captured or checked, equivalent to `.disable`. Otherwise, equivalent to `.inherit`.
111 auto,
112 /// The build runner does not modify the `CLICOLOR_FORCE` or `NO_COLOR` environment variables.
113 /// They are treated like normal variables, so can be controlled through `setEnvironmentVariable`.
114 manual,
115};
116
115pub const StdIn = union(enum) {117pub const StdIn = union(enum) {
116 none,118 none,
117 bytes: []const u8,119 bytes: []const u8,
...@@ -565,7 +567,7 @@ pub fn addPathDir(run: *Run, search_path: []const u8) void {...@@ -565,7 +567,7 @@ pub fn addPathDir(run: *Run, search_path: []const u8) void {
565 if (prev_path) |pp| {567 if (prev_path) |pp| {
566 const new_path = b.fmt("{s}{c}{s}", .{568 const new_path = b.fmt("{s}{c}{s}", .{
567 pp,569 pp,
568 if (use_wine) fs.path.delimiter_windows else fs.path.delimiter,570 if (use_wine) Dir.path.delimiter_windows else Dir.path.delimiter,
569 search_path,571 search_path,
570 });572 });
571 env_map.put(key, new_path) catch @panic("OOM");573 env_map.put(key, new_path) catch @panic("OOM");
...@@ -748,7 +750,7 @@ fn checksContainStderr(checks: []const StdIo.Check) bool {...@@ -748,7 +750,7 @@ fn checksContainStderr(checks: []const StdIo.Check) bool {
748fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 {750fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 {
749 const b = run.step.owner;751 const b = run.step.owner;
750 const path_str = path.toString(b.graph.arena) catch @panic("OOM");752 const path_str = path.toString(b.graph.arena) catch @panic("OOM");
751 if (std.fs.path.isAbsolute(path_str)) {753 if (Dir.path.isAbsolute(path_str)) {
752 // Absolute paths don't need changing.754 // Absolute paths don't need changing.
753 return path_str;755 return path_str;
754 }756 }
...@@ -756,19 +758,19 @@ fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 {...@@ -756,19 +758,19 @@ fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 {
756 const child_lazy_cwd = run.cwd orelse break :rel path_str;758 const child_lazy_cwd = run.cwd orelse break :rel path_str;
757 const child_cwd = child_lazy_cwd.getPath3(b, &run.step).toString(b.graph.arena) catch @panic("OOM");759 const child_cwd = child_lazy_cwd.getPath3(b, &run.step).toString(b.graph.arena) catch @panic("OOM");
758 // Convert it from relative to *our* cwd, to relative to the *child's* cwd.760 // Convert it from relative to *our* cwd, to relative to the *child's* cwd.
759 break :rel std.fs.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM");761 break :rel Dir.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM");
760 };762 };
761 // Not every path can be made relative, e.g. if the path and the child cwd are on different763 // Not every path can be made relative, e.g. if the path and the child cwd are on different
762 // disk designators on Windows. In that case, `relative` will return an absolute path which we can764 // disk designators on Windows. In that case, `relative` will return an absolute path which we can
763 // just return.765 // just return.
764 if (std.fs.path.isAbsolute(child_cwd_rel)) {766 if (Dir.path.isAbsolute(child_cwd_rel)) {
765 return child_cwd_rel;767 return child_cwd_rel;
766 }768 }
767 // We're not done yet. In some cases this path must be prefixed with './':769 // We're not done yet. In some cases this path must be prefixed with './':
768 // * On POSIX, the executable name cannot be a single component like 'foo'770 // * On POSIX, the executable name cannot be a single component like 'foo'
769 // * Some executables might treat a leading '-' like a flag, which we must avoid771 // * Some executables might treat a leading '-' like a flag, which we must avoid
770 // There's no harm in it, so just *always* apply this prefix.772 // There's no harm in it, so just *always* apply this prefix.
771 return std.fs.path.join(b.graph.arena, &.{ ".", child_cwd_rel }) catch @panic("OOM");773 return Dir.path.join(b.graph.arena, &.{ ".", child_cwd_rel }) catch @panic("OOM");
772}774}
773775
774const IndexedOutput = struct {776const IndexedOutput = struct {
...@@ -965,11 +967,11 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -965,11 +967,11 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
965 &digest,967 &digest,
966 );968 );
967969
968 const output_dir_path = "o" ++ fs.path.sep_str ++ &digest;970 const output_dir_path = "o" ++ Dir.path.sep_str ++ &digest;
969 for (output_placeholders.items) |placeholder| {971 for (output_placeholders.items) |placeholder| {
970 const output_sub_path = b.pathJoin(&.{ output_dir_path, placeholder.output.basename });972 const output_sub_path = b.pathJoin(&.{ output_dir_path, placeholder.output.basename });
971 const output_sub_dir_path = switch (placeholder.tag) {973 const output_sub_dir_path = switch (placeholder.tag) {
972 .output_file => fs.path.dirname(output_sub_path).?,974 .output_file => Dir.path.dirname(output_sub_path).?,
973 .output_directory => output_sub_path,975 .output_directory => output_sub_path,
974 else => unreachable,976 else => unreachable,
975 };977 };
...@@ -995,13 +997,13 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -995,13 +997,13 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
995997
996 // We do not know the final output paths yet, use temp paths to run the command.998 // We do not know the final output paths yet, use temp paths to run the command.
997 const rand_int = std.crypto.random.int(u64);999 const rand_int = std.crypto.random.int(u64);
998 const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);1000 const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);
9991001
1000 for (output_placeholders.items) |placeholder| {1002 for (output_placeholders.items) |placeholder| {
1001 const output_components = .{ tmp_dir_path, placeholder.output.basename };1003 const output_components = .{ tmp_dir_path, placeholder.output.basename };
1002 const output_sub_path = b.pathJoin(&output_components);1004 const output_sub_path = b.pathJoin(&output_components);
1003 const output_sub_dir_path = switch (placeholder.tag) {1005 const output_sub_dir_path = switch (placeholder.tag) {
1004 .output_file => fs.path.dirname(output_sub_path).?,1006 .output_file => Dir.path.dirname(output_sub_path).?,
1005 .output_directory => output_sub_path,1007 .output_directory => output_sub_path,
1006 else => unreachable,1008 else => unreachable,
1007 };1009 };
...@@ -1023,7 +1025,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -1023,7 +1025,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
10231025
1024 try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, options, null);1026 try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, options, null);
10251027
1026 const dep_file_dir = Io.Dir.cwd();1028 const dep_file_dir = Dir.cwd();
1027 const dep_file_basename = dep_output_file.generated_file.getPath2(b, step);1029 const dep_file_basename = dep_output_file.generated_file.getPath2(b, step);
1028 if (has_side_effects)1030 if (has_side_effects)
1029 try man.addDepFile(dep_file_dir, dep_file_basename)1031 try man.addDepFile(dep_file_dir, dep_file_basename)
...@@ -1040,7 +1042,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -1040,7 +1042,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
10401042
1041 // Rename into place1043 // Rename into place
1042 if (any_output) {1044 if (any_output) {
1043 const o_sub_path = "o" ++ fs.path.sep_str ++ &digest;1045 const o_sub_path = "o" ++ Dir.path.sep_str ++ &digest;
10441046
1045 b.cache_root.handle.rename(tmp_dir_path, b.cache_root.handle, o_sub_path, io) catch |err| {1047 b.cache_root.handle.rename(tmp_dir_path, b.cache_root.handle, o_sub_path, io) catch |err| {
1046 if (err == error.PathAlreadyExists) {1048 if (err == error.PathAlreadyExists) {
...@@ -1139,12 +1141,11 @@ pub fn rerunInFuzzMode(...@@ -1139,12 +1141,11 @@ pub fn rerunInFuzzMode(
11391141
1140 const has_side_effects = false;1142 const has_side_effects = false;
1141 const rand_int = std.crypto.random.int(u64);1143 const rand_int = std.crypto.random.int(u64);
1142 const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);1144 const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);
1143 try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, .{1145 try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, .{
1144 .progress_node = prog_node,1146 .progress_node = prog_node,
1145 .watch = undefined, // not used by `runCommand`1147 .watch = undefined, // not used by `runCommand`
1146 .web_server = null, // only needed for time reports1148 .web_server = null, // only needed for time reports
1147 .ttyconf = fuzz.ttyconf,
1148 .unit_test_timeout_ns = null, // don't time out fuzz tests for now1149 .unit_test_timeout_ns = null, // don't time out fuzz tests for now
1149 .gpa = fuzz.gpa,1150 .gpa = fuzz.gpa,
1150 }, .{1151 }, .{
...@@ -1266,10 +1267,7 @@ fn runCommand(...@@ -1266,10 +1267,7 @@ fn runCommand(
1266 try env_map.put("NO_COLOR", "1");1267 try env_map.put("NO_COLOR", "1");
1267 env_map.remove("CLICOLOR_FORCE");1268 env_map.remove("CLICOLOR_FORCE");
1268 },1269 },
1269 .inherit => switch (options.ttyconf) {1270 .inherit => {},
1270 .no_color, .windows_api => continue :color .disable,
1271 .escape_codes => continue :color .enable,
1272 },
1273 .auto => {1271 .auto => {
1274 const capture_stderr = run.captured_stderr != null or switch (run.stdio) {1272 const capture_stderr = run.captured_stderr != null or switch (run.stdio) {
1275 .check => |checks| checksContainStderr(checks.items),1273 .check => |checks| checksContainStderr(checks.items),
...@@ -1464,7 +1462,7 @@ fn runCommand(...@@ -1464,7 +1462,7 @@ fn runCommand(
1464 captured.output.generated_file.path = output_path;1462 captured.output.generated_file.path = output_path;
14651463
1466 const sub_path = b.pathJoin(&output_components);1464 const sub_path = b.pathJoin(&output_components);
1467 const sub_path_dirname = fs.path.dirname(sub_path).?;1465 const sub_path_dirname = Dir.path.dirname(sub_path).?;
1468 b.cache_root.handle.makePath(io, sub_path_dirname) catch |err| {1466 b.cache_root.handle.makePath(io, sub_path_dirname) catch |err| {
1469 return step.fail("unable to make path '{f}{s}': {s}", .{1467 return step.fail("unable to make path '{f}{s}': {s}", .{
1470 b.cache_root, sub_path_dirname, @errorName(err),1468 b.cache_root, sub_path_dirname, @errorName(err),
...@@ -1650,8 +1648,8 @@ fn spawnChildAndCollect(...@@ -1650,8 +1648,8 @@ fn spawnChildAndCollect(
1650 if (!run.disable_zig_progress and !inherit) {1648 if (!run.disable_zig_progress and !inherit) {
1651 child.progress_node = options.progress_node;1649 child.progress_node = options.progress_node;
1652 }1650 }
1653 if (inherit) std.debug.lockStdErr();1651 if (inherit) _ = std.debug.lockStderrWriter(&.{});
1654 defer if (inherit) std.debug.unlockStdErr();1652 defer if (inherit) std.debug.unlockStderrWriter();
1655 var timer = try std.time.Timer.start();1653 var timer = try std.time.Timer.start();
1656 const res = try evalGeneric(run, &child);1654 const res = try evalGeneric(run, &child);
1657 run.step.result_duration_ns = timer.read();1655 run.step.result_duration_ns = timer.read();
...@@ -2277,7 +2275,7 @@ fn addPathForDynLibs(run: *Run, artifact: *Step.Compile) void {...@@ -2277,7 +2275,7 @@ fn addPathForDynLibs(run: *Run, artifact: *Step.Compile) void {
2277 if (compile.root_module.resolved_target.?.result.os.tag == .windows and2275 if (compile.root_module.resolved_target.?.result.os.tag == .windows and
2278 compile.isDynamicLibrary())2276 compile.isDynamicLibrary())
2279 {2277 {
2280 addPathDir(run, fs.path.dirname(compile.getEmittedBin().getPath2(b, &run.step)).?);2278 addPathDir(run, Dir.path.dirname(compile.getEmittedBin().getPath2(b, &run.step)).?);
2281 }2279 }
2282 }2280 }
2283}2281}
lib/std/Build/WebServer.zig-4
...@@ -2,7 +2,6 @@ gpa: Allocator,...@@ -2,7 +2,6 @@ gpa: Allocator,
2graph: *const Build.Graph,2graph: *const Build.Graph,
3all_steps: []const *Build.Step,3all_steps: []const *Build.Step,
4listen_address: net.IpAddress,4listen_address: net.IpAddress,
5ttyconf: Io.tty.Config,
6root_prog_node: std.Progress.Node,5root_prog_node: std.Progress.Node,
7watch: bool,6watch: bool,
87
...@@ -52,7 +51,6 @@ pub fn notifyUpdate(ws: *WebServer) void {...@@ -52,7 +51,6 @@ pub fn notifyUpdate(ws: *WebServer) void {
5251
53pub const Options = struct {52pub const Options = struct {
54 gpa: Allocator,53 gpa: Allocator,
55 ttyconf: Io.tty.Config,
56 graph: *const std.Build.Graph,54 graph: *const std.Build.Graph,
57 all_steps: []const *Build.Step,55 all_steps: []const *Build.Step,
58 root_prog_node: std.Progress.Node,56 root_prog_node: std.Progress.Node,
...@@ -98,7 +96,6 @@ pub fn init(opts: Options) WebServer {...@@ -98,7 +96,6 @@ pub fn init(opts: Options) WebServer {
9896
99 return .{97 return .{
100 .gpa = opts.gpa,98 .gpa = opts.gpa,
101 .ttyconf = opts.ttyconf,
102 .graph = opts.graph,99 .graph = opts.graph,
103 .all_steps = all_steps,100 .all_steps = all_steps,
104 .listen_address = opts.listen_address,101 .listen_address = opts.listen_address,
...@@ -233,7 +230,6 @@ pub fn finishBuild(ws: *WebServer, opts: struct {...@@ -233,7 +230,6 @@ pub fn finishBuild(ws: *WebServer, opts: struct {
233 ws.fuzz = Fuzz.init(230 ws.fuzz = Fuzz.init(
234 ws.gpa,231 ws.gpa,
235 ws.graph.io,232 ws.graph.io,
236 ws.ttyconf,
237 ws.all_steps,233 ws.all_steps,
238 ws.root_prog_node,234 ws.root_prog_node,
239 .{ .forever = .{ .ws = ws } },235 .{ .forever = .{ .ws = ws } },
lib/std/Io/File/Writer.zig+36-5
...@@ -99,7 +99,7 @@ pub const Mode = union(enum) {...@@ -99,7 +99,7 @@ pub const Mode = union(enum) {
9999
100 pub const SetColorError = std.os.windows.SetConsoleTextAttributeError || Io.Writer.Error;100 pub const SetColorError = std.os.windows.SetConsoleTextAttributeError || Io.Writer.Error;
101101
102 pub fn setColor(mode: Mode, io_w: *Io.Writer, color: Color) Mode.SetColorError!void {102 pub fn setColor(mode: Mode, io_w: *Io.Writer, color: Color) SetColorError!void {
103 switch (mode) {103 switch (mode) {
104 .streaming, .positional, .streaming_simple, .positional_simple, .failure => return,104 .streaming, .positional, .streaming_simple, .positional_simple, .failure => return,
105 .terminal_escaped => {105 .terminal_escaped => {
...@@ -155,6 +155,34 @@ pub const Mode = union(enum) {...@@ -155,6 +155,34 @@ pub const Mode = union(enum) {
155 },155 },
156 }156 }
157 }157 }
158
159 fn DecorateArgs(comptime Args: type) type {
160 const fields = @typeInfo(Args).@"struct".fields;
161 var new_fields: [fields.len]type = undefined;
162 for (fields, &new_fields) |old, *new| {
163 if (old.type == std.debug.FormatStackTrace) {
164 new.* = std.debug.FormatStackTrace.Decorated;
165 } else {
166 new.* = old.type;
167 }
168 }
169 return @Tuple(&new_fields);
170 }
171
172 pub fn decorateArgs(file_writer_mode: std.Io.File.Writer.Mode, args: anytype) DecorateArgs(@TypeOf(args)) {
173 var new_args: DecorateArgs(@TypeOf(args)) = undefined;
174 inline for (args, &new_args) |old, *new| {
175 if (@TypeOf(old) == std.debug.FormatStackTrace) {
176 new.* = .{
177 .stack_trace = old.stack_trace,
178 .file_writer_mode = file_writer_mode,
179 };
180 } else {
181 new.* = old;
182 }
183 }
184 return new_args;
185 }
158};186};
159187
160pub const Error = error{188pub const Error = error{
...@@ -426,6 +454,8 @@ pub fn end(w: *Writer) EndError!void {...@@ -426,6 +454,8 @@ pub fn end(w: *Writer) EndError!void {
426454
427 .streaming,455 .streaming,
428 .streaming_simple,456 .streaming_simple,
457 .terminal_escaped,
458 .terminal_winapi,
429 .failure,459 .failure,
430 => {},460 => {},
431 }461 }
...@@ -453,10 +483,11 @@ pub const Color = enum {...@@ -453,10 +483,11 @@ pub const Color = enum {
453 reset,483 reset,
454};484};
455485
456pub const SetColorError = Mode.SetColorError;486pub fn setColor(w: *Writer, color: Color) Io.Writer.Error!void {
457487 return w.mode.setColor(&w.interface, color) catch |err| switch (err) {
458pub fn setColor(w: *Writer, color: Color) SetColorError!void {488 error.WriteFailed => |e| return e,
459 return w.mode.setColor(&w.interface, color);489 else => |e| w.err = e,
490 };
460}491}
461492
462pub fn disableEscape(w: *Writer) Mode {493pub fn disableEscape(w: *Writer) Mode {
lib/std/debug.zig+1-1
...@@ -306,7 +306,7 @@ pub fn print(comptime fmt: []const u8, args: anytype) void {...@@ -306,7 +306,7 @@ pub fn print(comptime fmt: []const u8, args: anytype) void {
306 var buffer: [64]u8 = undefined;306 var buffer: [64]u8 = undefined;
307 const stderr = lockStderrWriter(&buffer);307 const stderr = lockStderrWriter(&buffer);
308 defer unlockStderrWriter();308 defer unlockStderrWriter();
309 stderr.interface.print(fmt, args) catch return;309 stderr.interface.print(fmt, stderr.mode.decorateArgs(args)) catch return;
310 }310 }
311}311}
312312
lib/std/log.zig+1-29
...@@ -120,35 +120,7 @@ pub fn defaultLogFileWriter(...@@ -120,35 +120,7 @@ pub fn defaultLogFileWriter(
120 }120 }
121 fw.interface.writeAll(": ") catch return;121 fw.interface.writeAll(": ") catch return;
122 fw.setColor(.reset) catch {};122 fw.setColor(.reset) catch {};
123 fw.interface.print(format ++ "\n", decorateArgs(args, fw.mode)) catch return;123 fw.interface.print(format ++ "\n", fw.mode.decorateArgs(args)) catch return;
124}
125
126fn DecorateArgs(comptime Args: type) type {
127 const fields = @typeInfo(Args).@"struct".fields;
128 var new_fields: [fields.len]type = undefined;
129 for (fields, &new_fields) |old, *new| {
130 if (old.type == std.debug.FormatStackTrace) {
131 new.* = std.debug.FormatStackTrace.Decorated;
132 } else {
133 new.* = old.type;
134 }
135 }
136 return @Tuple(&new_fields);
137}
138
139fn decorateArgs(args: anytype, file_writer_mode: std.Io.File.Writer.Mode) DecorateArgs(@TypeOf(args)) {
140 var new_args: DecorateArgs(@TypeOf(args)) = undefined;
141 inline for (args, &new_args) |old, *new| {
142 if (@TypeOf(old) == std.debug.FormatStackTrace) {
143 new.* = .{
144 .stack_trace = old.stack_trace,
145 .file_writer_mode = file_writer_mode,
146 };
147 } else {
148 new.* = old;
149 }
150 }
151 return new_args;
152}124}
153125
154/// Returns a scoped logging namespace that logs all messages using the scope126/// Returns a scoped logging namespace that logs all messages using the scope
lib/std/testing.zig+16-26
...@@ -354,11 +354,10 @@ test expectApproxEqRel {...@@ -354,11 +354,10 @@ test expectApproxEqRel {
354 }354 }
355}355}
356356
357/// This function is intended to be used only in tests. When the two slices are not357/// This function is intended to be used only in tests. When the two slices are
358/// equal, prints diagnostics to stderr to show exactly how they are not equal (with358/// not equal, prints diagnostics to stderr to show exactly how they are not
359/// the differences highlighted in red), then returns a test failure error.359/// equal (with the differences highlighted in red), then returns a test
360/// The colorized output is optional and controlled by the return of `Io.tty.Config.detect`.360/// failure error.
361/// If your inputs are UTF-8 encoded strings, consider calling `expectEqualStrings` instead.
362pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) !void {361pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) !void {
363 const diff_index: usize = diff_index: {362 const diff_index: usize = diff_index: {
364 const shortest = @min(expected.len, actual.len);363 const shortest = @min(expected.len, actual.len);
...@@ -369,20 +368,13 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const...@@ -369,20 +368,13 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
369 break :diff_index if (expected.len == actual.len) return else shortest;368 break :diff_index if (expected.len == actual.len) return else shortest;
370 };369 };
371 if (!backend_can_print) return error.TestExpectedEqual;370 if (!backend_can_print) return error.TestExpectedEqual;
372 const stderr_w, const ttyconf = std.debug.lockStderrWriter(&.{});371 const stderr = std.debug.lockStderrWriter(&.{});
373 defer std.debug.unlockStderrWriter();372 defer std.debug.unlockStderrWriter();
374 failEqualSlices(T, expected, actual, diff_index, stderr_w, ttyconf) catch {};373 failEqualSlices(T, expected, actual, diff_index, &stderr.interface, stderr.mode) catch {};
375 return error.TestExpectedEqual;374 return error.TestExpectedEqual;
376}375}
377376
378fn failEqualSlices(377fn failEqualSlices(comptime T: type, expected: []const T, actual: []const T, diff_index: usize, w: *Io.Writer, fwm: Io.File.Writer.Mode) !void {
379 comptime T: type,
380 expected: []const T,
381 actual: []const T,
382 diff_index: usize,
383 w: *Io.Writer,
384 ttyconf: Io.tty.Config,
385) !void {
386 try w.print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index });378 try w.print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index });
387379
388 // TODO: Should this be configurable by the caller?380 // TODO: Should this be configurable by the caller?
...@@ -404,12 +396,12 @@ fn failEqualSlices(...@@ -404,12 +396,12 @@ fn failEqualSlices(
404 var differ = if (T == u8) BytesDiffer{396 var differ = if (T == u8) BytesDiffer{
405 .expected = expected_window,397 .expected = expected_window,
406 .actual = actual_window,398 .actual = actual_window,
407 .ttyconf = ttyconf,399 .file_writer_mode = fwm,
408 } else SliceDiffer(T){400 } else SliceDiffer(T){
409 .start_index = window_start,401 .start_index = window_start,
410 .expected = expected_window,402 .expected = expected_window,
411 .actual = actual_window,403 .actual = actual_window,
412 .ttyconf = ttyconf,404 .file_writer_mode = fwm,
413 };405 };
414406
415 // Print indexes as hex for slices of u8 since it's more likely to be binary data where407 // Print indexes as hex for slices of u8 since it's more likely to be binary data where
...@@ -466,7 +458,7 @@ fn SliceDiffer(comptime T: type) type {...@@ -466,7 +458,7 @@ fn SliceDiffer(comptime T: type) type {
466 start_index: usize,458 start_index: usize,
467 expected: []const T,459 expected: []const T,
468 actual: []const T,460 actual: []const T,
469 ttyconf: Io.tty.Config,461 file_writer_mode: Io.File.Writer.Mode,
470462
471 const Self = @This();463 const Self = @This();
472464
...@@ -474,13 +466,13 @@ fn SliceDiffer(comptime T: type) type {...@@ -474,13 +466,13 @@ fn SliceDiffer(comptime T: type) type {
474 for (self.expected, 0..) |value, i| {466 for (self.expected, 0..) |value, i| {
475 const full_index = self.start_index + i;467 const full_index = self.start_index + i;
476 const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;468 const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;
477 if (diff) try self.ttyconf.setColor(writer, .red);469 if (diff) try self.file_writer_mode.setColor(writer, .red);
478 if (@typeInfo(T) == .pointer) {470 if (@typeInfo(T) == .pointer) {
479 try writer.print("[{}]{*}: {any}\n", .{ full_index, value, value });471 try writer.print("[{}]{*}: {any}\n", .{ full_index, value, value });
480 } else {472 } else {
481 try writer.print("[{}]: {any}\n", .{ full_index, value });473 try writer.print("[{}]: {any}\n", .{ full_index, value });
482 }474 }
483 if (diff) try self.ttyconf.setColor(writer, .reset);475 if (diff) try self.file_writer_mode.setColor(writer, .reset);
484 }476 }
485 }477 }
486 };478 };
...@@ -489,7 +481,7 @@ fn SliceDiffer(comptime T: type) type {...@@ -489,7 +481,7 @@ fn SliceDiffer(comptime T: type) type {
489const BytesDiffer = struct {481const BytesDiffer = struct {
490 expected: []const u8,482 expected: []const u8,
491 actual: []const u8,483 actual: []const u8,
492 ttyconf: Io.tty.Config,484 file_writer_mode: Io.File.Writer.Mode,
493485
494 pub fn write(self: BytesDiffer, writer: *Io.Writer) !void {486 pub fn write(self: BytesDiffer, writer: *Io.Writer) !void {
495 var expected_iterator = std.mem.window(u8, self.expected, 16, 16);487 var expected_iterator = std.mem.window(u8, self.expected, 16, 16);
...@@ -516,7 +508,7 @@ const BytesDiffer = struct {...@@ -516,7 +508,7 @@ const BytesDiffer = struct {
516 try self.writeDiff(writer, "{c}", .{byte}, diff);508 try self.writeDiff(writer, "{c}", .{byte}, diff);
517 } else {509 } else {
518 // TODO: remove this `if` when https://github.com/ziglang/zig/issues/7600 is fixed510 // TODO: remove this `if` when https://github.com/ziglang/zig/issues/7600 is fixed
519 if (self.ttyconf == .windows_api) {511 if (self.file_writer_mode == .terminal_winapi) {
520 try self.writeDiff(writer, ".", .{}, diff);512 try self.writeDiff(writer, ".", .{}, diff);
521 continue;513 continue;
522 }514 }
...@@ -538,9 +530,9 @@ const BytesDiffer = struct {...@@ -538,9 +530,9 @@ const BytesDiffer = struct {
538 }530 }
539531
540 fn writeDiff(self: BytesDiffer, writer: *Io.Writer, comptime fmt: []const u8, args: anytype, diff: bool) !void {532 fn writeDiff(self: BytesDiffer, writer: *Io.Writer, comptime fmt: []const u8, args: anytype, diff: bool) !void {
541 if (diff) try self.ttyconf.setColor(writer, .red);533 if (diff) try self.file_writer_mode.setColor(writer, .red);
542 try writer.print(fmt, args);534 try writer.print(fmt, args);
543 if (diff) try self.ttyconf.setColor(writer, .reset);535 if (diff) try self.file_writer_mode.setColor(writer, .reset);
544 }536 }
545};537};
546538
...@@ -1162,7 +1154,6 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime...@@ -1162,7 +1154,6 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime
1162 } else |err| switch (err) {1154 } else |err| switch (err) {
1163 error.OutOfMemory => {1155 error.OutOfMemory => {
1164 if (failing_allocator_inst.allocated_bytes != failing_allocator_inst.freed_bytes) {1156 if (failing_allocator_inst.allocated_bytes != failing_allocator_inst.freed_bytes) {
1165 const tty_config: Io.tty.Config = .detect(.stderr());
1166 print(1157 print(
1167 "\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {f}",1158 "\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {f}",
1168 .{1159 .{
...@@ -1174,7 +1165,6 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime...@@ -1174,7 +1165,6 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime
1174 failing_allocator_inst.deallocations,1165 failing_allocator_inst.deallocations,
1175 std.debug.FormatStackTrace{1166 std.debug.FormatStackTrace{
1176 .stack_trace = failing_allocator_inst.getStackTrace(),1167 .stack_trace = failing_allocator_inst.getStackTrace(),
1177 .tty_config = tty_config,
1178 },1168 },
1179 },1169 },
1180 );1170 );
lib/std/zig.zig+6-6
...@@ -53,18 +53,18 @@ pub const Color = enum {...@@ -53,18 +53,18 @@ pub const Color = enum {
53 /// Assume stderr is a terminal.53 /// Assume stderr is a terminal.
54 on,54 on,
5555
56 pub fn getTtyConf(color: Color, detected: Io.tty.Config) Io.tty.Config {56 pub fn getTtyConf(color: Color, detected: Io.File.Writer.Mode) Io.File.Writer.Mode {
57 return switch (color) {57 return switch (color) {
58 .auto => detected,58 .auto => detected,
59 .on => .escape_codes,59 .on => .terminal_escaped,
60 .off => .no_color,60 .off => .streaming,
61 };61 };
62 }62 }
63 pub fn detectTtyConf(color: Color, io: Io) Io.tty.Config {63 pub fn detectTtyConf(color: Color, io: Io) Io.File.Writer.Mode {
64 return switch (color) {64 return switch (color) {
65 .auto => .detect(io, .stderr()),65 .auto => .detect(io, .stderr()),
66 .on => .escape_codes,66 .on => .terminal_escaped,
67 .off => .no_color,67 .off => .streaming,
68 };68 };
69 }69 }
70};70};
lib/std/zig/ErrorBundle.zig+31-28
...@@ -164,15 +164,20 @@ pub const RenderOptions = struct {...@@ -164,15 +164,20 @@ pub const RenderOptions = struct {
164164
165pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions, color: std.zig.Color) void {165pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions, color: std.zig.Color) void {
166 var buffer: [256]u8 = undefined;166 var buffer: [256]u8 = undefined;
167 const w, const ttyconf = std.debug.lockStderrWriter(&buffer);167 const stderr = std.debug.lockStderrWriter(&buffer);
168 defer std.debug.unlockStderrWriter();168 defer std.debug.unlockStderrWriter();
169 renderToWriter(eb, options, w, color.getTtyConf(ttyconf)) catch return;169 renderToWriter(eb, options, &stderr.interface, color.getTtyConf(stderr.mode)) catch return;
170}170}
171171
172pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, w: *Writer, ttyconf: Io.tty.Config) (Writer.Error || std.posix.UnexpectedError)!void {172pub fn renderToWriter(
173 eb: ErrorBundle,
174 options: RenderOptions,
175 w: *Writer,
176 fwm: Io.File.Writer.Mode,
177) Io.File.Writer.Mode.SetColorError!void {
173 if (eb.extra.len == 0) return;178 if (eb.extra.len == 0) return;
174 for (eb.getMessages()) |err_msg| {179 for (eb.getMessages()) |err_msg| {
175 try renderErrorMessageToWriter(eb, options, err_msg, w, ttyconf, "error", .red, 0);180 try renderErrorMessageToWriter(eb, options, err_msg, w, fwm, "error", .red, 0);
176 }181 }
177182
178 if (options.include_log_text) {183 if (options.include_log_text) {
...@@ -189,18 +194,18 @@ fn renderErrorMessageToWriter(...@@ -189,18 +194,18 @@ fn renderErrorMessageToWriter(
189 options: RenderOptions,194 options: RenderOptions,
190 err_msg_index: MessageIndex,195 err_msg_index: MessageIndex,
191 w: *Writer,196 w: *Writer,
192 ttyconf: Io.tty.Config,197 fwm: Io.File.Writer.Mode,
193 kind: []const u8,198 kind: []const u8,
194 color: Io.tty.Color,199 color: Io.File.Writer.Color,
195 indent: usize,200 indent: usize,
196) (Writer.Error || std.posix.UnexpectedError)!void {201) Io.File.Writer.Mode.SetColorError!void {
197 const err_msg = eb.getErrorMessage(err_msg_index);202 const err_msg = eb.getErrorMessage(err_msg_index);
198 if (err_msg.src_loc != .none) {203 if (err_msg.src_loc != .none) {
199 const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));204 const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
200 var prefix: Writer.Discarding = .init(&.{});205 var prefix: Writer.Discarding = .init(&.{});
201 try w.splatByteAll(' ', indent);206 try w.splatByteAll(' ', indent);
202 prefix.count += indent;207 prefix.count += indent;
203 try ttyconf.setColor(w, .bold);208 try fwm.setColor(w, .bold);
204 try w.print("{s}:{d}:{d}: ", .{209 try w.print("{s}:{d}:{d}: ", .{
205 eb.nullTerminatedString(src.data.src_path),210 eb.nullTerminatedString(src.data.src_path),
206 src.data.line + 1,211 src.data.line + 1,
...@@ -211,7 +216,7 @@ fn renderErrorMessageToWriter(...@@ -211,7 +216,7 @@ fn renderErrorMessageToWriter(
211 src.data.line + 1,216 src.data.line + 1,
212 src.data.column + 1,217 src.data.column + 1,
213 });218 });
214 try ttyconf.setColor(w, color);219 try fwm.setColor(w, color);
215 try w.writeAll(kind);220 try w.writeAll(kind);
216 prefix.count += kind.len;221 prefix.count += kind.len;
217 try w.writeAll(": ");222 try w.writeAll(": ");
...@@ -219,17 +224,17 @@ fn renderErrorMessageToWriter(...@@ -219,17 +224,17 @@ fn renderErrorMessageToWriter(
219 // This is the length of the part before the error message:224 // This is the length of the part before the error message:
220 // e.g. "file.zig:4:5: error: "225 // e.g. "file.zig:4:5: error: "
221 const prefix_len: usize = @intCast(prefix.count);226 const prefix_len: usize = @intCast(prefix.count);
222 try ttyconf.setColor(w, .reset);227 try fwm.setColor(w, .reset);
223 try ttyconf.setColor(w, .bold);228 try fwm.setColor(w, .bold);
224 if (err_msg.count == 1) {229 if (err_msg.count == 1) {
225 try writeMsg(eb, err_msg, w, prefix_len);230 try writeMsg(eb, err_msg, w, prefix_len);
226 try w.writeByte('\n');231 try w.writeByte('\n');
227 } else {232 } else {
228 try writeMsg(eb, err_msg, w, prefix_len);233 try writeMsg(eb, err_msg, w, prefix_len);
229 try ttyconf.setColor(w, .dim);234 try fwm.setColor(w, .dim);
230 try w.print(" ({d} times)\n", .{err_msg.count});235 try w.print(" ({d} times)\n", .{err_msg.count});
231 }236 }
232 try ttyconf.setColor(w, .reset);237 try fwm.setColor(w, .reset);
233 if (src.data.source_line != 0 and options.include_source_line) {238 if (src.data.source_line != 0 and options.include_source_line) {
234 const line = eb.nullTerminatedString(src.data.source_line);239 const line = eb.nullTerminatedString(src.data.source_line);
235 for (line) |b| switch (b) {240 for (line) |b| switch (b) {
...@@ -242,19 +247,19 @@ fn renderErrorMessageToWriter(...@@ -242,19 +247,19 @@ fn renderErrorMessageToWriter(
242 // -1 since span.main includes the caret247 // -1 since span.main includes the caret
243 const after_caret = src.data.span_end -| src.data.span_main -| 1;248 const after_caret = src.data.span_end -| src.data.span_main -| 1;
244 try w.splatByteAll(' ', src.data.column - before_caret);249 try w.splatByteAll(' ', src.data.column - before_caret);
245 try ttyconf.setColor(w, .green);250 try fwm.setColor(w, .green);
246 try w.splatByteAll('~', before_caret);251 try w.splatByteAll('~', before_caret);
247 try w.writeByte('^');252 try w.writeByte('^');
248 try w.splatByteAll('~', after_caret);253 try w.splatByteAll('~', after_caret);
249 try w.writeByte('\n');254 try w.writeByte('\n');
250 try ttyconf.setColor(w, .reset);255 try fwm.setColor(w, .reset);
251 }256 }
252 for (eb.getNotes(err_msg_index)) |note| {257 for (eb.getNotes(err_msg_index)) |note| {
253 try renderErrorMessageToWriter(eb, options, note, w, ttyconf, "note", .cyan, indent);258 try renderErrorMessageToWriter(eb, options, note, w, fwm, "note", .cyan, indent);
254 }259 }
255 if (src.data.reference_trace_len > 0 and options.include_reference_trace) {260 if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
256 try ttyconf.setColor(w, .reset);261 try fwm.setColor(w, .reset);
257 try ttyconf.setColor(w, .dim);262 try fwm.setColor(w, .dim);
258 try w.print("referenced by:\n", .{});263 try w.print("referenced by:\n", .{});
259 var ref_index = src.end;264 var ref_index = src.end;
260 for (0..src.data.reference_trace_len) |_| {265 for (0..src.data.reference_trace_len) |_| {
...@@ -281,25 +286,25 @@ fn renderErrorMessageToWriter(...@@ -281,25 +286,25 @@ fn renderErrorMessageToWriter(
281 );286 );
282 }287 }
283 }288 }
284 try ttyconf.setColor(w, .reset);289 try fwm.setColor(w, .reset);
285 }290 }
286 } else {291 } else {
287 try ttyconf.setColor(w, color);292 try fwm.setColor(w, color);
288 try w.splatByteAll(' ', indent);293 try w.splatByteAll(' ', indent);
289 try w.writeAll(kind);294 try w.writeAll(kind);
290 try w.writeAll(": ");295 try w.writeAll(": ");
291 try ttyconf.setColor(w, .reset);296 try fwm.setColor(w, .reset);
292 const msg = eb.nullTerminatedString(err_msg.msg);297 const msg = eb.nullTerminatedString(err_msg.msg);
293 if (err_msg.count == 1) {298 if (err_msg.count == 1) {
294 try w.print("{s}\n", .{msg});299 try w.print("{s}\n", .{msg});
295 } else {300 } else {
296 try w.print("{s}", .{msg});301 try w.print("{s}", .{msg});
297 try ttyconf.setColor(w, .dim);302 try fwm.setColor(w, .dim);
298 try w.print(" ({d} times)\n", .{err_msg.count});303 try w.print(" ({d} times)\n", .{err_msg.count});
299 }304 }
300 try ttyconf.setColor(w, .reset);305 try fwm.setColor(w, .reset);
301 for (eb.getNotes(err_msg_index)) |note| {306 for (eb.getNotes(err_msg_index)) |note| {
302 try renderErrorMessageToWriter(eb, options, note, w, ttyconf, "note", .cyan, indent + 4);307 try renderErrorMessageToWriter(eb, options, note, w, fwm, "note", .cyan, indent + 4);
303 }308 }
304 }309 }
305}310}
...@@ -806,12 +811,10 @@ pub const Wip = struct {...@@ -806,12 +811,10 @@ pub const Wip = struct {
806 };811 };
807 defer bundle.deinit(std.testing.allocator);812 defer bundle.deinit(std.testing.allocator);
808813
809 const ttyconf: Io.tty.Config = .no_color;
810
811 var bundle_buf: Writer.Allocating = .init(std.testing.allocator);814 var bundle_buf: Writer.Allocating = .init(std.testing.allocator);
812 const bundle_bw = &bundle_buf.interface;815 const bundle_bw = &bundle_buf.interface;
813 defer bundle_buf.deinit();816 defer bundle_buf.deinit();
814 try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_bw);817 try bundle.renderToWriter(bundle_bw);
815818
816 var copy = copy: {819 var copy = copy: {
817 var wip: ErrorBundle.Wip = undefined;820 var wip: ErrorBundle.Wip = undefined;
...@@ -827,7 +830,7 @@ pub const Wip = struct {...@@ -827,7 +830,7 @@ pub const Wip = struct {
827 var copy_buf: Writer.Allocating = .init(std.testing.allocator);830 var copy_buf: Writer.Allocating = .init(std.testing.allocator);
828 const copy_bw = &copy_buf.interface;831 const copy_bw = &copy_buf.interface;
829 defer copy_buf.deinit();832 defer copy_buf.deinit();
830 try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_bw);833 try copy.renderToWriter(copy_bw);
831834
832 try std.testing.expectEqualStrings(bundle_bw.written(), copy_bw.written());835 try std.testing.expectEqualStrings(bundle_bw.written(), copy_bw.written());
833 }836 }