| ... | ... | @@ -35,6 +35,9 @@ initial_delay_ns: u64, |
| 35 | 35 | |
| 36 | 36 | rows: u16, |
| 37 | 37 | cols: u16, |
| 38 | /// Needed because terminal escape codes require one to take scrolling into |
| 39 | /// account. |
| 40 | newline_count: u16, |
| 38 | 41 | |
| 39 | 42 | /// Accessed only by the update thread. |
| 40 | 43 | draw_buffer: []u8, |
| ... | ... | @@ -240,6 +243,7 @@ var global_progress: Progress = .{ |
| 240 | 243 | .initial_delay_ns = undefined, |
| 241 | 244 | .rows = 0, |
| 242 | 245 | .cols = 0, |
| 246 | .newline_count = 0, |
| 243 | 247 | .draw_buffer = undefined, |
| 244 | 248 | .done = false, |
| 245 | 249 | |
| ... | ... | @@ -346,6 +350,7 @@ fn updateThreadRun() void { |
| 346 | 350 | } |
| 347 | 351 | |
| 348 | 352 | const start_sync = "\x1b[?2026h"; |
| 353 | const up_one_line = "\x1bM"; |
| 349 | 354 | const clear = "\x1b[J"; |
| 350 | 355 | const save = "\x1b7"; |
| 351 | 356 | const restore = "\x1b8"; |
| ... | ... | @@ -431,22 +436,32 @@ fn computeRedraw() []u8 { |
| 431 | 436 | } |
| 432 | 437 | |
| 433 | 438 | // The strategy is: keep the cursor at the beginning, and then with every redraw: |
| 434 | | // erase, save, write, restore |
| 439 | // erase to end of screen, write, move cursor to beginning of line, move cursor up N lines |
| 435 | 440 | |
| 436 | 441 | var i: usize = 0; |
| 437 | 442 | const buf = global_progress.draw_buffer; |
| 438 | 443 | |
| 439 | | const prefix = start_sync ++ clear ++ save; |
| 440 | | const suffix = restore ++ finish_sync; |
| 444 | buf[i..][0..start_sync.len].* = start_sync.*; |
| 445 | i += start_sync.len; |
| 441 | 446 | |
| 442 | | buf[0..prefix.len].* = prefix.*; |
| 443 | | i = prefix.len; |
| 447 | buf[0..clear.len].* = clear.*; |
| 448 | i = clear.len; |
| 444 | 449 | |
| 445 | 450 | const root_node_index: Node.Index = @enumFromInt(0); |
| 446 | 451 | i = computeNode(buf, i, serialized_node_storage, serialized_node_parents, children, root_node_index); |
| 447 | 452 | |
| 448 | | buf[i..][0..suffix.len].* = suffix.*; |
| 449 | | i += suffix.len; |
| 453 | if (buf[i - 1] == '\n') { |
| 454 | buf[i - 1] = '\r'; |
| 455 | const prev_nl_n = global_progress.newline_count - 1; |
| 456 | global_progress.newline_count = 0; |
| 457 | for (0..prev_nl_n) |_| { |
| 458 | buf[i..][0..up_one_line.len].* = up_one_line.*; |
| 459 | i += up_one_line.len; |
| 460 | } |
| 461 | } |
| 462 | |
| 463 | buf[i..][0..finish_sync.len].* = finish_sync.*; |
| 464 | i += finish_sync.len; |
| 450 | 465 | |
| 451 | 466 | return buf[0..i]; |
| 452 | 467 | } |
| ... | ... | @@ -514,6 +529,7 @@ fn computeNode( |
| 514 | 529 | i = @min(global_progress.cols + start_i, i); |
| 515 | 530 | buf[i] = '\n'; |
| 516 | 531 | i += 1; |
| 532 | global_progress.newline_count += 1; |
| 517 | 533 | |
| 518 | 534 | if (children[@intFromEnum(node_index)].child.unwrap()) |child| { |
| 519 | 535 | i = computeNode(buf, i, serialized_node_storage, serialized_node_parents, children, child); |