authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-14 14:43:34-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-14 14:43:34-04:00
logcb257d59f97ea5655bf453d8e7f07bbfb0a88e58
tree0e28c227045b32ebd37a977ce6a8f67730f1edf0
parentf5f28e0d2c49d5c62914edf0bff8f1941eef721f
parentab4e696e1fac3eda1ad0481cfbdc1829cb5c6847
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13148 from r00ster91/progressfollowup

fix(std.Progress): some follow-ups

1 files changed, 31 insertions(+), 20 deletions(-)

lib/std/Progress.zig+31-20
...@@ -48,8 +48,9 @@ timer: ?time.Timer = null,...@@ -48,8 +48,9 @@ timer: ?time.Timer = null,
48/// Used to compare with `refresh_rate_ms`.48/// Used to compare with `refresh_rate_ms`.
49prev_refresh_timestamp: u64 = undefined,49prev_refresh_timestamp: u64 = undefined,
5050
51/// This buffer represents the maximum number of bytes written to the terminal51/// This is the maximum number of bytes that can be written to the terminal each refresh.
52/// with each refresh.52/// Anything larger than this is truncated.
53// we can bump this up if we need to
53output_buffer: [256]u8 = undefined,54output_buffer: [256]u8 = undefined,
54output_buffer_slice: []u8 = undefined,55output_buffer_slice: []u8 = undefined,
5556
...@@ -57,6 +58,8 @@ output_buffer_slice: []u8 = undefined,...@@ -57,6 +58,8 @@ output_buffer_slice: []u8 = undefined,
57///58///
58/// It is recommended to leave this as `null` so that `start` can automatically decide an59/// It is recommended to leave this as `null` so that `start` can automatically decide an
59/// optimal width for the terminal.60/// optimal width for the terminal.
61///
62/// Note that this will be clamped to at least 4 and output will appear malformed if it is < 4.
60max_width: ?usize = null,63max_width: ?usize = null,
6164
62/// How many nanoseconds between writing updates to the terminal.65/// How many nanoseconds between writing updates to the terminal.
...@@ -156,9 +159,13 @@ pub const Node = struct {...@@ -156,9 +159,13 @@ pub const Node = struct {
156159
157/// Create a new progress node.160/// Create a new progress node.
158/// Call `Node.end` when done.161/// Call `Node.end` when done.
159/// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this
160/// API to return Progress rather than accept it as a parameter.
161/// `estimated_total_items` value of 0 means unknown.162/// `estimated_total_items` value of 0 means unknown.
163///
164/// Note that as soon as work is started and progress output is printed,
165/// `std.Progress` expects you to lean back and wait and not resize the terminal.
166/// Resizing the terminal during progress output may result in malformed output.
167// TODO: solve https://github.com/ziglang/zig/issues/2765 and then change this
168// API to return Progress rather than accept it as a parameter.
162pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *Node {169pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *Node {
163 const stderr = std.io.getStdErr();170 const stderr = std.io.getStdErr();
164 self.terminal = null;171 self.terminal = null;
...@@ -172,6 +179,22 @@ pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *N...@@ -172,6 +179,22 @@ pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *N
172 // we are in a "dumb" terminal like in acme or writing to a file179 // we are in a "dumb" terminal like in acme or writing to a file
173 self.terminal = stderr;180 self.terminal = stderr;
174 }181 }
182 self.calculateMaxWidth();
183 self.root = Node{
184 .context = self,
185 .parent = null,
186 .name = name,
187 .unprotected_estimated_total_items = estimated_total_items,
188 .unprotected_completed_items = 0,
189 };
190 self.columns_written = 0;
191 self.prev_refresh_timestamp = 0;
192 self.timer = time.Timer.start() catch null;
193 self.done = false;
194 return &self.root;
195}
196
197fn calculateMaxWidth(self: *Progress) void {
175 if (self.max_width == null) {198 if (self.max_width == null) {
176 if (self.terminal) |terminal| {199 if (self.terminal) |terminal| {
177 // choose an optimal width and account for progress output that could have been printed200 // choose an optimal width and account for progress output that could have been printed
...@@ -188,18 +211,6 @@ pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *N...@@ -188,18 +211,6 @@ pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *N
188 truncation_suffix.len, // make sure we can at least truncate211 truncation_suffix.len, // make sure we can at least truncate
189 self.output_buffer.len - 1,212 self.output_buffer.len - 1,
190 );213 );
191 self.root = Node{
192 .context = self,
193 .parent = null,
194 .name = name,
195 .unprotected_estimated_total_items = estimated_total_items,
196 .unprotected_completed_items = 0,
197 };
198 self.columns_written = 0;
199 self.prev_refresh_timestamp = 0;
200 self.timer = time.Timer.start() catch null;
201 self.done = false;
202 return &self.root;
203}214}
204215
205fn getTerminalWidth(self: Progress, file_handle: os.fd_t) !u16 {216fn getTerminalWidth(self: Progress, file_handle: os.fd_t) !u16 {
...@@ -237,7 +248,7 @@ fn getTerminalCursorColumn(self: Progress, file: std.fs.File) !u16 {...@@ -237,7 +248,7 @@ fn getTerminalCursorColumn(self: Progress, file: std.fs.File) !u16 {
237 };248 };
238249
239 try file.writeAll("\x1b[6n");250 try file.writeAll("\x1b[6n");
240 var buf: ["\x1b[256;256R".len]u8 = undefined;251 var buf: ["\x1b[65536;65536R".len]u8 = undefined;
241 const output = try file.reader().readUntilDelimiter(&buf, 'R');252 const output = try file.reader().readUntilDelimiter(&buf, 'R');
242 var splitter = std.mem.split(u8, output, ";");253 var splitter = std.mem.split(u8, output, ";");
243 _ = splitter.next().?; // skip first half254 _ = splitter.next().?; // skip first half
...@@ -346,7 +357,7 @@ fn refreshWithHeldLock(self: *Progress) void {...@@ -346,7 +357,7 @@ fn refreshWithHeldLock(self: *Progress) void {
346 // we possibly wrote previously don't affect whether we truncate the line in `bufWrite`.357 // we possibly wrote previously don't affect whether we truncate the line in `bufWrite`.
347 const unprintables = end;358 const unprintables = end;
348 end = 0;359 end = 0;
349 self.output_buffer_slice = self.output_buffer[unprintables .. unprintables + self.max_width.?];360 self.output_buffer_slice = self.output_buffer[unprintables..@minimum(self.output_buffer.len, unprintables + self.max_width.?)];
350361
351 if (!self.done) {362 if (!self.done) {
352 var need_ellipsis = false;363 var need_ellipsis = false;
...@@ -432,8 +443,8 @@ test "behavior on buffer overflow" {...@@ -432,8 +443,8 @@ test "behavior on buffer overflow" {
432 if (skip_tests)443 if (skip_tests)
433 return error.SkipZigTest;444 return error.SkipZigTest;
434445
435 // move the cursor446 // uncomment this to move the cursor
436 std.debug.print("{s}", .{"A" ** 300});447 //std.debug.print("{s}", .{"A" ** 300});
437448
438 var progress = Progress{};449 var progress = Progress{};
439450