diff options
| author | historia <historiavg@proton.me> | 2026-08-25 18:27:50 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-08-25 18:27:50 -0400 |
| commit | 64e9940d43fad1bc5908b39673b03e4fdc1e8f2f (patch) | |
| tree | 145271b5d98efb1659a08e4ba883741df55ba299 | |
| parent | 4b49797b4d57c2d2cf63472636622a7a6280a38e (diff) | |
| download | tts-audiobook-generator-64e9940d43fad1bc5908b39673b03e4fdc1e8f2f.tar.gz | |
fix(tui): loading bar overflow during build
| -rw-r--r-- | app/tests/test_taskview.py | 44 | ||||
| -rw-r--r-- | app/ui/taskview.py | 14 |
2 files changed, 54 insertions, 4 deletions
diff --git a/app/tests/test_taskview.py b/app/tests/test_taskview.py index 5d97902..4b03b41 100644 --- a/app/tests/test_taskview.py +++ b/app/tests/test_taskview.py @@ -211,6 +211,20 @@ class RenderTests(_FakeTui, unittest.TestCase): text = self._strings(screen) self.assertIn("Progress", text) + def test_progress_label_never_paints_over_the_border(self): + # Worst-case byte label ("1023.7GB / 1024.0GB") on an 80-col + # terminal must end before the outer box's border column. + view, screen = self.make_view(steps=[_step("one")], width=80) + view.handle_event({"kind": "step_start", "index": 0, "title": "one"}) + view._ingest_line("AUDIOCPP_PROGRESS downloaded=1099240726528 " + "total=1099511627776") + view.render() + labels = [t for _, _, t, _ in screen.strings] + self.assertIn("1023.7GB / 1024.0GB", labels) + for _, x, text, _ in screen.strings: + self.assertLessEqual(x + len(text) - 1, 78, + f"{text!r} painted over the border") + class NoWaitTests(_FakeTui, unittest.TestCase): """wait_on_finish=False: the view returns to the caller on finish.""" @@ -496,6 +510,36 @@ class LanesViewTests(_FakeTui, unittest.TestCase): self.assertIn("Build", text) self.assertIn("Download models", text) + def test_split_render_progress_labels_stay_inside_their_panes(self): + # Regression: the label used to start on the pane's right border + # column, so the download pane drew over it ("52/794" -> "52"). + view, screen = self.make_view(self._two_lanes(), width=92) + view._ingest_lane_line(view._lanes[0], + "[52/794] Building CUDA object ggml") + view._ingest_lane_line(view._lanes[1], "[ 45%] building foo.o") + view.render() + pane_w = (screen.width - 3) // 2 + rects = [(1, pane_w), (1 + pane_w + 1, (screen.width - 3) - pane_w)] + for expected, (px, pw) in zip(("52/794", "45%"), rects): + found = [(x, t) for _, x, t, _ in screen.strings if t == expected] + self.assertEqual(len(found), 1, expected) + x, label = found[0] + # The whole label sits inside its own pane's interior. + self.assertGreaterEqual(x, px + 1) + self.assertLessEqual(x + len(label) - 1, px + pw - 2) + + def test_split_render_bytes_label_fits_in_its_pane(self): + view, screen = self.make_view(self._two_lanes(), width=76) + view._ingest_lane_line(view._lanes[0], + "AUDIOCPP_PROGRESS downloaded=512 total=2048") + view.render() + found = [(x, t) for _, x, t, _ in screen.strings + if t == "512B / 2.0KB"] + self.assertEqual(len(found), 1) + x, label = found[0] + pane_w = (screen.width - 3) // 2 + self.assertLessEqual(x + len(label) - 1, 1 + pane_w - 2) + if __name__ == "__main__": unittest.main() diff --git a/app/ui/taskview.py b/app/ui/taskview.py index ea72a86..c4fd35e 100644 --- a/app/ui/taskview.py +++ b/app/ui/taskview.py @@ -441,8 +441,11 @@ class TaskView: # -- progress bar ---------------------------------------------- if self._progress is not None and self.phase not in _TERMINAL: done, total = self._progress + label = _progress_label(self._progress, self._progress_kind) bar_x = inner_x + 10 - bar_room = max(10, width - bar_x - 16) + # Reserve a space plus the label inside the right border so even + # long byte counts never clip against the screen edge. + bar_room = max(10, width - bar_x - len(label) - 2) filled = 0 if total: filled = round(bar_room * min(done, total) / total) @@ -453,7 +456,7 @@ class TaskView: except Exception: pass _text(scr, theme, y, bar_x + bar_room + 1, - _progress_label(self._progress, self._progress_kind), + _fit(label, max(1, (width - 2) - (bar_x + bar_room))), theme["accent"]) y += 1 @@ -967,8 +970,11 @@ class LanesView: row += 1 if lane.progress is not None and not terminal: done, total = lane.progress + label = _progress_label(lane.progress, lane.progress_kind) bar_x = x + 10 - bar_room = max(6, w - 12) + # Reserve a space plus the label inside the right border so the + # percentage is never clipped by (or painted onto) the pane edge. + bar_room = max(6, w - 12 - len(label)) filled = 0 if total: filled = round(bar_room * min(done, total) / total) @@ -979,7 +985,7 @@ class LanesView: except Exception: pass _text(scr, theme, row, bar_x + bar_room + 1, - _progress_label(lane.progress, lane.progress_kind), + _fit(label, max(1, (x + w - 2) - (bar_x + bar_room))), theme["accent"]) row += 1 |
