aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-25 18:27:50 -0400
committerhistoria <historiavg@proton.me>2026-08-25 18:27:50 -0400
commit64e9940d43fad1bc5908b39673b03e4fdc1e8f2f (patch)
tree145271b5d98efb1659a08e4ba883741df55ba299
parent4b49797b4d57c2d2cf63472636622a7a6280a38e (diff)
downloadtts-audiobook-generator-64e9940d43fad1bc5908b39673b03e4fdc1e8f2f.tar.gz
fix(tui): loading bar overflow during build
-rw-r--r--app/tests/test_taskview.py44
-rw-r--r--app/ui/taskview.py14
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