authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-05-27 10:29:39-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-05-27 20:56:48-07:00
logdc3a192ae841706bb965218c68b0085bbec2b35e
tree24aa6cca1ca96e9ceeedc528942c55ab372fcc5a
parent6145819c0ba00924b37bab78200aeab6306c1672

std.Progress: count newlines more accurately

Split newline_count into written_newline_count and accumulated_newline_count. This handle the case when the tryLock() fails to obtain the lock, because in such case there would not be any newlines written to the terminal but the system would incorrectly think there were. Now, written_newline_count is only adjusted when the write() call succeeds. Furthermore, write() call failure is handled by exiting the update thread.

1 files changed, 21 insertions(+), 16 deletions(-)

lib/std/Progress.zig+21-16
......@@ -32,9 +32,11 @@ initial_delay_ns: u64,
3232
3333rows: u16,
3434cols: u16,
35/// Needed because terminal escape codes require one to take scrolling into
36/// account.
37newline_count: u16,
35/// Tracks the number of newlines that have been actually written to the terminal.
36written_newline_count: u16,
37/// Tracks the number of newlines that will be written to the terminal if the
38/// draw buffer is sent.
39accumulated_newline_count: u16,
3840
3941/// Accessed only by the update thread.
4042draw_buffer: []u8,
......@@ -284,7 +286,8 @@ var global_progress: Progress = .{
284286 .initial_delay_ns = undefined,
285287 .rows = 0,
286288 .cols = 0,
287 .newline_count = 0,
289 .written_newline_count = 0,
290 .accumulated_newline_count = 0,
288291 .draw_buffer = undefined,
289292 .done = false,
290293
......@@ -423,7 +426,7 @@ fn updateThreadRun() void {
423426 const buffer = computeRedraw(&serialized_buffer);
424427 if (stderr_mutex.tryLock()) {
425428 defer stderr_mutex.unlock();
426 write(buffer);
429 write(buffer) catch return;
427430 }
428431 }
429432
......@@ -440,7 +443,7 @@ fn updateThreadRun() void {
440443 const buffer = computeRedraw(&serialized_buffer);
441444 if (stderr_mutex.tryLock()) {
442445 defer stderr_mutex.unlock();
443 write(buffer);
446 write(buffer) catch return;
444447 }
445448 }
446449}
......@@ -499,7 +502,7 @@ const tree_line = "\x1B\x28\x30\x78\x1B\x28\x42 "; // │
499502const tree_langle = "\x1B\x28\x30\x6d\x71\x1B\x28\x42 "; // └─
500503
501504fn clearTerminal() void {
502 if (global_progress.newline_count == 0) return;
505 if (global_progress.written_newline_count == 0) return;
503506
504507 var i: usize = 0;
505508 const buf = global_progress.draw_buffer;
......@@ -512,15 +515,17 @@ fn clearTerminal() void {
512515 buf[i..][0..finish_sync.len].* = finish_sync.*;
513516 i += finish_sync.len;
514517
515 write(buf[0..i]);
518 global_progress.accumulated_newline_count = 0;
519 write(buf[0..i]) catch {
520 global_progress.terminal = null;
521 };
516522}
517523
518524fn computeClear(buf: []u8, start_i: usize) usize {
519525 var i = start_i;
520526
521 const prev_nl_n = global_progress.newline_count;
527 const prev_nl_n = global_progress.written_newline_count;
522528 if (prev_nl_n > 0) {
523 global_progress.newline_count = 0;
524529 buf[i] = '\r';
525530 i += 1;
526531 for (0..prev_nl_n) |_| {
......@@ -854,6 +859,7 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) []u8 {
854859
855860 i = computeClear(buf, i);
856861
862 global_progress.accumulated_newline_count = 0;
857863 const root_node_index: Node.Index = @enumFromInt(0);
858864 i = computeNode(buf, i, serialized, children, root_node_index);
859865
......@@ -937,7 +943,7 @@ fn computeNode(
937943 i = @min(global_progress.cols + start_i, i);
938944 buf[i] = '\n';
939945 i += 1;
940 global_progress.newline_count += 1;
946 global_progress.accumulated_newline_count += 1;
941947 }
942948
943949 if (global_progress.withinRowLimit()) {
......@@ -959,14 +965,13 @@ fn withinRowLimit(p: *Progress) bool {
959965 // The +2 here is so that the PS1 is not scrolled off the top of the terminal.
960966 // one because we keep the cursor on the next line
961967 // one more to account for the PS1
962 return p.newline_count + 2 < p.rows;
968 return p.accumulated_newline_count + 2 < p.rows;
963969}
964970
965fn write(buf: []const u8) void {
971fn write(buf: []const u8) anyerror!void {
966972 const tty = global_progress.terminal orelse return;
967 tty.writeAll(buf) catch {
968 global_progress.terminal = null;
969 };
973 try tty.writeAll(buf);
974 global_progress.written_newline_count = global_progress.accumulated_newline_count;
970975}
971976
972977fn writeIpc(fd: posix.fd_t, serialized: Serialized) error{BrokenPipe}!void {