fix: clamp cursor-up to viewport height, preventing terminal scroll-to-top - #917
fix: clamp cursor-up to viewport height, preventing terminal scroll-to-top#917MagnetonIO wants to merge 2 commits into
Conversation
…o-top When rendered content exceeds the terminal viewport, eraseLines() and cursorUp() emit ANSI cursor-up sequences that move the cursor above the visible area into scrollback. This causes terminals to snap the viewport to the top of scrollback history — a widespread bug affecting iTerm2, VS Code, tmux, Windows Terminal, kitty, and others. The fix reads stream.rows (available on TTY streams) and clamps all cursor-up operations to the viewport height. Lines beyond the viewport have already scrolled into terminal scrollback and cannot be erased, so the clamp is semantically correct. Non-TTY streams fall back to Infinity (no clamping). Fixes the root cause behind: - anthropics/claude-code#34845 - anthropics/claude-code#33814 - anthropics/claude-code#826 - anthropics/claude-code#36582 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Send it |
|
I think this is still incomplete.
Also, CI is failing. |
|
Need this asap |
Address review feedback: buildCursorSuffix() was still emitting unclamped cursorUp sequences when useCursor positioned the cursor far from the bottom of tall output. Add viewportHeight parameter to buildCursorSuffix and buildCursorOnlySequence, and pass stream.rows from all call sites. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
#982 has been merged and changes the same line in The first parameter changed from I'd expect the resolution to be: const moveUp = Math.min(bottomLine - cursorPosition.y, viewportHeight); |
Summary
eraseLines()andcursorUp()calls inlog-update.tstostream.rows(viewport height)Infinity(no clamping) for non-TTY streamsRoot Cause
When Ink re-renders content that exceeds the terminal viewport,
eraseLines(previousLineCount)andcursorUp(previousLines.length - 1)emit cursor-up escape sequences (\e[NA) where N can far exceed the viewport height. Terminals follow the cursor above the visible area and snap to the top of scrollback history.This affects all terminals — iTerm2, VS Code, tmux, Windows Terminal, kitty, GNOME Terminal, and xterm.js embeddings.
The Fix
Two small helpers read
stream.rowsfrom TTY streams and clamp line counts:Applied to all 6
eraseLines/cursorUpcall sites in bothcreateStandardandcreateIncremental. The clamp is semantically correct: lines above the viewport have already scrolled into scrollback and cannot be erased or navigated to.Tests
eraseLinesclamped when content exceeds viewportcursorUpclamped when content exceeds viewportDownstream Impact
This is the root cause behind a wave of scroll-to-top bugs in tools built on Ink, most notably Claude Code:
Also affects Gemini CLI and any Ink-based TUI that renders content taller than the viewport.
🤖 Generated with Claude Code