aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2025-12-17 17:00:41 -0800
committerAndrew Kelley <andrew@ziglang.org>2025-12-23 22:15:10 -0800
commit608145c2f07d90c46cdaa8bc2013f31b965a5b8b (patch)
treea8704744b3808887c25ecf7b674eed030b2f6c7d /lib/std
parentaa57793b680b3da05f1d888b4df15807905e57c8 (diff)
downloadzig-608145c2f07d90c46cdaa8bc2013f31b965a5b8b.tar.gz
zig-608145c2f07d90c46cdaa8bc2013f31b965a5b8b.zip
fix more fallout from locking stderr
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/Build.zig73
-rw-r--r--lib/std/Build/Fuzz.zig18
-rw-r--r--lib/std/Build/Step.zig9
-rw-r--r--lib/std/Build/Step/Compile.zig17
-rw-r--r--lib/std/Build/Step/Run.zig22
-rw-r--r--lib/std/Io.zig2
-rw-r--r--lib/std/Io/File/Writer.zig2
-rw-r--r--lib/std/Io/Terminal.zig22
-rw-r--r--lib/std/Io/Threaded.zig6
-rw-r--r--lib/std/debug.zig24
-rw-r--r--lib/std/debug/simple_panic.zig6
-rw-r--r--lib/std/json/dynamic.zig6
-rw-r--r--lib/std/log.zig2
-rw-r--r--lib/std/process.zig2
-rw-r--r--lib/std/testing.zig21
-rw-r--r--lib/std/zig.zig21
-rw-r--r--lib/std/zig/ErrorBundle.zig72
-rw-r--r--lib/std/zig/parser_test.zig16
18 files changed, 160 insertions, 181 deletions
diff --git a/lib/std/Build.zig b/lib/std/Build.zig
index de2985d2b5..cf0b9e5b0d 100644
--- a/lib/std/Build.zig
+++ b/lib/std/Build.zig
@@ -129,6 +129,9 @@ pub const Graph = struct {
dependency_cache: InitializedDepMap = .empty,
allow_so_scripts: ?bool = null,
time_report: bool,
+ /// Similar to the `Io.Terminal.Mode` returned by `Io.lockStderr`, but also
+ /// respects the '--color' flag.
+ stderr_mode: ?Io.Terminal.Mode = null,
};
const AvailableDeps = []const struct { []const u8, []const u8 };
@@ -2255,9 +2258,10 @@ pub const GeneratedFile = struct {
pub fn getPath3(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) Io.Cancelable![]const u8 {
return gen.path orelse {
- const io = gen.step.owner.graph.io;
- const stderr = try io.lockStderrWriter(&.{});
- dumpBadGetPathHelp(gen.step, &stderr.interface, stderr.mode, src_builder, asking_step) catch {};
+ const graph = gen.step.owner.graph;
+ const io = graph.io;
+ const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
+ dumpBadGetPathHelp(gen.step, stderr.terminal(), src_builder, asking_step) catch {};
@panic("misconfigured build script");
};
}
@@ -2468,13 +2472,15 @@ pub const LazyPath = union(enum) {
// TODO make gen.file.path not be absolute and use that as the
// basis for not traversing up too many directories.
+ const graph = src_builder.graph;
+
var file_path: Cache.Path = .{
.root_dir = Cache.Directory.cwd(),
.sub_path = gen.file.path orelse {
- const io = src_builder.graph.io;
- const stderr = try io.lockStderrWriter(&.{});
- dumpBadGetPathHelp(gen.file.step, &stderr.interface, stderr.mode, src_builder, asking_step) catch {};
- io.unlockStderrWriter();
+ const io = graph.io;
+ const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
+ dumpBadGetPathHelp(gen.file.step, stderr.terminal(), src_builder, asking_step) catch {};
+ io.unlockStderr();
@panic("misconfigured build script");
},
};
@@ -2564,43 +2570,36 @@ fn dumpBadDirnameHelp(
comptime msg: []const u8,
args: anytype,
) anyerror!void {
- const stderr = std.debug.lockStderrWriter(&.{});
- defer std.debug.unlockStderrWriter();
-
- const w = &stderr.interface;
- const fwm = stderr.mode;
+ const stderr = std.debug.lockStderr(&.{}).terminal();
+ defer std.debug.unlockStderr();
+ const w = stderr.writer;
try w.print(msg, args);
if (fail_step) |s| {
- fwm.setColor(w, .red) catch {};
+ stderr.setColor(.red) catch {};
try w.writeAll(" The step was created by this stack trace:\n");
- fwm.setColor(w, .reset) catch {};
+ stderr.setColor(.reset) catch {};
- s.dump(w, fwm);
+ s.dump(stderr);
}
if (asking_step) |as| {
- fwm.setColor(w, .red) catch {};
+ stderr.setColor(.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});
- fwm.setColor(w, .reset) catch {};
+ stderr.setColor(.reset) catch {};
- as.dump(w, fwm);
+ as.dump(stderr);
}
- fwm.setColor(w, .red) catch {};
- try w.writeAll(" Hope that helps. Proceeding to panic.\n");
- fwm.setColor(w, .reset) catch {};
+ stderr.setColor(.red) catch {};
+ try w.writeAll(" Proceeding to panic.\n");
+ stderr.setColor(.reset) catch {};
}
/// In this function the stderr mutex has already been locked.
-pub fn dumpBadGetPathHelp(
- s: *Step,
- w: *Io.Writer,
- fwm: File.Writer.Mode,
- src_builder: *Build,
- asking_step: ?*Step,
-) anyerror!void {
+pub fn dumpBadGetPathHelp(s: *Step, t: Io.Terminal, src_builder: *Build, asking_step: ?*Step) anyerror!void {
+ const w = t.writer;
try w.print(
\\getPath() was called on a GeneratedFile that wasn't built yet.
\\ source package path: {s}
@@ -2611,21 +2610,21 @@ pub fn dumpBadGetPathHelp(
s.name,
});
- fwm.setColor(w, .red) catch {};
+ t.setColor(.red) catch {};
try w.writeAll(" The step was created by this stack trace:\n");
- fwm.setColor(w, .reset) catch {};
+ t.setColor(.reset) catch {};
- s.dump(w, fwm);
+ s.dump(t);
if (asking_step) |as| {
- fwm.setColor(w, .red) catch {};
+ t.setColor(.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});
- fwm.setColor(w, .reset) catch {};
+ t.setColor(.reset) catch {};
- as.dump(w, fwm);
+ as.dump(t);
}
- fwm.setColor(w, .red) catch {};
- try w.writeAll(" Hope that helps. Proceeding to panic.\n");
- fwm.setColor(w, .reset) catch {};
+ t.setColor(.red) catch {};
+ try w.writeAll(" Proceeding to panic.\n");
+ t.setColor(.reset) catch {};
}
pub const InstallDir = union(enum) {
diff --git a/lib/std/Build/Fuzz.zig b/lib/std/Build/Fuzz.zig
index 4770e03a0c..d308efdf70 100644
--- a/lib/std/Build/Fuzz.zig
+++ b/lib/std/Build/Fuzz.zig
@@ -158,7 +158,8 @@ fn rebuildTestsWorkerRun(run: *Step.Run, gpa: Allocator, parent_prog_node: std.P
}
fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, parent_prog_node: std.Progress.Node) !void {
- const io = run.step.owner.graph.io;
+ const graph = run.step.owner.graph;
+ const io = graph.io;
const compile = run.producer.?;
const prog_node = parent_prog_node.start(compile.step.name, 0);
defer prog_node.end();
@@ -171,9 +172,9 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, parent_prog_nod
if (show_error_msgs or show_compile_errors or show_stderr) {
var buf: [256]u8 = undefined;
- const stderr = try io.lockStderrWriter(&buf);
- defer io.unlockStderrWriter();
- build_runner.printErrorMessages(gpa, &compile.step, .{}, &stderr.interface, stderr.mode, .verbose, .indent) catch {};
+ const stderr = try io.lockStderr(&buf, graph.stderr_mode);
+ defer io.unlockStderr();
+ build_runner.printErrorMessages(gpa, &compile.step, .{}, stderr.terminal(), .verbose, .indent) catch {};
}
const rebuilt_bin_path = result catch |err| switch (err) {
@@ -186,7 +187,8 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, parent_prog_nod
fn fuzzWorkerRun(fuzz: *Fuzz, run: *Step.Run, unit_test_index: u32) void {
const owner = run.step.owner;
const gpa = owner.allocator;
- const io = owner.graph.io;
+ const graph = owner.graph;
+ const io = graph.io;
const test_name = run.cached_test_metadata.?.testName(unit_test_index);
const prog_node = fuzz.prog_node.start(test_name, 0);
@@ -195,11 +197,11 @@ fn fuzzWorkerRun(fuzz: *Fuzz, run: *Step.Run, unit_test_index: u32) void {
run.rerunInFuzzMode(fuzz, unit_test_index, prog_node) catch |err| switch (err) {
error.MakeFailed => {
var buf: [256]u8 = undefined;
- const stderr = io.lockStderrWriter(&buf) catch |e| switch (e) {
+ const stderr = io.lockStderr(&buf, graph.stderr_mode) catch |e| switch (e) {
error.Canceled => return,
};
- defer io.unlockStderrWriter();
- build_runner.printErrorMessages(gpa, &run.step, .{}, &stderr.interface, stderr.mode, .verbose, .indent) catch {};
+ defer io.unlockStderr();
+ build_runner.printErrorMessages(gpa, &run.step, .{}, stderr.terminal(), .verbose, .indent) catch {};
return;
},
else => {
diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig
index 0df58b24b7..74b41634a7 100644
--- a/lib/std/Build/Step.zig
+++ b/lib/std/Build/Step.zig
@@ -328,16 +328,17 @@ 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, fwm: Io.File.Writer.Mode) void {
+pub fn dump(step: *Step, t: Io.Terminal) void {
+ const w = t.writer;
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, fwm) catch {};
+ std.debug.writeStackTrace(&step.debug_stack_trace, t) catch {};
} else {
const field = "debug_stack_frames_count";
comptime assert(@hasField(Build, field));
- fwm.setColor(w, .yellow) catch {};
+ t.setColor(.yellow) catch {};
w.print("name: '{s}'. no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{step.name}) catch {};
- fwm.setColor(w, .reset) catch {};
+ t.setColor(.reset) catch {};
}
}
diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig
index 888775884d..4752046089 100644
--- a/lib/std/Build/Step/Compile.zig
+++ b/lib/std/Build/Step/Compile.zig
@@ -925,20 +925,21 @@ const CliNamedModules = struct {
fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking_step: ?*Step) ![]const u8 {
const step = &compile.step;
const b = step.owner;
- const io = b.graph.io;
+ const graph = b.graph;
+ const io = graph.io;
const maybe_path: ?*GeneratedFile = @field(compile, tag_name);
const generated_file = maybe_path orelse {
- const stderr = try io.lockStderrWriter(&.{});
- std.Build.dumpBadGetPathHelp(&compile.step, &stderr.interface, stderr.mode, compile.step.owner, asking_step) catch {};
- io.unlockStderrWriter();
+ const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
+ std.Build.dumpBadGetPathHelp(&compile.step, stderr.terminal(), compile.step.owner, asking_step) catch {};
+ io.unlockStderr();
@panic("missing emit option for " ++ tag_name);
};
const path = generated_file.path orelse {
- const stderr = try io.lockStderrWriter(&.{});
- std.Build.dumpBadGetPathHelp(&compile.step, &stderr.interface, stderr.mode, compile.step.owner, asking_step) catch {};
- io.unlockStderrWriter();
+ const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
+ std.Build.dumpBadGetPathHelp(&compile.step, stderr.terminal(), compile.step.owner, asking_step) catch {};
+ io.unlockStderr();
@panic(tag_name ++ " is null. Is there a missing step dependency?");
};
@@ -1907,7 +1908,7 @@ fn checkCompileErrors(compile: *Compile) !void {
try actual_eb.renderToWriter(.{
.include_reference_trace = false,
.include_source_line = false,
- }, &aw.writer, .streaming);
+ }, &aw.writer);
break :ae try aw.toOwnedSlice();
};
diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig
index 67cf201374..157a0292e7 100644
--- a/lib/std/Build/Step/Run.zig
+++ b/lib/std/Build/Step/Run.zig
@@ -1559,7 +1559,8 @@ fn spawnChildAndCollect(
) !?EvalGenericResult {
const b = run.step.owner;
const arena = b.allocator;
- const io = b.graph.io;
+ const graph = b.graph;
+ const io = graph.io;
if (fuzz_context != null) {
assert(!has_side_effects);
@@ -1625,11 +1626,12 @@ fn spawnChildAndCollect(
if (!run.disable_zig_progress and !inherit) {
child.progress_node = options.progress_node;
}
- if (inherit) {
- const stderr = try io.lockStderrWriter(&.{});
- try setColorEnvironmentVariables(run, env_map, stderr.mode);
- }
- defer if (inherit) io.unlockStderrWriter();
+ const terminal_mode: Io.Terminal.Mode = if (inherit) m: {
+ const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
+ break :m stderr.terminal_mode;
+ } else .no_color;
+ defer if (inherit) io.unlockStderr();
+ try setColorEnvironmentVariables(run, env_map, terminal_mode);
var timer = try std.time.Timer.start();
const res = try evalGeneric(run, &child);
run.step.result_duration_ns = timer.read();
@@ -1637,7 +1639,7 @@ fn spawnChildAndCollect(
}
}
-fn setColorEnvironmentVariables(run: *Run, env_map: *EnvMap, fwm: Io.File.Writer.Mode) !void {
+fn setColorEnvironmentVariables(run: *Run, env_map: *EnvMap, terminal_mode: Io.Terminal.Mode) !void {
color: switch (run.color) {
.manual => {},
.enable => {
@@ -1648,9 +1650,9 @@ fn setColorEnvironmentVariables(run: *Run, env_map: *EnvMap, fwm: Io.File.Writer
try env_map.put("NO_COLOR", "1");
env_map.remove("CLICOLOR_FORCE");
},
- .inherit => switch (fwm) {
- .terminal_escaped => continue :color .enable,
- else => continue :color .disable,
+ .inherit => switch (terminal_mode) {
+ .no_color, .windows_api => continue :color .disable,
+ .escape_codes => continue :color .enable,
},
.auto => {
const capture_stderr = run.captured_stderr != null or switch (run.stdio) {
diff --git a/lib/std/Io.zig b/lib/std/Io.zig
index 6fa05b16d2..78049633a0 100644
--- a/lib/std/Io.zig
+++ b/lib/std/Io.zig
@@ -713,7 +713,7 @@ pub const VTable = struct {
processExecutableOpen: *const fn (?*anyopaque, File.OpenFlags) std.process.OpenExecutableError!File,
processExecutablePath: *const fn (?*anyopaque, buffer: []u8) std.process.ExecutablePathError!usize,
lockStderr: *const fn (?*anyopaque, buffer: []u8, ?Terminal.Mode) Cancelable!LockedStderr,
- tryLockStderr: *const fn (?*anyopaque, buffer: []u8) Cancelable!?LockedStderr,
+ tryLockStderr: *const fn (?*anyopaque, buffer: []u8, ?Terminal.Mode) Cancelable!?LockedStderr,
unlockStderr: *const fn (?*anyopaque) void,
now: *const fn (?*anyopaque, Clock) Clock.Error!Timestamp,
diff --git a/lib/std/Io/File/Writer.zig b/lib/std/Io/File/Writer.zig
index 1d0494c674..56a1c09340 100644
--- a/lib/std/Io/File/Writer.zig
+++ b/lib/std/Io/File/Writer.zig
@@ -229,7 +229,7 @@ pub fn seekToUnbuffered(w: *Writer, offset: u64) SeekError!void {
.positional, .positional_simple => {
w.pos = offset;
},
- .streaming, .streaming_simple, .terminal_escaped, .terminal_winapi => {
+ .streaming, .streaming_simple => {
if (w.seek_err) |err| return err;
io.vtable.fileSeekTo(io.userdata, w.file, offset) catch |err| {
w.seek_err = err;
diff --git a/lib/std/Io/Terminal.zig b/lib/std/Io/Terminal.zig
index cd0ec56caa..a39f2175d2 100644
--- a/lib/std/Io/Terminal.zig
+++ b/lib/std/Io/Terminal.zig
@@ -130,25 +130,3 @@ pub fn setColor(t: Terminal, color: Color) Io.Writer.Error!void {
},
}
}
-
-pub fn disableEscape(t: *Terminal) Mode {
- const prev = t.mode;
- t.mode = t.mode.toUnescaped();
- return prev;
-}
-
-pub fn restoreEscape(t: *Terminal, mode: Mode) void {
- t.mode = mode;
-}
-
-pub fn writeAllUnescaped(t: *Terminal, bytes: []const u8) Io.Writer.Error!void {
- const prev_mode = t.disableEscape();
- defer t.restoreEscape(prev_mode);
- return t.interface.writeAll(bytes);
-}
-
-pub fn printUnescaped(t: *Terminal, comptime fmt: []const u8, args: anytype) Io.Writer.Error!void {
- const prev_mode = t.disableEscape();
- defer t.restoreEscape(prev_mode);
- return t.interface.print(fmt, args);
-}
diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig
index 3e7b6950d4..b07a9bb9a8 100644
--- a/lib/std/Io/Threaded.zig
+++ b/lib/std/Io/Threaded.zig
@@ -7178,7 +7178,7 @@ fn fileWriteFileStreaming(
break :o .{ &off, @min(@intFromEnum(limit), size - file_reader.pos, max_count) };
},
.streaming => .{ null, limit.minInt(max_count) },
- .streaming_reading, .positional_reading => break :sf,
+ .streaming_simple, .positional_simple => break :sf,
.failure => return error.ReadFailed,
};
const current_thread = Thread.getCurrent(t);
@@ -7251,7 +7251,7 @@ fn fileWriteFileStreaming(
}
var off_in: i64 = undefined;
const off_in_ptr: ?*i64 = switch (file_reader.mode) {
- .positional_reading, .streaming_reading => return error.Unimplemented,
+ .positional_simple, .streaming_simple => return error.Unimplemented,
.positional => p: {
off_in = @intCast(file_reader.pos);
break :p &off_in;
@@ -7427,7 +7427,7 @@ fn fileWriteFilePositional(
}
var off_in: i64 = undefined;
const off_in_ptr: ?*i64 = switch (file_reader.mode) {
- .positional_reading, .streaming_reading => return error.Unimplemented,
+ .positional_simple, .streaming_simple => return error.Unimplemented,
.positional => p: {
off_in = @intCast(file_reader.pos);
break :p &off_in;
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index fd3a456ff7..e33a2bd575 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -283,12 +283,12 @@ var static_single_threaded_io: Io.Threaded = .init_single_threaded;
///
/// Alternatively, use the higher-level `Io.lockStderr` to integrate with the
/// application's chosen `Io` implementation.
-pub fn lockStderr(buffer: []u8) Io.Terminal {
- return (static_single_threaded_io.ioBasic().lockStderr(buffer, null) catch |err| switch (err) {
+pub fn lockStderr(buffer: []u8) Io.LockedStderr {
+ return static_single_threaded_io.ioBasic().lockStderr(buffer, null) catch |err| switch (err) {
// Impossible to cancel because no calls to cancel using
// `static_single_threaded_io` exist.
error.Canceled => unreachable,
- }).terminal();
+ };
}
pub fn unlockStderr() void {
@@ -311,7 +311,7 @@ pub fn print(comptime fmt: []const u8, args: anytype) void {
var buffer: [64]u8 = undefined;
const stderr = lockStderr(&buffer);
defer unlockStderr();
- stderr.writer.print(fmt, args) catch return;
+ stderr.file_writer.interface.print(fmt, args) catch return;
}
}
@@ -327,7 +327,7 @@ pub inline fn getSelfDebugInfo() !*SelfInfo {
/// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned.
/// Obtains the stderr mutex while dumping.
pub fn dumpHex(bytes: []const u8) void {
- const stderr = lockStderr(&.{});
+ const stderr = lockStderr(&.{}).terminal();
defer unlockStderr();
dumpHexFallible(stderr, bytes) catch {};
}
@@ -551,7 +551,7 @@ pub fn defaultPanic(
_ = panicking.fetchAdd(1, .seq_cst);
trace: {
- const stderr = lockStderr(&.{});
+ const stderr = lockStderr(&.{}).terminal();
defer unlockStderr();
const writer = stderr.writer;
@@ -581,7 +581,7 @@ pub fn defaultPanic(
// A panic happened while trying to print a previous panic message.
// We're still holding the mutex but that's fine as we're going to
// call abort().
- const stderr = lockStderr(&.{});
+ const stderr = lockStderr(&.{}).terminal();
stderr.writer.writeAll("aborting due to recursive panic\n") catch {};
},
else => {}, // Panicked while printing the recursive panic message.
@@ -751,7 +751,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin
}
/// A thin wrapper around `writeCurrentStackTrace` which writes to stderr and ignores write errors.
pub fn dumpCurrentStackTrace(options: StackUnwindOptions) void {
- const stderr = lockStderr(&.{});
+ const stderr = lockStderr(&.{}).terminal();
defer unlockStderr();
writeCurrentStackTrace(.{
.first_address = a: {
@@ -814,7 +814,7 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void
}
/// A thin wrapper around `writeStackTrace` which writes to stderr and ignores write errors.
pub fn dumpStackTrace(st: *const StackTrace) void {
- const stderr = lockStderr(&.{});
+ const stderr = lockStderr(&.{}).terminal();
defer unlockStderr();
writeStackTrace(st, stderr) catch |err| switch (err) {
error.WriteFailed => {},
@@ -1550,7 +1550,7 @@ pub fn defaultHandleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?CpuContex
_ = panicking.fetchAdd(1, .seq_cst);
trace: {
- const stderr = lockStderr(&.{});
+ const stderr = lockStderr(&.{}).terminal();
defer unlockStderr();
if (addr) |a| {
@@ -1571,7 +1571,7 @@ pub fn defaultHandleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?CpuContex
// A segfault happened while trying to print a previous panic message.
// We're still holding the mutex but that's fine as we're going to
// call abort().
- const stderr = lockStderr(&.{});
+ const stderr = lockStderr(&.{}).terminal();
stderr.writer.writeAll("aborting due to recursive panic\n") catch {};
},
else => {}, // Panicked while printing the recursive panic message.
@@ -1678,7 +1678,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
pub fn dump(t: @This()) void {
if (!enabled) return;
- const stderr = lockStderr(&.{});
+ const stderr = lockStderr(&.{}).terminal();
defer unlockStderr();
const end = @min(t.index, size);
for (t.addrs[0..end], 0..) |frames_array, i| {
diff --git a/lib/std/debug/simple_panic.zig b/lib/std/debug/simple_panic.zig
index 2d0e5abf4e..34e8f7b43c 100644
--- a/lib/std/debug/simple_panic.zig
+++ b/lib/std/debug/simple_panic.zig
@@ -14,9 +14,9 @@ const std = @import("../std.zig");
pub fn call(msg: []const u8, ra: ?usize) noreturn {
@branchHint(.cold);
_ = ra;
- const stderr = std.debug.lockStderrWriter(&.{});
- stderr.interface.writeAll(msg) catch {};
- stderr.interface.flush(msg) catch {};
+ const stderr_writer = std.debug.lockStderr(&.{}, null).terminal().writer;
+ stderr_writer.writeAll(msg) catch {};
+ stderr_writer.flush(msg) catch {};
@trap();
}
diff --git a/lib/std/json/dynamic.zig b/lib/std/json/dynamic.zig
index f85916670b..e38ea9cb17 100644
--- a/lib/std/json/dynamic.zig
+++ b/lib/std/json/dynamic.zig
@@ -47,9 +47,9 @@ pub const Value = union(enum) {
}
pub fn dump(v: Value) void {
- const stderr = std.debug.lockStderrWriter(&.{});
- defer std.debug.unlockStderrWriter();
- json.Stringify.value(v, .{}, &stderr.interface) catch return;
+ const stderr = std.debug.lockStderr(&.{}, null);
+ defer std.debug.unlockStderr();
+ json.Stringify.value(v, .{}, &stderr.file_writer.interface) catch return;
}
pub fn jsonStringify(value: @This(), jws: anytype) !void {
diff --git a/lib/std/log.zig b/lib/std/log.zig
index 8579bb04e0..81bfc4ebb6 100644
--- a/lib/std/log.zig
+++ b/lib/std/log.zig
@@ -92,7 +92,7 @@ pub fn defaultLog(
args: anytype,
) void {
var buffer: [64]u8 = undefined;
- const stderr = std.debug.lockStderr(&buffer);
+ const stderr = std.debug.lockStderr(&buffer).terminal();
defer std.debug.unlockStderr();
return defaultLogFileTerminal(level, scope, format, args, stderr) catch {};
}
diff --git a/lib/std/process.zig b/lib/std/process.zig
index 45cd575133..23a3d92e9b 100644
--- a/lib/std/process.zig
+++ b/lib/std/process.zig
@@ -1856,7 +1856,7 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 {
/// and does not return.
pub fn cleanExit(io: Io) void {
if (builtin.mode == .Debug) return;
- _ = io.lockStderrWriter(&.{}) catch {};
+ _ = io.lockStderr(&.{}, .no_color) catch {};
exit(0);
}
diff --git a/lib/std/testing.zig b/lib/std/testing.zig
index be6f316804..98fca2f2d5 100644
--- a/lib/std/testing.zig
+++ b/lib/std/testing.zig
@@ -368,8 +368,8 @@ 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;
- if (io.lockStderrWriter(&.{})) |stderr| {
- defer io.unlockStderrWriter();
+ if (io.lockStderr(&.{}, null)) |stderr| {
+ defer io.unlockStderr();
failEqualSlices(T, expected, actual, diff_index, &stderr.interface, stderr.mode) catch {};
} else |_| {}
return error.TestExpectedEqual;
@@ -381,7 +381,7 @@ fn failEqualSlices(
actual: []const T,
diff_index: usize,
w: *Io.Writer,
- fwm: Io.File.Writer.Mode,
+ terminal_mode: Io.Terminal.Mode,
) !void {
try w.print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index });
@@ -404,12 +404,12 @@ fn failEqualSlices(
var differ = if (T == u8) BytesDiffer{
.expected = expected_window,
.actual = actual_window,
- .file_writer_mode = fwm,
+ .terminal_mode = terminal_mode,
} else SliceDiffer(T){
.start_index = window_start,
.expected = expected_window,
.actual = actual_window,
- .file_writer_mode = fwm,
+ .terminal_mode = terminal_mode,
};
// Print indexes as hex for slices of u8 since it's more likely to be binary data where
@@ -466,21 +466,22 @@ fn SliceDiffer(comptime T: type) type {
start_index: usize,
expected: []const T,
actual: []const T,
- file_writer_mode: Io.File.Writer.Mode,
+ terminal_mode: Io.Terminal.Mode,
const Self = @This();
pub fn write(self: Self, writer: *Io.Writer) !void {
+ const t: Io.Terminal = .{ .writer = writer, .mode = self.terminal_mode };
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.file_writer_mode.setColor(writer, .red);
+ if (diff) try t.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.file_writer_mode.setColor(writer, .reset);
+ if (diff) try t.setColor(writer, .reset);
}
}
};
@@ -489,7 +490,7 @@ fn SliceDiffer(comptime T: type) type {
const BytesDiffer = struct {
expected: []const u8,
actual: []const u8,
- file_writer_mode: Io.File.Writer.Mode,
+ terminal_mode: Io.Terminal.Mode,
pub fn write(self: BytesDiffer, writer: *Io.Writer) !void {
var expected_iterator = std.mem.window(u8, self.expected, 16, 16);
@@ -516,7 +517,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.file_writer_mode == .terminal_winapi) {
+ if (self.terminal_mode == .windows_api) {
try self.writeDiff(writer, ".", .{}, diff);
continue;
}
diff --git a/lib/std/zig.zig b/lib/std/zig.zig
index 6e89c75d91..6212264005 100644
--- a/lib/std/zig.zig
+++ b/lib/std/zig.zig
@@ -46,25 +46,18 @@ pub const SrcHasher = std.crypto.hash.Blake3;
pub const SrcHash = [16]u8;
pub const Color = enum {
- /// Determine whether stderr is a terminal or not automatically.
+ /// Auto-detect whether stream supports terminal colors.
auto,
- /// Assume stderr is not a terminal.
+ /// Force-enable colors.
off,
- /// Assume stderr is a terminal.
+ /// Suppress colors.
on,
- pub fn getTtyConf(color: Color, detected: Io.File.Writer.Mode) Io.File.Writer.Mode {
+ pub fn terminalMode(color: Color) ?Io.Terminal.Mode {
return switch (color) {
- .auto => detected,
- .on => .terminal_escaped,
- .off => .streaming,
- };
- }
- pub fn detectTtyConf(color: Color, io: Io) Io.File.Writer.Mode {
- return switch (color) {
- .auto => .detect(io, .stderr()),
- .on => .terminal_escaped,
- .off => .streaming,
+ .auto => null,
+ .on => .escape_codes,
+ .off => .no_color,
};
}
};
diff --git a/lib/std/zig/ErrorBundle.zig b/lib/std/zig/ErrorBundle.zig
index 556b1167a3..c5275729ae 100644
--- a/lib/std/zig/ErrorBundle.zig
+++ b/lib/std/zig/ErrorBundle.zig
@@ -166,51 +166,53 @@ pub const RenderToStderrError = Io.Cancelable || Io.File.Writer.Error;
pub fn renderToStderr(eb: ErrorBundle, io: Io, options: RenderOptions, color: std.zig.Color) RenderToStderrError!void {
var buffer: [256]u8 = undefined;
- const stderr = try io.lockStderrWriter(&buffer);
- defer io.unlockStderrWriter();
- renderToWriter(eb, options, &stderr.interface, color.getTtyConf(stderr.mode)) catch |err| switch (err) {
- error.WriteFailed => return stderr.err.?,
+ const stderr = try io.lockStderr(&buffer, color.terminalMode());
+ defer io.unlockStderr();
+ renderToTerminal(eb, options, stderr.terminal()) catch |err| switch (err) {
+ error.WriteFailed => return stderr.file_writer.err.?,
else => |e| return e,
};
}
-pub fn renderToWriter(
- eb: ErrorBundle,
- options: RenderOptions,
- w: *Writer,
- fwm: Io.File.Writer.Mode,
-) Io.File.Writer.Mode.SetColorError!void {
+pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, w: *Writer) Writer.Error!void {
+ return renderToTerminal(eb, options, .{ .writer = w, .mode = .no_color }) catch |err| switch (err) {
+ error.WriteFailed => |e| return e,
+ else => unreachable,
+ };
+}
+
+pub fn renderToTerminal(eb: ErrorBundle, options: RenderOptions, t: Io.Terminal) Io.Terminal.SetColorError!void {
if (eb.extra.len == 0) return;
for (eb.getMessages()) |err_msg| {
- try renderErrorMessageToWriter(eb, options, err_msg, w, fwm, "error", .red, 0);
+ try renderErrorMessage(eb, options, err_msg, t, "error", .red, 0);
}
if (options.include_log_text) {
const log_text = eb.getCompileLogOutput();
if (log_text.len != 0) {
- try w.writeAll("\nCompile Log Output:\n");
- try w.writeAll(log_text);
+ try t.writer.writeAll("\nCompile Log Output:\n");
+ try t.writer.writeAll(log_text);
}
}
}
-fn renderErrorMessageToWriter(
+fn renderErrorMessage(
eb: ErrorBundle,
options: RenderOptions,
err_msg_index: MessageIndex,
- w: *Writer,
- fwm: Io.File.Writer.Mode,
+ t: Io.Terminal,
kind: []const u8,
- color: Io.File.Writer.Color,
+ color: Io.Terminal.Color,
indent: usize,
-) Io.File.Writer.Mode.SetColorError!void {
+) Io.Terminal.SetColorError!void {
+ const w = t.writer;
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 fwm.setColor(w, .bold);
+ try t.setColor(.bold);
try w.print("{s}:{d}:{d}: ", .{
eb.nullTerminatedString(src.data.src_path),
src.data.line + 1,
@@ -221,7 +223,7 @@ fn renderErrorMessageToWriter(
src.data.line + 1,
src.data.column + 1,
});
- try fwm.setColor(w, color);
+ try t.setColor(color);
try w.writeAll(kind);
prefix.count += kind.len;
try w.writeAll(": ");
@@ -229,17 +231,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 fwm.setColor(w, .reset);
- try fwm.setColor(w, .bold);
+ try t.setColor(.reset);
+ try t.setColor(.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 fwm.setColor(w, .dim);
+ try t.setColor(.dim);
try w.print(" ({d} times)\n", .{err_msg.count});
}
- try fwm.setColor(w, .reset);
+ try t.setColor(.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) {
@@ -252,19 +254,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 fwm.setColor(w, .green);
+ try t.setColor(.green);
try w.splatByteAll('~', before_caret);
try w.writeByte('^');
try w.splatByteAll('~', after_caret);
try w.writeByte('\n');
- try fwm.setColor(w, .reset);
+ try t.setColor(.reset);
}
for (eb.getNotes(err_msg_index)) |note| {
- try renderErrorMessageToWriter(eb, options, note, w, fwm, "note", .cyan, indent);
+ try renderErrorMessage(eb, options, note, t, "note", .cyan, indent);
}
if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
- try fwm.setColor(w, .reset);
- try fwm.setColor(w, .dim);
+ try t.setColor(.reset);
+ try t.setColor(.dim);
try w.print("referenced by:\n", .{});
var ref_index = src.end;
for (0..src.data.reference_trace_len) |_| {
@@ -291,25 +293,25 @@ fn renderErrorMessageToWriter(
);
}
}
- try fwm.setColor(w, .reset);
+ try t.setColor(.reset);
}
} else {
- try fwm.setColor(w, color);
+ try t.setColor(color);
try w.splatByteAll(' ', indent);
try w.writeAll(kind);
try w.writeAll(": ");
- try fwm.setColor(w, .reset);
+ try t.setColor(.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 fwm.setColor(w, .dim);
+ try t.setColor(.dim);
try w.print(" ({d} times)\n", .{err_msg.count});
}
- try fwm.setColor(w, .reset);
+ try t.setColor(.reset);
for (eb.getNotes(err_msg_index)) |note| {
- try renderErrorMessageToWriter(eb, options, note, w, fwm, "note", .cyan, indent + 4);
+ try renderErrorMessage(eb, options, note, t, "note", .cyan, indent + 4);
}
}
}
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig
index 6c11c3021b..94d877b406 100644
--- a/lib/std/zig/parser_test.zig
+++ b/lib/std/zig/parser_test.zig
@@ -6333,25 +6333,25 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined;
fn testParse(io: Io, source: [:0]const u8, allocator: Allocator, anything_changed: *bool) ![]u8 {
var buffer: [64]u8 = undefined;
- const stderr = try io.lockStderrWriter(&buffer);
- defer io.unlockStderrWriter();
+ const stderr = try io.lockStderr(&buffer, null);
+ defer io.unlockStderr();
var tree = try std.zig.Ast.parse(allocator, source, .zig);
defer tree.deinit(allocator);
for (tree.errors) |parse_error| {
const loc = tree.tokenLocation(0, parse_error.token);
- try stderr.printUnescaped("(memory buffer):{d}:{d}: error: ", .{ loc.line + 1, loc.column + 1 });
- try tree.renderError(parse_error, &stderr.interface);
- try stderr.interface.print("\n{s}\n", .{source[loc.line_start..loc.line_end]});
+ try stderr.writer.print("(memory buffer):{d}:{d}: error: ", .{ loc.line + 1, loc.column + 1 });
+ try tree.renderError(parse_error, stderr.writer);
+ try stderr.writer.print("\n{s}\n", .{source[loc.line_start..loc.line_end]});
{
var i: usize = 0;
while (i < loc.column) : (i += 1) {
- try stderr.writeAllUnescaped(" ");
+ try stderr.writer.writeAll(" ");
}
- try stderr.writeAllUnescaped("^");
+ try stderr.writer.writeAll("^");
}
- try stderr.writeAllUnescaped("\n");
+ try stderr.writer.writeAll("\n");
}
if (tree.errors.len != 0) {
return error.ParseError;