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