fix(renderer): eagerly erase the previous frame on resize in inline mode#1696
Open
TaraTheStar wants to merge 1 commit into
Open
fix(renderer): eagerly erase the previous frame on resize in inline mode#1696TaraTheStar wants to merge 1 commit into
TaraTheStar wants to merge 1 commit into
Conversation
When tea.Println triggers insertAbove, the cursed renderer resets its tracked cursor position to (0, 0). The next WindowSizeMsg only flips ultraviolet's deferred clear flag; the physical erase happens later inside Render's clearUpdate path, which calls move(newbuf, 0, 0) before EraseScreenBelow. Because move() short-circuits to a zero-byte no-op when source and target are both (0, 0), ED-0 fires at whatever the physical cursor's position happens to be — which can differ from the renderer's tracked anchor after terminal reflow. The previous frame is then stranded above the new one and accumulates in scrollback on subsequent resizes. Eagerly emit \r + CUU(y) + ED-0 at the top of resize() using the renderer's tracked cursor, then invalidate the cursor sentinel so the next moveCursor call emits its first-move \r. Guarded on inline mode.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
After tea.Println, subsequent terminal resizes can leave the previous live region stranded above the new one and accumulate copies of stale frames in scrollback on each resize event.
insertAbove ends with s.scr.SetPosition(0, 0) to declare the live region's new anchor. resize then only sets ultraviolet's deferred clear flag; the physical erase is deferred to the next Render, which takes the clearUpdate path and emits move(newbuf, 0, 0) followed by EraseScreenBelow. With s.cur == (0, 0), move() short-circuits to zero bytes (see ultraviolet/terminal_renderer.go:439), so ED-0 fires at whatever the physical cursor's position actually is — not necessarily the renderer's logical anchor — and the old frame above is never erased.
Fix: in cursedRenderer.resize, before flipping the deferred clear, write \r + CUU(s.cur.Y) + ED-0 directly to the writer (matching insertAbove's direct-write pattern), then set s.cur = (-1, -1) so moveCursor's first-move safety (terminal_renderer.go:362-368) emits a defensive \r on the next cursor move. Alt-screen is guarded out — it uses absolute positioning and its own clear contract.
Reproducer:
Run, press p, then drag-resize the terminal. Pre-fix: old frames stack in scrollback. Post-fix: clean.
A note on reproducibility: I could not reproduce the visual artifact on a Linux PTY with xterm-256color; the wire bytes happen to align there. The mechanism is unambiguous from the source, and the bug has been reported in adjacent contexts (e.g. anthropics/claude-code#49086). Reviewers on iTerm2 / Terminal.app / Windows Terminal
would be best positioned to confirm the visual fix.
CONTRIBUTING.md.