diff options
Diffstat (limited to 'lib/std/Progress.zig')
| -rw-r--r-- | lib/std/Progress.zig | 43 |
1 files changed, 39 insertions, 4 deletions
diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index b7ac1fa328..c5c1d17b93 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -58,7 +58,7 @@ pub const Options = struct { /// cannot fit into this buffer which will look bad but not cause any malfunctions. /// /// Must be at least 200 bytes. - draw_buffer: []u8, + draw_buffer: []u8 = &default_draw_buffer, /// How many nanoseconds between writing updates to the terminal. refresh_rate_ns: u64 = 60 * std.time.ns_per_ms, /// How many nanoseconds to keep the output hidden @@ -67,6 +67,7 @@ pub const Options = struct { /// 0 means unknown. estimated_total_items: usize = 0, root_name: []const u8 = "", + disable_printing: bool = false, }; /// Represents one unit of progress. Each node can have children nodes, or @@ -203,6 +204,13 @@ pub const Node = struct { @atomicStore(u32, &storage.estimated_total_count, std.math.lossyCast(u32, count), .monotonic); } + /// Thread-safe. + pub fn increaseEstimatedTotalItems(n: Node, count: usize) void { + const index = n.index.unwrap() orelse return; + const storage = storageByIndex(index); + _ = @atomicRmw(u32, &storage.estimated_total_count, .Add, std.math.lossyCast(u32, count), .monotonic); + } + /// Finish a started `Node`. Thread-safe. pub fn end(n: Node) void { const index = n.index.unwrap() orelse return; @@ -290,6 +298,8 @@ var node_parents_buffer: [default_node_storage_buffer_len]Node.Parent = undefine var node_storage_buffer: [default_node_storage_buffer_len]Node.Storage = undefined; var node_freelist_buffer: [default_node_storage_buffer_len]Node.OptionalIndex = undefined; +var default_draw_buffer: [2000]u8 = undefined; + /// Initializes a global Progress instance. /// /// Asserts there is only one global Progress instance. @@ -318,6 +328,9 @@ pub fn start(options: Options) Node { } } else |env_err| switch (env_err) { error.EnvironmentVariableNotFound => { + if (options.disable_printing) { + return .{ .index = .none }; + } const stderr = std.io.getStdErr(); if (stderr.supportsAnsiEscapeCodes()) { global_progress.terminal = stderr; @@ -330,7 +343,7 @@ pub fn start(options: Options) Node { global_progress.terminal = stderr; } - if (global_progress.terminal == null) { + if (global_progress.terminal == null or !global_progress.supports_ansi_escape_codes) { return .{ .index = .none }; } @@ -379,7 +392,10 @@ fn updateThreadRun() void { return clearTerminal(); const buffer = computeRedraw(); - write(buffer); + if (stderr_mutex.tryLock()) { + defer stderr_mutex.unlock(); + write(buffer); + } } while (true) { @@ -390,10 +406,25 @@ fn updateThreadRun() void { return clearTerminal(); const buffer = computeRedraw(); - write(buffer); + if (stderr_mutex.tryLock()) { + defer stderr_mutex.unlock(); + write(buffer); + } } } +/// Allows the caller to freely write to stderr until `unlockStdErr` is called. +/// +/// During the lock, any `std.Progress` information is cleared from the terminal. +pub fn lockStdErr() void { + stderr_mutex.lock(); + clearTerminal(); +} + +pub fn unlockStdErr() void { + stderr_mutex.unlock(); +} + fn ipcThreadRun(fd: posix.fd_t) anyerror!void { { _ = wait(global_progress.initial_delay_ns); @@ -432,6 +463,8 @@ const tree_line = "\x1B\x28\x30\x78\x1B\x28\x42 "; // │ const tree_langle = "\x1B\x28\x30\x6d\x71\x1B\x28\x42 "; // └─ fn clearTerminal() void { + if (global_progress.newline_count == 0) return; + var i: usize = 0; const buf = global_progress.draw_buffer; @@ -876,3 +909,5 @@ fn handleSigWinch(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) assert(sig == posix.SIG.WINCH); global_progress.redraw_event.set(); } + +var stderr_mutex: std.Thread.Mutex = .{}; |
