Files
oh-my-pi/packages
Leo Kimandcan1357 7ccf5c4b0a fix(tui): erase-after-content to avoid BSU-split blank flash on every keystroke
Four TUI render paths emitted `\x1b[2K` (erase entire line) BEFORE the new line content, all wrapped in BSU (`\x1b[?2026h…l`):

  1. Differential render loop (per changed line, fires on every keystroke).

  2. Trailing extra-line clear when content shrinks (`\r\n\x1b[2K` per stale row).

  3. Shrink-tail-only branch (`firstChanged >= newLines.length`, `\r\x1b[2K` per tail row).

  4. `viewportRefresh()` (per line when a row above the viewport changes mid-stream).

BSU mode 2026 is only atomic if the multiplexer and the terminal both honor it strictly. In tmux + ghostty (the user's setup, confirmed by screen recording), the BSU envelope splits across PTY reads (~4 KB chunks). When `\x1b[2K` arrives before the content payload, the user sees the line blank for ~16 ms. The eye registers this as a flash, multiplied across every keystroke and every streamed chunk that touches an above-viewport line.

All four paths now use the inverse pattern: write content FIRST, then `\x1b[m\x1b[K` (SGR reset + erase cursor-to-EOL) AFTER. Old content stays on screen until the new content overwrites it character-by-character, so a BSU split produces at worst a frame of stale trailing characters — invisible during keystroke- or streaming-paced repaint, far less noticeable than a black bar. The trailing `\x1b[m` ensures the erase uses default attributes (no leftover background-color strip if the new content ended mid-SGR before `#applyLineResets` terminated it).

Transitively fixes a vertical-collision bug surfaced by the same user recording: while streaming markdown with code fences, the streamed text and the Bash tool-call cards would visually overlap. Root cause: `viewportRefresh()`'s BSU-split window left `#hardwareCursorRow` desynced, and the next differential frame would use the stale row offset in `computeLineDiff`, writing changed lines over rows already occupied by another component. With no BSU-split blank frame, the cursor-row tracking stays consistent across frames.

Tests: 3 new cases in `packages/tui/test/render-no-2k-flash.test.ts` (differential render, trailing-clear, viewportRefresh — each asserts no `\x1b[2K` appears in the captured `write()` bytes after a state mutation, and that `\x1b[m\x1b[K` does appear).

Verified pre-existing failures (overlay-scroll 4 + render-regressions 4 = 8) are unchanged by this commit — confirmed by stashing the patches, re-running the same files, observing identical failure counts and titles.
2026-05-25 12:08:36 +02:00
..
2026-05-22 17:48:11 +09:00
2026-05-22 17:48:11 +09:00
2026-05-22 17:48:11 +09:00