fix(tui): clear chat area each frame so stale cells don't bleed into sidebar

ChatWidget's render path was `Paragraph::new(lines).render(content_area, buf)`
with no Block and no Clear — ratatui's Paragraph only writes cells that
contain text, leaving any cell the current frame's paragraph doesn't
touch holding the *previous* frame's contents. With wide tool output
(`gh pr list`, `git log`) emitting ISO-8601 timestamps like
`2026-05-02T07:29:24Z`, then a subsequent shorter-paragraph frame, the
old timestamp tails (`:24Z`, `7:29:24Z`, etc.) persisted on the right
edge of the chat area, visually colliding with the section headers in
the sidebar (`Plan` rendering as `:24Zan`, `Agents` as `:24Zents`).

Fix: render `Clear` over the full content_area before drawing the
Paragraph. Cheap (one buffer-fill per frame) and guarantees stale cells
can never persist into the next frame's render.

Reported in v0.8.5 testing right after install. The other v0.8.5
bordered widgets (composer, sidebar sections, footer) already render
into a Block with a solid background style, so they were never
affected — only the chat area used a bare Paragraph.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
Hunter BownandClaude Opus 4.7 committed 2026-05-02 15:13:23 -05:00
1 parent d66b13b73b
commit 0ae2ceade4
1 file changed
+11
+11
View File
@@ -210,6 +210,17 @@ impl ChatWidget {
impl Renderable for ChatWidget {
fn render(&self, _area: Rect, buf: &mut Buffer) {
// Clear the full chat area every frame. Ratatui's `Paragraph` does
// not fill the area's background — it only writes the cells that
// contain text — so any cell the current frame's paragraph doesn't
// touch retains the *previous* frame's contents. With wide tool
// output (e.g. `gh pr list` lines containing ISO timestamps) and
// a narrower-on-the-next-turn paragraph, the old timestamp tails
// (`:24Z`, `7:29:24Z`, …) appeared to "bleed" into the right edge
// of the chat area, visually colliding with the sidebar (#372 vis
// followup).
Clear.render(self.content_area, buf);
let paragraph = Paragraph::new(self.lines.clone());
paragraph.render(self.content_area, buf);