Repository navigation
Conversation
Three causes, all reproduced in the running app with a streaming agent: - The follow-the-bottom decision was sampled when a pty chunk was queued and applied after xterm parsed it, so chunks already in flight when the user scrolled up snapped them back to the bottom. Stick-to-bottom is now an entry flag changed only by the user's own scrolling (wheel, keys, scrollbar) and the views' explicit snap-to-bottom. - xterm's wheel path only moves the DOM scrollTop and reads it back on the next scroll event; a repaint in between restores the old scrollTop and drops the event, so quick wheel flicks during a stream were lost. In the normal buffer the wheel now goes through term.scrollLines. Mouse-tracking TUIs and the alternate screen keep xterm's default handling. - A full redraw (CSI 2 J, CSI 3 J, home, reprint) while scrolled up left the viewport clamped to line 0, the top of the transcript. The reader is now put back where they were once the redraw lands. Also sets overflow-anchor: none on the xterm viewport so browser scroll anchoring cannot move it.
Contributor
🚫 This PR is missing its before/after evidenceEvery pull request here has to show its work. Screenshots or a short screen recording, before the change and after it.
How to fix it: edit the description, keep the A bug fix with no visible surface still needs it: show the failing behaviour, then the same steps passing. A terminal recording is fine. Genuinely nothing to show — a CI tweak, a typo, a dependency bump? A maintainer can apply the |
This branch has not been deployed
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.
Fixes #778.
What this fixes
While an agent streams output into its terminal pane, scrolling up to read an earlier response fails in three ways: the viewport is yanked back to the bottom, wheel scrolls are silently dropped, and a full-screen redraw snaps the viewport to the very top (line 0). You cannot hold a scroll position while output keeps arriving. See #778 for the full repro and root-cause analysis.
This affects agents streaming into the normal screen buffer (Codex, OpenCode, pi, custom CLIs, Claude with the classic
tui). Alt-screen / mouse-capture agents (Claudetui: fullscreen) scroll themselves and are left untouched.Changes
terminalPool.ts- introduce anentry.followOutputflag that only user scrolling (wheel / keys / scrollbar) and an explicit snap-to-bottom can change. Stop samplingfollowfrom queued-chunk timing, which was the source of the yank-back.terminalPool.ts/PtyTerminalView.tsx- add aCSI Jhandler that records the reader's distance-from-bottom on3J(clear-scrollback), and a write callback that restores it as the redraw refills: the same distance while the buffer rebuilds, then the exact prior line once the buffer is back to its old length. This removes the snap-to-top.terminalAutomation.ts- route the wheel throughterm.scrollLinesviaattachCustomWheelEventHandlerin the normal buffer, so a repaint between events can no longer drop a wheel flick. Mouse-tracking TUIs and the alt screen keep xterm's default handling.global.css-overflow-anchor: noneon.xterm-viewport.Verification
Reproduced all three behaviours in the running dev app (driven over a debugging port, agent streaming in the normal buffer) before the change. After:
fromBottom0).scrollTopstays constant through continuous output and through repeated full redraws.npm run typecheckclean.terminal-automationtests 9/9 pass (2 new cases added intest/terminal-automation.test.cjs).Notes
tui: fullscreenxterm scrolls itself and already holds position; the new wheel handler deliberately steps aside in that mode, so the fix is scoped to normal-buffer agents.