| ... | ... | @@ -32,9 +32,11 @@ initial_delay_ns: u64, |
| 32 | 32 | |
| 33 | 33 | rows: u16, |
| 34 | 34 | cols: u16, |
| 35 | | /// Needed because terminal escape codes require one to take scrolling into |
| 36 | | /// account. |
| 37 | | newline_count: u16, |
| 35 | /// Tracks the number of newlines that have been actually written to the terminal. |
| 36 | written_newline_count: u16, |
| 37 | /// Tracks the number of newlines that will be written to the terminal if the |
| 38 | /// draw buffer is sent. |
| 39 | accumulated_newline_count: u16, |
| 38 | 40 | |
| 39 | 41 | /// Accessed only by the update thread. |
| 40 | 42 | draw_buffer: []u8, |
| ... | ... | @@ -284,7 +286,8 @@ var global_progress: Progress = .{ |
| 284 | 286 | .initial_delay_ns = undefined, |
| 285 | 287 | .rows = 0, |
| 286 | 288 | .cols = 0, |
| 287 | | .newline_count = 0, |
| 289 | .written_newline_count = 0, |
| 290 | .accumulated_newline_count = 0, |
| 288 | 291 | .draw_buffer = undefined, |
| 289 | 292 | .done = false, |
| 290 | 293 | |
| ... | ... | @@ -423,7 +426,7 @@ fn updateThreadRun() void { |
| 423 | 426 | const buffer = computeRedraw(&serialized_buffer); |
| 424 | 427 | if (stderr_mutex.tryLock()) { |
| 425 | 428 | defer stderr_mutex.unlock(); |
| 426 | | write(buffer); |
| 429 | write(buffer) catch return; |
| 427 | 430 | } |
| 428 | 431 | } |
| 429 | 432 | |
| ... | ... | @@ -440,7 +443,7 @@ fn updateThreadRun() void { |
| 440 | 443 | const buffer = computeRedraw(&serialized_buffer); |
| 441 | 444 | if (stderr_mutex.tryLock()) { |
| 442 | 445 | defer stderr_mutex.unlock(); |
| 443 | | write(buffer); |
| 446 | write(buffer) catch return; |
| 444 | 447 | } |
| 445 | 448 | } |
| 446 | 449 | } |
| ... | ... | @@ -499,7 +502,7 @@ const tree_line = "\x1B\x28\x30\x78\x1B\x28\x42 "; // │ |
| 499 | 502 | const tree_langle = "\x1B\x28\x30\x6d\x71\x1B\x28\x42 "; // └─ |
| 500 | 503 | |
| 501 | 504 | fn clearTerminal() void { |
| 502 | | if (global_progress.newline_count == 0) return; |
| 505 | if (global_progress.written_newline_count == 0) return; |
| 503 | 506 | |
| 504 | 507 | var i: usize = 0; |
| 505 | 508 | const buf = global_progress.draw_buffer; |
| ... | ... | @@ -512,15 +515,17 @@ fn clearTerminal() void { |
| 512 | 515 | buf[i..][0..finish_sync.len].* = finish_sync.*; |
| 513 | 516 | i += finish_sync.len; |
| 514 | 517 | |
| 515 | | write(buf[0..i]); |
| 518 | global_progress.accumulated_newline_count = 0; |
| 519 | write(buf[0..i]) catch { |
| 520 | global_progress.terminal = null; |
| 521 | }; |
| 516 | 522 | } |
| 517 | 523 | |
| 518 | 524 | fn computeClear(buf: []u8, start_i: usize) usize { |
| 519 | 525 | var i = start_i; |
| 520 | 526 | |
| 521 | | const prev_nl_n = global_progress.newline_count; |
| 527 | const prev_nl_n = global_progress.written_newline_count; |
| 522 | 528 | if (prev_nl_n > 0) { |
| 523 | | global_progress.newline_count = 0; |
| 524 | 529 | buf[i] = '\r'; |
| 525 | 530 | i += 1; |
| 526 | 531 | for (0..prev_nl_n) |_| { |
| ... | ... | @@ -854,6 +859,7 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) []u8 { |
| 854 | 859 | |
| 855 | 860 | i = computeClear(buf, i); |
| 856 | 861 | |
| 862 | global_progress.accumulated_newline_count = 0; |
| 857 | 863 | const root_node_index: Node.Index = @enumFromInt(0); |
| 858 | 864 | i = computeNode(buf, i, serialized, children, root_node_index); |
| 859 | 865 | |
| ... | ... | @@ -937,7 +943,7 @@ fn computeNode( |
| 937 | 943 | i = @min(global_progress.cols + start_i, i); |
| 938 | 944 | buf[i] = '\n'; |
| 939 | 945 | i += 1; |
| 940 | | global_progress.newline_count += 1; |
| 946 | global_progress.accumulated_newline_count += 1; |
| 941 | 947 | } |
| 942 | 948 | |
| 943 | 949 | if (global_progress.withinRowLimit()) { |
| ... | ... | @@ -959,14 +965,13 @@ fn withinRowLimit(p: *Progress) bool { |
| 959 | 965 | // The +2 here is so that the PS1 is not scrolled off the top of the terminal. |
| 960 | 966 | // one because we keep the cursor on the next line |
| 961 | 967 | // one more to account for the PS1 |
| 962 | | return p.newline_count + 2 < p.rows; |
| 968 | return p.accumulated_newline_count + 2 < p.rows; |
| 963 | 969 | } |
| 964 | 970 | |
| 965 | | fn write(buf: []const u8) void { |
| 971 | fn write(buf: []const u8) anyerror!void { |
| 966 | 972 | 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; |
| 970 | 975 | } |
| 971 | 976 | |
| 972 | 977 | fn writeIpc(fd: posix.fd_t, serialized: Serialized) error{BrokenPipe}!void { |