fix glyph-overhang artifacts in partial row repaint

repaintColumns cleared and redrew only [start,end], but a neighbouring cell's
glyph can overhang into that span. The clearRect erased the overhang and the
neighbour was never redrawn, leaving black notches through the line 1-2 cells
before the cursor that survived until a full rerender.

Redraw text for a couple of extra cells on each side, clipped to the cleared
span, so overhang from just-outside cells is restored without touching their
own cell areas. Keeps the per-column repaint efficiency (vs the full-row
repaint debug toggle, which fixed the bars but repainted every dirty cell).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-05-31 21:48:34 +02:00
parent cb95a7188d
commit 57103bb98b

View File

@@ -44,6 +44,11 @@ final class TerminalPaneNode extends Region {
private static final int DIRTY_PARTIAL = 1;
private static final int DIRTY_FULL = 2;
// Glyphs (bold/italic/wide) can overhang into neighbouring cells. When repainting a
// column run we redraw this many extra cells of text on each side, clipped to the
// cleared span, so a neighbour's overhang is restored without disturbing its own cell.
private static final int GLYPH_OVERHANG_CELLS = 2;
// Debug toggle: when set, skip the per-column repaint and always repaint the whole row.
// Used to bisect partial-repaint artifacts (stale black bars near the cursor).
private static final boolean FULL_ROW_REPAINT =
@@ -851,7 +856,18 @@ final class TerminalPaneNode extends Region {
}
drawRowBackgrounds(gc, row, localCellTop, cellWidth, lineHeight, startColumn, endColumn);
drawRowText(gc, row, baseline, cellWidth, startColumn, endColumn);
// Repaint text for a few neighbouring cells too, clipped to the cleared span, so
// any glyph overhang from just-outside cells (erased by the clearRect above) is
// restored. The clip keeps us from touching those neighbours' own cell areas.
gc.save();
gc.beginPath();
gc.rect(x, 0.0, width, canvas.getHeight());
gc.clip();
int textStart = Math.max(0, startColumn - GLYPH_OVERHANG_CELLS);
int textEnd = Math.min(row.cells().size() - 1, endColumn + GLYPH_OVERHANG_CELLS);
drawRowText(gc, row, baseline, cellWidth, textStart, textEnd);
gc.restore();
}
private void paintSidePadding(GraphicsContext gc, RenderRow row, double paneWidth, double bandHeight) {