aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2025-12-10 20:55:11 -0800
committerAndrew Kelley <andrew@ziglang.org>2025-12-23 22:15:09 -0800
commitb042e935228db5d46271d4d3d17afeb9ba5d7ce3 (patch)
treefd02941ee06e6abed96f0f1193a27ce1dfe41cc3
parent7837d975dcaa17ff22f536607c4ff6db7b697b04 (diff)
downloadzig-b042e935228db5d46271d4d3d17afeb9ba5d7ce3.tar.gz
zig-b042e935228db5d46271d4d3d17afeb9ba5d7ce3.zip
std: update tty config references in the build system
-rw-r--r--lib/compiler/build_runner.zig208
-rw-r--r--lib/std/Build.zig60
-rw-r--r--lib/std/Build/Fuzz.zig20
-rw-r--r--lib/std/Build/Step.zig9
-rw-r--r--lib/std/Build/Step/Compile.zig10
-rw-r--r--lib/std/Build/Step/Run.zig68
-rw-r--r--lib/std/Build/WebServer.zig4
-rw-r--r--lib/std/Io/File/Writer.zig41
-rw-r--r--lib/std/debug.zig2
-rw-r--r--lib/std/log.zig30
-rw-r--r--lib/std/testing.zig42
-rw-r--r--lib/std/zig.zig12
-rw-r--r--lib/std/zig/ErrorBundle.zig59
13 files changed, 271 insertions, 294 deletions
diff --git a/lib/compiler/build_runner.zig b/lib/compiler/build_runner.zig
index 05cd21ecdb..acba1a4621 100644
--- a/lib/compiler/build_runner.zig
+++ b/lib/compiler/build_runner.zig
@@ -14,7 +14,6 @@ const WebServer = std.Build.WebServer;
const Allocator = std.mem.Allocator;
const fatal = std.process.fatal;
const Writer = std.Io.Writer;
-const tty = std.Io.tty;
pub const root = @import("@build");
pub const dependencies = @import("@dependencies");
@@ -435,9 +434,7 @@ pub fn main() !void {
if (builtin.single_threaded) fatal("'--webui' is not yet supported on single-threaded hosts", .{});
}
- const ttyconf = color.detectTtyConf(io);
-
- const main_progress_node = std.Progress.start(.{
+ const main_progress_node = std.Progress.start(io, .{
.disable_printing = (color == .off),
});
defer main_progress_node.end();
@@ -509,8 +506,6 @@ pub fn main() !void {
.error_style = error_style,
.multiline_errors = multiline_errors,
.summary = summary orelse if (watch or webui_listen != null) .line else .failures,
-
- .ttyconf = ttyconf,
};
defer {
run.memory_blocked_steps.deinit(gpa);
@@ -524,10 +519,10 @@ pub fn main() !void {
prepare(arena, builder, targets.items, &run, graph.random_seed) catch |err| switch (err) {
error.DependencyLoopDetected => {
- // Perhaps in the future there could be an Advanced Options flag such as
- // --debug-build-runner-leaks which would make this code return instead of
- // calling exit.
- std.debug.lockStdErr();
+ // Perhaps in the future there could be an Advanced Options flag
+ // such as --debug-build-runner-leaks which would make this code
+ // return instead of calling exit.
+ _ = std.debug.lockStderrWriter(&.{});
process.exit(1);
},
else => |e| return e,
@@ -545,7 +540,6 @@ pub fn main() !void {
if (builtin.single_threaded) unreachable; // `fatal` above
break :ws .init(.{
.gpa = gpa,
- .ttyconf = ttyconf,
.graph = &graph,
.all_steps = run.step_stack.keys(),
.root_prog_node = main_progress_node,
@@ -560,9 +554,9 @@ pub fn main() !void {
}
rebuild: while (true) : (if (run.error_style.clearOnUpdate()) {
- const bw, _ = std.debug.lockStderrWriter(&stdio_buffer_allocation);
+ const stderr = std.debug.lockStderrWriter(&stdio_buffer_allocation);
defer std.debug.unlockStderrWriter();
- try bw.writeAll("\x1B[2J\x1B[3J\x1B[H");
+ try stderr.writeAllUnescaped("\x1B[2J\x1B[3J\x1B[H");
}) {
if (run.web_server) |*ws| ws.startBuild();
@@ -663,9 +657,6 @@ const Run = struct {
memory_blocked_steps: std.ArrayList(*Step),
/// Allocated into `gpa`.
step_stack: std.AutoArrayHashMapUnmanaged(*Step, void),
- /// Similar to the `tty.Config` returned by `std.debug.lockStderrWriter`,
- /// but also respects the '--color' flag.
- ttyconf: tty.Config,
claimed_rss: usize,
error_style: ErrorStyle,
@@ -839,7 +830,6 @@ fn runStepNames(
var f = std.Build.Fuzz.init(
gpa,
io,
- run.ttyconf,
step_stack.keys(),
parent_prog_node,
mode,
@@ -866,18 +856,20 @@ fn runStepNames(
.none => break :summary,
}
- const w, _ = std.debug.lockStderrWriter(&stdio_buffer_allocation);
+ const stderr = std.debug.lockStderrWriter(&stdio_buffer_allocation);
defer std.debug.unlockStderrWriter();
- const ttyconf = run.ttyconf;
+
+ const w = &stderr.interface;
+ const fwm = stderr.mode;
const total_count = success_count + failure_count + pending_count + skipped_count;
- ttyconf.setColor(w, .cyan) catch {};
- ttyconf.setColor(w, .bold) catch {};
+ fwm.setColor(w, .cyan) catch {};
+ fwm.setColor(w, .bold) catch {};
w.writeAll("Build Summary: ") catch {};
- ttyconf.setColor(w, .reset) catch {};
+ fwm.setColor(w, .reset) catch {};
w.print("{d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
{
- ttyconf.setColor(w, .dim) catch {};
+ fwm.setColor(w, .dim) catch {};
var first = true;
if (skipped_count > 0) {
w.print("{s}{d} skipped", .{ if (first) " (" else ", ", skipped_count }) catch {};
@@ -888,12 +880,12 @@ fn runStepNames(
first = false;
}
if (!first) w.writeByte(')') catch {};
- ttyconf.setColor(w, .reset) catch {};
+ fwm.setColor(w, .reset) catch {};
}
if (test_count > 0) {
w.print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
- ttyconf.setColor(w, .dim) catch {};
+ fwm.setColor(w, .dim) catch {};
var first = true;
if (test_skip_count > 0) {
w.print("{s}{d} skipped", .{ if (first) " (" else ", ", test_skip_count }) catch {};
@@ -912,7 +904,7 @@ fn runStepNames(
first = false;
}
if (!first) w.writeByte(')') catch {};
- ttyconf.setColor(w, .reset) catch {};
+ fwm.setColor(w, .reset) catch {};
}
w.writeAll("\n") catch {};
@@ -926,7 +918,7 @@ fn runStepNames(
var print_node: PrintNode = .{ .parent = null };
if (step_names.len == 0) {
print_node.last = true;
- printTreeStep(b, b.default_step, run, w, ttyconf, &print_node, &step_stack_copy) catch {};
+ printTreeStep(b, b.default_step, run, w, fwm, &print_node, &step_stack_copy) catch {};
} else {
const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {
var i: usize = step_names.len;
@@ -945,7 +937,7 @@ fn runStepNames(
for (step_names, 0..) |step_name, i| {
const tls = b.top_level_steps.get(step_name).?;
print_node.last = i + 1 == last_index;
- printTreeStep(b, &tls.step, run, w, ttyconf, &print_node, &step_stack_copy) catch {};
+ printTreeStep(b, &tls.step, run, w, fwm, &print_node, &step_stack_copy) catch {};
}
}
w.writeByte('\n') catch {};
@@ -962,7 +954,7 @@ fn runStepNames(
if (run.error_style.verboseContext()) break :code 1; // failure; print build command
break :code 2; // failure; do not print build command
};
- std.debug.lockStdErr();
+ _ = std.debug.lockStderrWriter(&.{});
process.exit(code);
}
@@ -971,31 +963,31 @@ const PrintNode = struct {
last: bool = false,
};
-fn printPrefix(node: *PrintNode, stderr: *Writer, ttyconf: tty.Config) !void {
+fn printPrefix(node: *PrintNode, w: *Writer, fwm: File.Writer.Mode) !void {
const parent = node.parent orelse return;
if (parent.parent == null) return;
- try printPrefix(parent, stderr, ttyconf);
+ try printPrefix(parent, w, fwm);
if (parent.last) {
- try stderr.writeAll(" ");
+ try w.writeAll(" ");
} else {
- try stderr.writeAll(switch (ttyconf) {
- .no_color, .windows_api => "| ",
- .escape_codes => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │
+ try w.writeAll(switch (fwm) {
+ .terminal_escaped => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │
+ else => "| ",
});
}
}
-fn printChildNodePrefix(stderr: *Writer, ttyconf: tty.Config) !void {
- try stderr.writeAll(switch (ttyconf) {
- .no_color, .windows_api => "+- ",
- .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
+fn printChildNodePrefix(w: *Writer, fwm: File.Writer.Mode) !void {
+ try w.writeAll(switch (fwm) {
+ .terminal_escaped => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
+ else => "+- ",
});
}
fn printStepStatus(
s: *Step,
stderr: *Writer,
- ttyconf: tty.Config,
+ fwm: File.Writer.Mode,
run: *const Run,
) !void {
switch (s.state) {
@@ -1005,13 +997,13 @@ fn printStepStatus(
.running => unreachable,
.dependency_failure => {
- try ttyconf.setColor(stderr, .dim);
+ try fwm.setColor(stderr, .dim);
try stderr.writeAll(" transitive failure\n");
- try ttyconf.setColor(stderr, .reset);
+ try fwm.setColor(stderr, .reset);
},
.success => {
- try ttyconf.setColor(stderr, .green);
+ try fwm.setColor(stderr, .green);
if (s.result_cached) {
try stderr.writeAll(" cached");
} else if (s.test_results.test_count > 0) {
@@ -1019,19 +1011,19 @@ fn printStepStatus(
assert(s.test_results.test_count == pass_count + s.test_results.skip_count);
try stderr.print(" {d} pass", .{pass_count});
if (s.test_results.skip_count > 0) {
- try ttyconf.setColor(stderr, .reset);
+ try fwm.setColor(stderr, .reset);
try stderr.writeAll(", ");
- try ttyconf.setColor(stderr, .yellow);
+ try fwm.setColor(stderr, .yellow);
try stderr.print("{d} skip", .{s.test_results.skip_count});
}
- try ttyconf.setColor(stderr, .reset);
+ try fwm.setColor(stderr, .reset);
try stderr.print(" ({d} total)", .{s.test_results.test_count});
} else {
try stderr.writeAll(" success");
}
- try ttyconf.setColor(stderr, .reset);
+ try fwm.setColor(stderr, .reset);
if (s.result_duration_ns) |ns| {
- try ttyconf.setColor(stderr, .dim);
+ try fwm.setColor(stderr, .dim);
if (ns >= std.time.ns_per_min) {
try stderr.print(" {d}m", .{ns / std.time.ns_per_min});
} else if (ns >= std.time.ns_per_s) {
@@ -1043,11 +1035,11 @@ fn printStepStatus(
} else {
try stderr.print(" {d}ns", .{ns});
}
- try ttyconf.setColor(stderr, .reset);
+ try fwm.setColor(stderr, .reset);
}
if (s.result_peak_rss != 0) {
const rss = s.result_peak_rss;
- try ttyconf.setColor(stderr, .dim);
+ try fwm.setColor(stderr, .dim);
if (rss >= 1000_000_000) {
try stderr.print(" MaxRSS:{d}G", .{rss / 1000_000_000});
} else if (rss >= 1000_000) {
@@ -1057,25 +1049,25 @@ fn printStepStatus(
} else {
try stderr.print(" MaxRSS:{d}B", .{rss});
}
- try ttyconf.setColor(stderr, .reset);
+ try fwm.setColor(stderr, .reset);
}
try stderr.writeAll("\n");
},
.skipped, .skipped_oom => |skip| {
- try ttyconf.setColor(stderr, .yellow);
+ try fwm.setColor(stderr, .yellow);
try stderr.writeAll(" skipped");
if (skip == .skipped_oom) {
try stderr.writeAll(" (not enough memory)");
- try ttyconf.setColor(stderr, .dim);
+ try fwm.setColor(stderr, .dim);
try stderr.print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
- try ttyconf.setColor(stderr, .yellow);
+ try fwm.setColor(stderr, .yellow);
}
try stderr.writeAll("\n");
- try ttyconf.setColor(stderr, .reset);
+ try fwm.setColor(stderr, .reset);
},
.failure => {
- try printStepFailure(s, stderr, ttyconf, false);
- try ttyconf.setColor(stderr, .reset);
+ try printStepFailure(s, stderr, fwm, false);
+ try fwm.setColor(stderr, .reset);
},
}
}
@@ -1083,48 +1075,48 @@ fn printStepStatus(
fn printStepFailure(
s: *Step,
stderr: *Writer,
- ttyconf: tty.Config,
+ fwm: File.Writer.Mode,
dim: bool,
) !void {
if (s.result_error_bundle.errorMessageCount() > 0) {
- try ttyconf.setColor(stderr, .red);
+ try fwm.setColor(stderr, .red);
try stderr.print(" {d} errors\n", .{
s.result_error_bundle.errorMessageCount(),
});
} else if (!s.test_results.isSuccess()) {
// These first values include all of the test "statuses". Every test is either passsed,
// skipped, failed, crashed, or timed out.
- try ttyconf.setColor(stderr, .green);
+ try fwm.setColor(stderr, .green);
try stderr.print(" {d} pass", .{s.test_results.passCount()});
- try ttyconf.setColor(stderr, .reset);
- if (dim) try ttyconf.setColor(stderr, .dim);
+ try fwm.setColor(stderr, .reset);
+ if (dim) try fwm.setColor(stderr, .dim);
if (s.test_results.skip_count > 0) {
try stderr.writeAll(", ");
- try ttyconf.setColor(stderr, .yellow);
+ try fwm.setColor(stderr, .yellow);
try stderr.print("{d} skip", .{s.test_results.skip_count});
- try ttyconf.setColor(stderr, .reset);
- if (dim) try ttyconf.setColor(stderr, .dim);
+ try fwm.setColor(stderr, .reset);
+ if (dim) try fwm.setColor(stderr, .dim);
}
if (s.test_results.fail_count > 0) {
try stderr.writeAll(", ");
- try ttyconf.setColor(stderr, .red);
+ try fwm.setColor(stderr, .red);
try stderr.print("{d} fail", .{s.test_results.fail_count});
- try ttyconf.setColor(stderr, .reset);
- if (dim) try ttyconf.setColor(stderr, .dim);
+ try fwm.setColor(stderr, .reset);
+ if (dim) try fwm.setColor(stderr, .dim);
}
if (s.test_results.crash_count > 0) {
try stderr.writeAll(", ");
- try ttyconf.setColor(stderr, .red);
+ try fwm.setColor(stderr, .red);
try stderr.print("{d} crash", .{s.test_results.crash_count});
- try ttyconf.setColor(stderr, .reset);
- if (dim) try ttyconf.setColor(stderr, .dim);
+ try fwm.setColor(stderr, .reset);
+ if (dim) try fwm.setColor(stderr, .dim);
}
if (s.test_results.timeout_count > 0) {
try stderr.writeAll(", ");
- try ttyconf.setColor(stderr, .red);
+ try fwm.setColor(stderr, .red);
try stderr.print("{d} timeout", .{s.test_results.timeout_count});
- try ttyconf.setColor(stderr, .reset);
- if (dim) try ttyconf.setColor(stderr, .dim);
+ try fwm.setColor(stderr, .reset);
+ if (dim) try fwm.setColor(stderr, .dim);
}
try stderr.print(" ({d} total)", .{s.test_results.test_count});
@@ -1134,10 +1126,10 @@ fn printStepFailure(
// 2 pass, 1 skip, 2 fail (5 total); 2 leaks
if (s.test_results.leak_count > 0) {
try stderr.writeAll("; ");
- try ttyconf.setColor(stderr, .red);
+ try fwm.setColor(stderr, .red);
try stderr.print("{d} leaks", .{s.test_results.leak_count});
- try ttyconf.setColor(stderr, .reset);
- if (dim) try ttyconf.setColor(stderr, .dim);
+ try fwm.setColor(stderr, .reset);
+ if (dim) try fwm.setColor(stderr, .dim);
}
// It's usually not helpful to know how many error logs there were because they tend to
@@ -1151,19 +1143,19 @@ fn printStepFailure(
};
if (show_err_logs) {
try stderr.writeAll("; ");
- try ttyconf.setColor(stderr, .red);
+ try fwm.setColor(stderr, .red);
try stderr.print("{d} error logs", .{s.test_results.log_err_count});
- try ttyconf.setColor(stderr, .reset);
- if (dim) try ttyconf.setColor(stderr, .dim);
+ try fwm.setColor(stderr, .reset);
+ if (dim) try fwm.setColor(stderr, .dim);
}
try stderr.writeAll("\n");
} else if (s.result_error_msgs.items.len > 0) {
- try ttyconf.setColor(stderr, .red);
+ try fwm.setColor(stderr, .red);
try stderr.writeAll(" failure\n");
} else {
assert(s.result_stderr.len > 0);
- try ttyconf.setColor(stderr, .red);
+ try fwm.setColor(stderr, .red);
try stderr.writeAll(" stderr\n");
}
}
@@ -1173,7 +1165,7 @@ fn printTreeStep(
s: *Step,
run: *const Run,
stderr: *Writer,
- ttyconf: tty.Config,
+ fwm: File.Writer.Mode,
parent_node: *PrintNode,
step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
) !void {
@@ -1186,26 +1178,26 @@ fn printTreeStep(
.failures => s.state == .success,
};
if (skip) return;
- try printPrefix(parent_node, stderr, ttyconf);
+ try printPrefix(parent_node, stderr, fwm);
if (parent_node.parent != null) {
if (parent_node.last) {
- try printChildNodePrefix(stderr, ttyconf);
+ try printChildNodePrefix(stderr, fwm);
} else {
- try stderr.writeAll(switch (ttyconf) {
- .no_color, .windows_api => "+- ",
- .escape_codes => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─
+ try stderr.writeAll(switch (fwm) {
+ .terminal_escaped => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─
+ else => "+- ",
});
}
}
- if (!first) try ttyconf.setColor(stderr, .dim);
+ if (!first) try fwm.setColor(stderr, .dim);
// dep_prefix omitted here because it is redundant with the tree.
try stderr.writeAll(s.name);
if (first) {
- try printStepStatus(s, stderr, ttyconf, run);
+ try printStepStatus(s, stderr, fwm, run);
const last_index = if (summary == .all) s.dependencies.items.len -| 1 else blk: {
var i: usize = s.dependencies.items.len;
@@ -1227,7 +1219,7 @@ fn printTreeStep(
.parent = parent_node,
.last = i == last_index,
};
- try printTreeStep(b, dep, run, stderr, ttyconf, &print_node, step_stack);
+ try printTreeStep(b, dep, run, stderr, fwm, &print_node, step_stack);
}
} else {
if (s.dependencies.items.len == 0) {
@@ -1237,7 +1229,7 @@ fn printTreeStep(
s.dependencies.items.len,
});
}
- try ttyconf.setColor(stderr, .reset);
+ try fwm.setColor(stderr, .reset);
}
}
@@ -1368,7 +1360,6 @@ fn workerMakeOneStep(
.progress_node = sub_prog_node,
.watch = run.watch,
.web_server = if (run.web_server) |*ws| ws else null,
- .ttyconf = run.ttyconf,
.unit_test_timeout_ns = run.unit_test_timeout_ns,
.gpa = gpa,
});
@@ -1378,10 +1369,9 @@ fn workerMakeOneStep(
const show_error_msgs = s.result_error_msgs.items.len > 0;
const show_stderr = s.result_stderr.len > 0;
if (show_error_msgs or show_compile_errors or show_stderr) {
- const bw, _ = std.debug.lockStderrWriter(&stdio_buffer_allocation);
+ const stderr = std.debug.lockStderrWriter(&stdio_buffer_allocation);
defer std.debug.unlockStderrWriter();
- const ttyconf = run.ttyconf;
- printErrorMessages(gpa, s, .{}, bw, ttyconf, run.error_style, run.multiline_errors) catch {};
+ printErrorMessages(gpa, s, .{}, &stderr.interface, stderr.mode, run.error_style, run.multiline_errors) catch {};
}
handle_result: {
@@ -1449,7 +1439,7 @@ pub fn printErrorMessages(
failing_step: *Step,
options: std.zig.ErrorBundle.RenderOptions,
stderr: *Writer,
- ttyconf: tty.Config,
+ fwm: File.Writer.Mode,
error_style: ErrorStyle,
multiline_errors: MultilineErrors,
) !void {
@@ -1464,29 +1454,29 @@ pub fn printErrorMessages(
}
// Now, `step_stack` has the subtree that we want to print, in reverse order.
- try ttyconf.setColor(stderr, .dim);
+ try fwm.setColor(stderr, .dim);
var indent: usize = 0;
while (step_stack.pop()) |s| : (indent += 1) {
if (indent > 0) {
try stderr.splatByteAll(' ', (indent - 1) * 3);
- try printChildNodePrefix(stderr, ttyconf);
+ try printChildNodePrefix(stderr, fwm);
}
try stderr.writeAll(s.name);
if (s == failing_step) {
- try printStepFailure(s, stderr, ttyconf, true);
+ try printStepFailure(s, stderr, fwm, true);
} else {
try stderr.writeAll("\n");
}
}
- try ttyconf.setColor(stderr, .reset);
+ try fwm.setColor(stderr, .reset);
} else {
// Just print the failing step itself.
- try ttyconf.setColor(stderr, .dim);
+ try fwm.setColor(stderr, .dim);
try stderr.writeAll(failing_step.name);
- try printStepFailure(failing_step, stderr, ttyconf, true);
- try ttyconf.setColor(stderr, .reset);
+ try printStepFailure(failing_step, stderr, fwm, true);
+ try fwm.setColor(stderr, .reset);
}
if (failing_step.result_stderr.len > 0) {
@@ -1496,12 +1486,12 @@ pub fn printErrorMessages(
}
}
- try failing_step.result_error_bundle.renderToWriter(options, stderr, ttyconf);
+ try failing_step.result_error_bundle.renderToWriter(options, stderr, fwm);
for (failing_step.result_error_msgs.items) |msg| {
- try ttyconf.setColor(stderr, .red);
+ try fwm.setColor(stderr, .red);
try stderr.writeAll("error:");
- try ttyconf.setColor(stderr, .reset);
+ try fwm.setColor(stderr, .reset);
if (std.mem.indexOfScalar(u8, msg, '\n') == null) {
try stderr.print(" {s}\n", .{msg});
} else switch (multiline_errors) {
@@ -1519,9 +1509,9 @@ pub fn printErrorMessages(
if (error_style.verboseContext()) {
if (failing_step.result_failed_command) |cmd_str| {
- try ttyconf.setColor(stderr, .red);
+ try fwm.setColor(stderr, .red);
try stderr.writeAll("failed command: ");
- try ttyconf.setColor(stderr, .reset);
+ try fwm.setColor(stderr, .reset);
try stderr.writeAll(cmd_str);
try stderr.writeByte('\n');
}
diff --git a/lib/std/Build.zig b/lib/std/Build.zig
index ae2ab1c4d0..085254fdde 100644
--- a/lib/std/Build.zig
+++ b/lib/std/Build.zig
@@ -5,9 +5,8 @@ const std = @import("std.zig");
const Io = std.Io;
const fs = std.fs;
const mem = std.mem;
-const debug = std.debug;
const panic = std.debug.panic;
-const assert = debug.assert;
+const assert = std.debug.assert;
const log = std.log;
const StringHashMap = std.StringHashMap;
const Allocator = std.mem.Allocator;
@@ -2090,7 +2089,7 @@ pub fn dependencyFromBuildZig(
}
const full_path = b.pathFromRoot("build.zig.zon");
- debug.panic("'{}' is not a build.zig struct of a dependency in '{s}'", .{ build_zig, full_path });
+ std.debug.panic("'{}' is not a build.zig struct of a dependency in '{s}'", .{ build_zig, full_path });
}
fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool {
@@ -2249,9 +2248,9 @@ pub const GeneratedFile = struct {
pub fn getPath2(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) []const u8 {
return gen.path orelse {
- const w, const ttyconf = debug.lockStderrWriter(&.{});
- dumpBadGetPathHelp(gen.step, w, ttyconf, src_builder, asking_step) catch {};
- debug.unlockStderrWriter();
+ const stderr = std.debug.lockStderrWriter(&.{});
+ dumpBadGetPathHelp(gen.step, &stderr.interface, stderr.mode, src_builder, asking_step) catch {};
+ std.debug.unlockStderrWriter();
@panic("misconfigured build script");
};
}
@@ -2458,9 +2457,9 @@ pub const LazyPath = union(enum) {
var file_path: Cache.Path = .{
.root_dir = Cache.Directory.cwd(),
.sub_path = gen.file.path orelse {
- const w, const ttyconf = debug.lockStderrWriter(&.{});
- dumpBadGetPathHelp(gen.file.step, w, ttyconf, src_builder, asking_step) catch {};
- debug.unlockStderrWriter();
+ const stderr = std.debug.lockStderrWriter(&.{});
+ dumpBadGetPathHelp(gen.file.step, &stderr.interface, stderr.mode, src_builder, asking_step) catch {};
+ std.debug.unlockStderrWriter();
@panic("misconfigured build script");
},
};
@@ -2550,37 +2549,40 @@ fn dumpBadDirnameHelp(
comptime msg: []const u8,
args: anytype,
) anyerror!void {
- const w, const tty_config = debug.lockStderrWriter(&.{});
- defer debug.unlockStderrWriter();
+ const stderr = std.debug.lockStderrWriter(&.{});
+ defer std.debug.unlockStderrWriter();
+
+ const w = &stderr.interface;
+ const fwm = stderr.mode;
try w.print(msg, args);
if (fail_step) |s| {
- tty_config.setColor(w, .red) catch {};
+ fwm.setColor(w, .red) catch {};
try w.writeAll(" The step was created by this stack trace:\n");
- tty_config.setColor(w, .reset) catch {};
+ fwm.setColor(w, .reset) catch {};
- s.dump(w, tty_config);
+ s.dump(w, fwm);
}
if (asking_step) |as| {
- tty_config.setColor(w, .red) catch {};
+ fwm.setColor(w, .red) catch {};
try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
- tty_config.setColor(w, .reset) catch {};
+ fwm.setColor(w, .reset) catch {};
- as.dump(w, tty_config);
+ as.dump(w, fwm);
}
- tty_config.setColor(w, .red) catch {};
+ fwm.setColor(w, .red) catch {};
try w.writeAll(" Hope that helps. Proceeding to panic.\n");
- tty_config.setColor(w, .reset) catch {};
+ fwm.setColor(w, .reset) catch {};
}
/// In this function the stderr mutex has already been locked.
pub fn dumpBadGetPathHelp(
s: *Step,
- w: *std.Io.Writer,
- tty_config: std.Io.tty.Config,
+ w: *Io.Writer,
+ fwm: File.Writer.Mode,
src_builder: *Build,
asking_step: ?*Step,
) anyerror!void {
@@ -2594,21 +2596,21 @@ pub fn dumpBadGetPathHelp(
s.name,
});
- tty_config.setColor(w, .red) catch {};
+ fwm.setColor(w, .red) catch {};
try w.writeAll(" The step was created by this stack trace:\n");
- tty_config.setColor(w, .reset) catch {};
+ fwm.setColor(w, .reset) catch {};
- s.dump(w, tty_config);
+ s.dump(w, fwm);
if (asking_step) |as| {
- tty_config.setColor(w, .red) catch {};
+ fwm.setColor(w, .red) catch {};
try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
- tty_config.setColor(w, .reset) catch {};
+ fwm.setColor(w, .reset) catch {};
- as.dump(w, tty_config);
+ as.dump(w, fwm);
}
- tty_config.setColor(w, .red) catch {};
+ fwm.setColor(w, .red) catch {};
try w.writeAll(" Hope that helps. Proceeding to panic.\n");
- tty_config.setColor(w, .reset) catch {};
+ fwm.setColor(w, .reset) catch {};
}
pub const InstallDir = union(enum) {
diff --git a/lib/std/Build/Fuzz.zig b/lib/std/Build/Fuzz.zig
index 8837d7d527..c2b7d1e9e9 100644
--- a/lib/std/Build/Fuzz.zig
+++ b/lib/std/Build/Fuzz.zig
@@ -9,14 +9,12 @@ const Allocator = std.mem.Allocator;
const log = std.log;
const Coverage = std.debug.Coverage;
const abi = Build.abi.fuzz;
-const tty = std.Io.tty;
const Fuzz = @This();
const build_runner = @import("root");
gpa: Allocator,
io: Io,
-ttyconf: tty.Config,
mode: Mode,
/// Allocated into `gpa`.
@@ -77,7 +75,6 @@ const CoverageMap = struct {
pub fn init(
gpa: Allocator,
io: Io,
- ttyconf: tty.Config,
all_steps: []const *Build.Step,
root_prog_node: std.Progress.Node,
mode: Mode,
@@ -95,7 +92,7 @@ pub fn init(
if (run.producer == null) continue;
if (run.fuzz_tests.items.len == 0) continue;
try steps.append(gpa, run);
- rebuild_group.async(io, rebuildTestsWorkerRun, .{ run, gpa, ttyconf, rebuild_node });
+ rebuild_group.async(io, rebuildTestsWorkerRun, .{ run, gpa, rebuild_node });
}
if (steps.items.len == 0) fatal("no fuzz tests found", .{});
@@ -115,7 +112,6 @@ pub fn init(
return .{
.gpa = gpa,
.io = io,
- .ttyconf = ttyconf,
.mode = mode,
.run_steps = run_steps,
.group = .init,
@@ -154,14 +150,14 @@ pub fn deinit(fuzz: *Fuzz) void {
fuzz.gpa.free(fuzz.run_steps);
}
-fn rebuildTestsWorkerRun(run: *Step.Run, gpa: Allocator, ttyconf: tty.Config, parent_prog_node: std.Progress.Node) void {
- rebuildTestsWorkerRunFallible(run, gpa, ttyconf, parent_prog_node) catch |err| {
+fn rebuildTestsWorkerRun(run: *Step.Run, gpa: Allocator, parent_prog_node: std.Progress.Node) void {
+ rebuildTestsWorkerRunFallible(run, gpa, parent_prog_node) catch |err| {
const compile = run.producer.?;
log.err("step '{s}': failed to rebuild in fuzz mode: {t}", .{ compile.step.name, err });
};
}
-fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, ttyconf: tty.Config, parent_prog_node: std.Progress.Node) !void {
+fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, parent_prog_node: std.Progress.Node) !void {
const compile = run.producer.?;
const prog_node = parent_prog_node.start(compile.step.name, 0);
defer prog_node.end();
@@ -174,9 +170,9 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, ttyconf: tty.Co
if (show_error_msgs or show_compile_errors or show_stderr) {
var buf: [256]u8 = undefined;
- const w, _ = std.debug.lockStderrWriter(&buf);
+ const stderr = std.debug.lockStderrWriter(&buf);
defer std.debug.unlockStderrWriter();
- build_runner.printErrorMessages(gpa, &compile.step, .{}, w, ttyconf, .verbose, .indent) catch {};
+ build_runner.printErrorMessages(gpa, &compile.step, .{}, &stderr.interface, stderr.mode, .verbose, .indent) catch {};
}
const rebuilt_bin_path = result catch |err| switch (err) {
@@ -200,9 +196,9 @@ fn fuzzWorkerRun(
run.rerunInFuzzMode(fuzz, unit_test_index, prog_node) catch |err| switch (err) {
error.MakeFailed => {
var buf: [256]u8 = undefined;
- const w, _ = std.debug.lockStderrWriter(&buf);
+ const stderr = std.debug.lockStderrWriter(&buf);
defer std.debug.unlockStderrWriter();
- build_runner.printErrorMessages(gpa, &run.step, .{}, w, fuzz.ttyconf, .verbose, .indent) catch {};
+ build_runner.printErrorMessages(gpa, &run.step, .{}, &stderr.interface, stderr.mode, .verbose, .indent) catch {};
return;
},
else => {
diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig
index 9c7fcc757f..0df58b24b7 100644
--- a/lib/std/Build/Step.zig
+++ b/lib/std/Build/Step.zig
@@ -117,7 +117,6 @@ pub const MakeOptions = struct {
// it currently breaks because `std.net.Address` doesn't work there. Work around for now.
.wasm32 => void,
},
- ttyconf: std.Io.tty.Config,
/// If set, this is a timeout to enforce on all individual unit tests, in nanoseconds.
unit_test_timeout_ns: ?u64,
/// 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 {
}
/// For debugging purposes, prints identifying information about this Step.
-pub fn dump(step: *Step, w: *Io.Writer, tty_config: Io.tty.Config) void {
+pub fn dump(step: *Step, w: *Io.Writer, fwm: Io.File.Writer.Mode) void {
if (step.debug_stack_trace.instruction_addresses.len > 0) {
w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};
- std.debug.writeStackTrace(&step.debug_stack_trace, w, tty_config) catch {};
+ std.debug.writeStackTrace(&step.debug_stack_trace, w, fwm) catch {};
} else {
const field = "debug_stack_frames_count";
comptime assert(@hasField(Build, field));
- tty_config.setColor(w, .yellow) catch {};
+ fwm.setColor(w, .yellow) catch {};
w.print("name: '{s}'. no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{step.name}) catch {};
- tty_config.setColor(w, .reset) catch {};
+ fwm.setColor(w, .reset) catch {};
}
}
diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig
index dfa5460981..d703e55b87 100644
--- a/lib/std/Build/Step/Compile.zig
+++ b/lib/std/Build/Step/Compile.zig
@@ -926,15 +926,15 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking
const maybe_path: ?*GeneratedFile = @field(compile, tag_name);
const generated_file = maybe_path orelse {
- const w, const ttyconf = std.debug.lockStderrWriter(&.{});
- std.Build.dumpBadGetPathHelp(&compile.step, w, ttyconf, compile.step.owner, asking_step) catch {};
+ const stderr = std.debug.lockStderrWriter(&.{});
+ std.Build.dumpBadGetPathHelp(&compile.step, &stderr.interface, stderr.mode, compile.step.owner, asking_step) catch {};
std.debug.unlockStderrWriter();
@panic("missing emit option for " ++ tag_name);
};
const path = generated_file.path orelse {
- const w, const ttyconf = std.debug.lockStderrWriter(&.{});
- std.Build.dumpBadGetPathHelp(&compile.step, w, ttyconf, compile.step.owner, asking_step) catch {};
+ const stderr = std.debug.lockStderrWriter(&.{});
+ std.Build.dumpBadGetPathHelp(&compile.step, &stderr.interface, stderr.mode, compile.step.owner, asking_step) catch {};
std.debug.unlockStderrWriter();
@panic(tag_name ++ " is null. Is there a missing step dependency?");
};
@@ -1904,7 +1904,7 @@ fn checkCompileErrors(compile: *Compile) !void {
try actual_eb.renderToWriter(.{
.include_reference_trace = false,
.include_source_line = false,
- }, &aw.writer, .no_color);
+ }, &aw.writer, .streaming);
break :ae try aw.toOwnedSlice();
};
diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig
index 95024061d8..8aafc77820 100644
--- a/lib/std/Build/Step/Run.zig
+++ b/lib/std/Build/Step/Run.zig
@@ -5,7 +5,7 @@ const std = @import("std");
const Io = std.Io;
const Build = std.Build;
const Step = std.Build.Step;
-const fs = std.fs;
+const Dir = std.Io.Dir;
const mem = std.mem;
const process = std.process;
const EnvMap = std.process.EnvMap;
@@ -26,19 +26,7 @@ cwd: ?Build.LazyPath,
env_map: ?*EnvMap,
/// Controls the `NO_COLOR` and `CLICOLOR_FORCE` environment variables.
-color: enum {
- /// `CLICOLOR_FORCE` is set, and `NO_COLOR` is unset.
- enable,
- /// `NO_COLOR` is set, and `CLICOLOR_FORCE` is unset.
- disable,
- /// If the build runner is using color, equivalent to `.enable`. Otherwise, equivalent to `.disable`.
- inherit,
- /// If stderr is captured or checked, equivalent to `.disable`. Otherwise, equivalent to `.inherit`.
- auto,
- /// The build runner does not modify the `CLICOLOR_FORCE` or `NO_COLOR` environment variables.
- /// They are treated like normal variables, so can be controlled through `setEnvironmentVariable`.
- manual,
-} = .auto,
+color: Color = .auto,
/// When `true` prevents `ZIG_PROGRESS` environment variable from being passed
/// to the child process, which otherwise would be used for the child to send
@@ -112,6 +100,20 @@ rebuilt_executable: ?Path,
/// If this Run step was produced by a Compile step, it is tracked here.
producer: ?*Step.Compile,
+pub const Color = enum {
+ /// `CLICOLOR_FORCE` is set, and `NO_COLOR` is unset.
+ enable,
+ /// `NO_COLOR` is set, and `CLICOLOR_FORCE` is unset.
+ disable,
+ /// If the build runner is using color, equivalent to `.enable`. Otherwise, equivalent to `.disable`.
+ inherit,
+ /// If stderr is captured or checked, equivalent to `.disable`. Otherwise, equivalent to `.inherit`.
+ auto,
+ /// The build runner does not modify the `CLICOLOR_FORCE` or `NO_COLOR` environment variables.
+ /// They are treated like normal variables, so can be controlled through `setEnvironmentVariable`.
+ manual,
+};
+
pub const StdIn = union(enum) {
none,
bytes: []const u8,
@@ -565,7 +567,7 @@ pub fn addPathDir(run: *Run, search_path: []const u8) void {
if (prev_path) |pp| {
const new_path = b.fmt("{s}{c}{s}", .{
pp,
- if (use_wine) fs.path.delimiter_windows else fs.path.delimiter,
+ if (use_wine) Dir.path.delimiter_windows else Dir.path.delimiter,
search_path,
});
env_map.put(key, new_path) catch @panic("OOM");
@@ -748,7 +750,7 @@ fn checksContainStderr(checks: []const StdIo.Check) bool {
fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 {
const b = run.step.owner;
const path_str = path.toString(b.graph.arena) catch @panic("OOM");
- if (std.fs.path.isAbsolute(path_str)) {
+ if (Dir.path.isAbsolute(path_str)) {
// Absolute paths don't need changing.
return path_str;
}
@@ -756,19 +758,19 @@ fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 {
const child_lazy_cwd = run.cwd orelse break :rel path_str;
const child_cwd = child_lazy_cwd.getPath3(b, &run.step).toString(b.graph.arena) catch @panic("OOM");
// Convert it from relative to *our* cwd, to relative to the *child's* cwd.
- break :rel std.fs.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM");
+ break :rel Dir.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM");
};
// Not every path can be made relative, e.g. if the path and the child cwd are on different
// disk designators on Windows. In that case, `relative` will return an absolute path which we can
// just return.
- if (std.fs.path.isAbsolute(child_cwd_rel)) {
+ if (Dir.path.isAbsolute(child_cwd_rel)) {
return child_cwd_rel;
}
// We're not done yet. In some cases this path must be prefixed with './':
// * On POSIX, the executable name cannot be a single component like 'foo'
// * Some executables might treat a leading '-' like a flag, which we must avoid
// There's no harm in it, so just *always* apply this prefix.
- return std.fs.path.join(b.graph.arena, &.{ ".", child_cwd_rel }) catch @panic("OOM");
+ return Dir.path.join(b.graph.arena, &.{ ".", child_cwd_rel }) catch @panic("OOM");
}
const IndexedOutput = struct {
@@ -965,11 +967,11 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
&digest,
);
- const output_dir_path = "o" ++ fs.path.sep_str ++ &digest;
+ const output_dir_path = "o" ++ Dir.path.sep_str ++ &digest;
for (output_placeholders.items) |placeholder| {
const output_sub_path = b.pathJoin(&.{ output_dir_path, placeholder.output.basename });
const output_sub_dir_path = switch (placeholder.tag) {
- .output_file => fs.path.dirname(output_sub_path).?,
+ .output_file => Dir.path.dirname(output_sub_path).?,
.output_directory => output_sub_path,
else => unreachable,
};
@@ -995,13 +997,13 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
// We do not know the final output paths yet, use temp paths to run the command.
const rand_int = std.crypto.random.int(u64);
- const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
+ const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);
for (output_placeholders.items) |placeholder| {
const output_components = .{ tmp_dir_path, placeholder.output.basename };
const output_sub_path = b.pathJoin(&output_components);
const output_sub_dir_path = switch (placeholder.tag) {
- .output_file => fs.path.dirname(output_sub_path).?,
+ .output_file => Dir.path.dirname(output_sub_path).?,
.output_directory => output_sub_path,
else => unreachable,
};
@@ -1023,7 +1025,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, options, null);
- const dep_file_dir = Io.Dir.cwd();
+ const dep_file_dir = Dir.cwd();
const dep_file_basename = dep_output_file.generated_file.getPath2(b, step);
if (has_side_effects)
try man.addDepFile(dep_file_dir, dep_file_basename)
@@ -1040,7 +1042,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
// Rename into place
if (any_output) {
- const o_sub_path = "o" ++ fs.path.sep_str ++ &digest;
+ const o_sub_path = "o" ++ Dir.path.sep_str ++ &digest;
b.cache_root.handle.rename(tmp_dir_path, b.cache_root.handle, o_sub_path, io) catch |err| {
if (err == error.PathAlreadyExists) {
@@ -1139,12 +1141,11 @@ pub fn rerunInFuzzMode(
const has_side_effects = false;
const rand_int = std.crypto.random.int(u64);
- const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
+ const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);
try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, .{
.progress_node = prog_node,
.watch = undefined, // not used by `runCommand`
.web_server = null, // only needed for time reports
- .ttyconf = fuzz.ttyconf,
.unit_test_timeout_ns = null, // don't time out fuzz tests for now
.gpa = fuzz.gpa,
}, .{
@@ -1266,10 +1267,7 @@ fn runCommand(
try env_map.put("NO_COLOR", "1");
env_map.remove("CLICOLOR_FORCE");
},
- .inherit => switch (options.ttyconf) {
- .no_color, .windows_api => continue :color .disable,
- .escape_codes => continue :color .enable,
- },
+ .inherit => {},
.auto => {
const capture_stderr = run.captured_stderr != null or switch (run.stdio) {
.check => |checks| checksContainStderr(checks.items),
@@ -1464,7 +1462,7 @@ fn runCommand(
captured.output.generated_file.path = output_path;
const sub_path = b.pathJoin(&output_components);
- const sub_path_dirname = fs.path.dirname(sub_path).?;
+ const sub_path_dirname = Dir.path.dirname(sub_path).?;
b.cache_root.handle.makePath(io, sub_path_dirname) catch |err| {
return step.fail("unable to make path '{f}{s}': {s}", .{
b.cache_root, sub_path_dirname, @errorName(err),
@@ -1650,8 +1648,8 @@ fn spawnChildAndCollect(
if (!run.disable_zig_progress and !inherit) {
child.progress_node = options.progress_node;
}
- if (inherit) std.debug.lockStdErr();
- defer if (inherit) std.debug.unlockStdErr();
+ if (inherit) _ = std.debug.lockStderrWriter(&.{});
+ defer if (inherit) std.debug.unlockStderrWriter();
var timer = try std.time.Timer.start();
const res = try evalGeneric(run, &child);
run.step.result_duration_ns = timer.read();
@@ -2277,7 +2275,7 @@ fn addPathForDynLibs(run: *Run, artifact: *Step.Compile) void {
if (compile.root_module.resolved_target.?.result.os.tag == .windows and
compile.isDynamicLibrary())
{
- addPathDir(run, fs.path.dirname(compile.getEmittedBin().getPath2(b, &run.step)).?);
+ addPathDir(run, Dir.path.dirname(compile.getEmittedBin().getPath2(b, &run.step)).?);
}
}
}
diff --git a/lib/std/Build/WebServer.zig b/lib/std/Build/WebServer.zig
index 5f633c5948..ccb7159192 100644
--- a/lib/std/Build/WebServer.zig
+++ b/lib/std/Build/WebServer.zig
@@ -2,7 +2,6 @@ gpa: Allocator,
graph: *const Build.Graph,
all_steps: []const *Build.Step,
listen_address: net.IpAddress,
-ttyconf: Io.tty.Config,
root_prog_node: std.Progress.Node,
watch: bool,
@@ -52,7 +51,6 @@ pub fn notifyUpdate(ws: *WebServer) void {
pub const Options = struct {
gpa: Allocator,
- ttyconf: Io.tty.Config,
graph: *const std.Build.Graph,
all_steps: []const *Build.Step,
root_prog_node: std.Progress.Node,
@@ -98,7 +96,6 @@ pub fn init(opts: Options) WebServer {
return .{
.gpa = opts.gpa,
- .ttyconf = opts.ttyconf,
.graph = opts.graph,
.all_steps = all_steps,
.listen_address = opts.listen_address,
@@ -233,7 +230,6 @@ pub fn finishBuild(ws: *WebServer, opts: struct {
ws.fuzz = Fuzz.init(
ws.gpa,
ws.graph.io,
- ws.ttyconf,
ws.all_steps,
ws.root_prog_node,
.{ .forever = .{ .ws = ws } },
diff --git a/lib/std/Io/File/Writer.zig b/lib/std/Io/File/Writer.zig
index 8f9f573a4b..03e4ad8a15 100644
--- a/lib/std/Io/File/Writer.zig
+++ b/lib/std/Io/File/Writer.zig
@@ -99,7 +99,7 @@ pub const Mode = union(enum) {
pub const SetColorError = std.os.windows.SetConsoleTextAttributeError || Io.Writer.Error;
- pub fn setColor(mode: Mode, io_w: *Io.Writer, color: Color) Mode.SetColorError!void {
+ pub fn setColor(mode: Mode, io_w: *Io.Writer, color: Color) SetColorError!void {
switch (mode) {
.streaming, .positional, .streaming_simple, .positional_simple, .failure => return,
.terminal_escaped => {
@@ -155,6 +155,34 @@ pub const Mode = union(enum) {
},
}
}
+
+ fn DecorateArgs(comptime Args: type) type {
+ const fields = @typeInfo(Args).@"struct".fields;
+ var new_fields: [fields.len]type = undefined;
+ for (fields, &new_fields) |old, *new| {
+ if (old.type == std.debug.FormatStackTrace) {
+ new.* = std.debug.FormatStackTrace.Decorated;
+ } else {
+ new.* = old.type;
+ }
+ }
+ return @Tuple(&new_fields);
+ }
+
+ pub fn decorateArgs(file_writer_mode: std.Io.File.Writer.Mode, args: anytype) DecorateArgs(@TypeOf(args)) {
+ var new_args: DecorateArgs(@TypeOf(args)) = undefined;
+ inline for (args, &new_args) |old, *new| {
+ if (@TypeOf(old) == std.debug.FormatStackTrace) {
+ new.* = .{
+ .stack_trace = old.stack_trace,
+ .file_writer_mode = file_writer_mode,
+ };
+ } else {
+ new.* = old;
+ }
+ }
+ return new_args;
+ }
};
pub const Error = error{
@@ -426,6 +454,8 @@ pub fn end(w: *Writer) EndError!void {
.streaming,
.streaming_simple,
+ .terminal_escaped,
+ .terminal_winapi,
.failure,
=> {},
}
@@ -453,10 +483,11 @@ pub const Color = enum {
reset,
};
-pub const SetColorError = Mode.SetColorError;
-
-pub fn setColor(w: *Writer, color: Color) SetColorError!void {
- return w.mode.setColor(&w.interface, color);
+pub fn setColor(w: *Writer, color: Color) Io.Writer.Error!void {
+ return w.mode.setColor(&w.interface, color) catch |err| switch (err) {
+ error.WriteFailed => |e| return e,
+ else => |e| w.err = e,
+ };
}
pub fn disableEscape(w: *Writer) Mode {
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 69d8c942c4..67f7d3a9fe 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -306,7 +306,7 @@ pub fn print(comptime fmt: []const u8, args: anytype) void {
var buffer: [64]u8 = undefined;
const stderr = lockStderrWriter(&buffer);
defer unlockStderrWriter();
- stderr.interface.print(fmt, args) catch return;
+ stderr.interface.print(fmt, stderr.mode.decorateArgs(args)) catch return;
}
}
diff --git a/lib/std/log.zig b/lib/std/log.zig
index 029f724f44..b75bada580 100644
--- a/lib/std/log.zig
+++ b/lib/std/log.zig
@@ -120,35 +120,7 @@ pub fn defaultLogFileWriter(
}
fw.interface.writeAll(": ") catch return;
fw.setColor(.reset) catch {};
- fw.interface.print(format ++ "\n", decorateArgs(args, fw.mode)) catch return;
-}
-
-fn DecorateArgs(comptime Args: type) type {
- const fields = @typeInfo(Args).@"struct".fields;
- var new_fields: [fields.len]type = undefined;
- for (fields, &new_fields) |old, *new| {
- if (old.type == std.debug.FormatStackTrace) {
- new.* = std.debug.FormatStackTrace.Decorated;
- } else {
- new.* = old.type;
- }
- }
- return @Tuple(&new_fields);
-}
-
-fn decorateArgs(args: anytype, file_writer_mode: std.Io.File.Writer.Mode) DecorateArgs(@TypeOf(args)) {
- var new_args: DecorateArgs(@TypeOf(args)) = undefined;
- inline for (args, &new_args) |old, *new| {
- if (@TypeOf(old) == std.debug.FormatStackTrace) {
- new.* = .{
- .stack_trace = old.stack_trace,
- .file_writer_mode = file_writer_mode,
- };
- } else {
- new.* = old;
- }
- }
- return new_args;
+ fw.interface.print(format ++ "\n", fw.mode.decorateArgs(args)) catch return;
}
/// Returns a scoped logging namespace that logs all messages using the scope
diff --git a/lib/std/testing.zig b/lib/std/testing.zig
index ab9f1f73c3..092b65d71a 100644
--- a/lib/std/testing.zig
+++ b/lib/std/testing.zig
@@ -354,11 +354,10 @@ test expectApproxEqRel {
}
}
-/// This function is intended to be used only in tests. When the two slices are not
-/// equal, prints diagnostics to stderr to show exactly how they are not equal (with
-/// the differences highlighted in red), then returns a test failure error.
-/// The colorized output is optional and controlled by the return of `Io.tty.Config.detect`.
-/// If your inputs are UTF-8 encoded strings, consider calling `expectEqualStrings` instead.
+/// This function is intended to be used only in tests. When the two slices are
+/// not equal, prints diagnostics to stderr to show exactly how they are not
+/// equal (with the differences highlighted in red), then returns a test
+/// failure error.
pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) !void {
const diff_index: usize = diff_index: {
const shortest = @min(expected.len, actual.len);
@@ -369,20 +368,13 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
break :diff_index if (expected.len == actual.len) return else shortest;
};
if (!backend_can_print) return error.TestExpectedEqual;
- const stderr_w, const ttyconf = std.debug.lockStderrWriter(&.{});
+ const stderr = std.debug.lockStderrWriter(&.{});
defer std.debug.unlockStderrWriter();
- failEqualSlices(T, expected, actual, diff_index, stderr_w, ttyconf) catch {};
+ failEqualSlices(T, expected, actual, diff_index, &stderr.interface, stderr.mode) catch {};
return error.TestExpectedEqual;
}
-fn failEqualSlices(
- comptime T: type,
- expected: []const T,
- actual: []const T,
- diff_index: usize,
- w: *Io.Writer,
- ttyconf: Io.tty.Config,
-) !void {
+fn failEqualSlices(comptime T: type, expected: []const T, actual: []const T, diff_index: usize, w: *Io.Writer, fwm: Io.File.Writer.Mode) !void {
try w.print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index });
// TODO: Should this be configurable by the caller?
@@ -404,12 +396,12 @@ fn failEqualSlices(
var differ = if (T == u8) BytesDiffer{
.expected = expected_window,
.actual = actual_window,
- .ttyconf = ttyconf,
+ .file_writer_mode = fwm,
} else SliceDiffer(T){
.start_index = window_start,
.expected = expected_window,
.actual = actual_window,
- .ttyconf = ttyconf,
+ .file_writer_mode = fwm,
};
// 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 {
start_index: usize,
expected: []const T,
actual: []const T,
- ttyconf: Io.tty.Config,
+ file_writer_mode: Io.File.Writer.Mode,
const Self = @This();
@@ -474,13 +466,13 @@ fn SliceDiffer(comptime T: type) type {
for (self.expected, 0..) |value, i| {
const full_index = self.start_index + i;
const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;
- if (diff) try self.ttyconf.setColor(writer, .red);
+ if (diff) try self.file_writer_mode.setColor(writer, .red);
if (@typeInfo(T) == .pointer) {
try writer.print("[{}]{*}: {any}\n", .{ full_index, value, value });
} else {
try writer.print("[{}]: {any}\n", .{ full_index, value });
}
- if (diff) try self.ttyconf.setColor(writer, .reset);
+ if (diff) try self.file_writer_mode.setColor(writer, .reset);
}
}
};
@@ -489,7 +481,7 @@ fn SliceDiffer(comptime T: type) type {
const BytesDiffer = struct {
expected: []const u8,
actual: []const u8,
- ttyconf: Io.tty.Config,
+ file_writer_mode: Io.File.Writer.Mode,
pub fn write(self: BytesDiffer, writer: *Io.Writer) !void {
var expected_iterator = std.mem.window(u8, self.expected, 16, 16);
@@ -516,7 +508,7 @@ const BytesDiffer = struct {
try self.writeDiff(writer, "{c}", .{byte}, diff);
} else {
// TODO: remove this `if` when https://github.com/ziglang/zig/issues/7600 is fixed
- if (self.ttyconf == .windows_api) {
+ if (self.file_writer_mode == .terminal_winapi) {
try self.writeDiff(writer, ".", .{}, diff);
continue;
}
@@ -538,9 +530,9 @@ const BytesDiffer = struct {
}
fn writeDiff(self: BytesDiffer, writer: *Io.Writer, comptime fmt: []const u8, args: anytype, diff: bool) !void {
- if (diff) try self.ttyconf.setColor(writer, .red);
+ if (diff) try self.file_writer_mode.setColor(writer, .red);
try writer.print(fmt, args);
- if (diff) try self.ttyconf.setColor(writer, .reset);
+ if (diff) try self.file_writer_mode.setColor(writer, .reset);
}
};
@@ -1162,7 +1154,6 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime
} else |err| switch (err) {
error.OutOfMemory => {
if (failing_allocator_inst.allocated_bytes != failing_allocator_inst.freed_bytes) {
- const tty_config: Io.tty.Config = .detect(.stderr());
print(
"\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {f}",
.{
@@ -1174,7 +1165,6 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime
failing_allocator_inst.deallocations,
std.debug.FormatStackTrace{
.stack_trace = failing_allocator_inst.getStackTrace(),
- .tty_config = tty_config,
},
},
);
diff --git a/lib/std/zig.zig b/lib/std/zig.zig
index ac6a0787de..b6203326f2 100644
--- a/lib/std/zig.zig
+++ b/lib/std/zig.zig
@@ -53,18 +53,18 @@ pub const Color = enum {
/// Assume stderr is a terminal.
on,
- pub fn getTtyConf(color: Color, detected: Io.tty.Config) Io.tty.Config {
+ pub fn getTtyConf(color: Color, detected: Io.File.Writer.Mode) Io.File.Writer.Mode {
return switch (color) {
.auto => detected,
- .on => .escape_codes,
- .off => .no_color,
+ .on => .terminal_escaped,
+ .off => .streaming,
};
}
- pub fn detectTtyConf(color: Color, io: Io) Io.tty.Config {
+ pub fn detectTtyConf(color: Color, io: Io) Io.File.Writer.Mode {
return switch (color) {
.auto => .detect(io, .stderr()),
- .on => .escape_codes,
- .off => .no_color,
+ .on => .terminal_escaped,
+ .off => .streaming,
};
}
};
diff --git a/lib/std/zig/ErrorBundle.zig b/lib/std/zig/ErrorBundle.zig
index ef6203cbe8..cc6182c8aa 100644
--- a/lib/std/zig/ErrorBundle.zig
+++ b/lib/std/zig/ErrorBundle.zig
@@ -164,15 +164,20 @@ pub const RenderOptions = struct {
pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions, color: std.zig.Color) void {
var buffer: [256]u8 = undefined;
- const w, const ttyconf = std.debug.lockStderrWriter(&buffer);
+ const stderr = std.debug.lockStderrWriter(&buffer);
defer std.debug.unlockStderrWriter();
- renderToWriter(eb, options, w, color.getTtyConf(ttyconf)) catch return;
+ renderToWriter(eb, options, &stderr.interface, color.getTtyConf(stderr.mode)) catch return;
}
-pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, w: *Writer, ttyconf: Io.tty.Config) (Writer.Error || std.posix.UnexpectedError)!void {
+pub fn renderToWriter(
+ eb: ErrorBundle,
+ options: RenderOptions,
+ w: *Writer,
+ fwm: Io.File.Writer.Mode,
+) Io.File.Writer.Mode.SetColorError!void {
if (eb.extra.len == 0) return;
for (eb.getMessages()) |err_msg| {
- try renderErrorMessageToWriter(eb, options, err_msg, w, ttyconf, "error", .red, 0);
+ try renderErrorMessageToWriter(eb, options, err_msg, w, fwm, "error", .red, 0);
}
if (options.include_log_text) {
@@ -189,18 +194,18 @@ fn renderErrorMessageToWriter(
options: RenderOptions,
err_msg_index: MessageIndex,
w: *Writer,
- ttyconf: Io.tty.Config,
+ fwm: Io.File.Writer.Mode,
kind: []const u8,
- color: Io.tty.Color,
+ color: Io.File.Writer.Color,
indent: usize,
-) (Writer.Error || std.posix.UnexpectedError)!void {
+) Io.File.Writer.Mode.SetColorError!void {
const err_msg = eb.getErrorMessage(err_msg_index);
if (err_msg.src_loc != .none) {
const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
var prefix: Writer.Discarding = .init(&.{});
try w.splatByteAll(' ', indent);
prefix.count += indent;
- try ttyconf.setColor(w, .bold);
+ try fwm.setColor(w, .bold);
try w.print("{s}:{d}:{d}: ", .{
eb.nullTerminatedString(src.data.src_path),
src.data.line + 1,
@@ -211,7 +216,7 @@ fn renderErrorMessageToWriter(
src.data.line + 1,
src.data.column + 1,
});
- try ttyconf.setColor(w, color);
+ try fwm.setColor(w, color);
try w.writeAll(kind);
prefix.count += kind.len;
try w.writeAll(": ");
@@ -219,17 +224,17 @@ fn renderErrorMessageToWriter(
// This is the length of the part before the error message:
// e.g. "file.zig:4:5: error: "
const prefix_len: usize = @intCast(prefix.count);
- try ttyconf.setColor(w, .reset);
- try ttyconf.setColor(w, .bold);
+ try fwm.setColor(w, .reset);
+ try fwm.setColor(w, .bold);
if (err_msg.count == 1) {
try writeMsg(eb, err_msg, w, prefix_len);
try w.writeByte('\n');
} else {
try writeMsg(eb, err_msg, w, prefix_len);
- try ttyconf.setColor(w, .dim);
+ try fwm.setColor(w, .dim);
try w.print(" ({d} times)\n", .{err_msg.count});
}
- try ttyconf.setColor(w, .reset);
+ try fwm.setColor(w, .reset);
if (src.data.source_line != 0 and options.include_source_line) {
const line = eb.nullTerminatedString(src.data.source_line);
for (line) |b| switch (b) {
@@ -242,19 +247,19 @@ fn renderErrorMessageToWriter(
// -1 since span.main includes the caret
const after_caret = src.data.span_end -| src.data.span_main -| 1;
try w.splatByteAll(' ', src.data.column - before_caret);
- try ttyconf.setColor(w, .green);
+ try fwm.setColor(w, .green);
try w.splatByteAll('~', before_caret);
try w.writeByte('^');
try w.splatByteAll('~', after_caret);
try w.writeByte('\n');
- try ttyconf.setColor(w, .reset);
+ try fwm.setColor(w, .reset);
}
for (eb.getNotes(err_msg_index)) |note| {
- try renderErrorMessageToWriter(eb, options, note, w, ttyconf, "note", .cyan, indent);
+ try renderErrorMessageToWriter(eb, options, note, w, fwm, "note", .cyan, indent);
}
if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
- try ttyconf.setColor(w, .reset);
- try ttyconf.setColor(w, .dim);
+ try fwm.setColor(w, .reset);
+ try fwm.setColor(w, .dim);
try w.print("referenced by:\n", .{});
var ref_index = src.end;
for (0..src.data.reference_trace_len) |_| {
@@ -281,25 +286,25 @@ fn renderErrorMessageToWriter(
);
}
}
- try ttyconf.setColor(w, .reset);
+ try fwm.setColor(w, .reset);
}
} else {
- try ttyconf.setColor(w, color);
+ try fwm.setColor(w, color);
try w.splatByteAll(' ', indent);
try w.writeAll(kind);
try w.writeAll(": ");
- try ttyconf.setColor(w, .reset);
+ try fwm.setColor(w, .reset);
const msg = eb.nullTerminatedString(err_msg.msg);
if (err_msg.count == 1) {
try w.print("{s}\n", .{msg});
} else {
try w.print("{s}", .{msg});
- try ttyconf.setColor(w, .dim);
+ try fwm.setColor(w, .dim);
try w.print(" ({d} times)\n", .{err_msg.count});
}
- try ttyconf.setColor(w, .reset);
+ try fwm.setColor(w, .reset);
for (eb.getNotes(err_msg_index)) |note| {
- try renderErrorMessageToWriter(eb, options, note, w, ttyconf, "note", .cyan, indent + 4);
+ try renderErrorMessageToWriter(eb, options, note, w, fwm, "note", .cyan, indent + 4);
}
}
}
@@ -806,12 +811,10 @@ pub const Wip = struct {
};
defer bundle.deinit(std.testing.allocator);
- const ttyconf: Io.tty.Config = .no_color;
-
var bundle_buf: Writer.Allocating = .init(std.testing.allocator);
const bundle_bw = &bundle_buf.interface;
defer bundle_buf.deinit();
- try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_bw);
+ try bundle.renderToWriter(bundle_bw);
var copy = copy: {
var wip: ErrorBundle.Wip = undefined;
@@ -827,7 +830,7 @@ pub const Wip = struct {
var copy_buf: Writer.Allocating = .init(std.testing.allocator);
const copy_bw = &copy_buf.interface;
defer copy_buf.deinit();
- try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_bw);
+ try copy.renderToWriter(copy_bw);
try std.testing.expectEqualStrings(bundle_bw.written(), copy_bw.written());
}