Conversation
A burst of output leaves a Shell pane with about one screen of browser scrollback, because tmux repaints the burst instead of scrolling it, while tmux itself keeps every line. Shell declined the scroll-to-top re-pull other modes use, and the Load full history button renders only once a replay was truncated, so a Shell tab under 1 MiB could not scroll back at all. The scroll gesture now pulls ?full=1&tail=TERMINAL_TAIL_SIZE, the same bound a tab switch loads; the route's existing tail cut marks longer histories 'tail', so the banner still offers the unbounded pull. A window no longer than the browser's buffer is not rewritten. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Thanks for this, @timkjr. It fixes a real gap: after a burst, a Shell pane kept about one screen of browser scrollback, and the scroll gesture could not reach the history tmux still held. Your change makes scroll-to-top in a Shell pull a bounded window of it ( 1. A bounded window can mark the session "exhausted" and hide Load full history ( The downgrade guard runs before your new bounded check. It was written for an unbounded capture, where "smaller than the browser" means tmux has nothing more to give. A bounded window is smaller than the browser whenever tmux holds more than 1 MiB and the browser already has more rows than the window. Two ways to get there: press Load full history and then scroll to the top of what it loaded, or keep a Shell tab open while it prints more than about 1 MiB. In both cases the guard runs The ask:
2. Every Shell scroll-to-top now pays for a full tmux capture on the server (
3. CLAUDE.md still says the opposite ( The Full-scrollback replay entry still reads "Shell loads the rest only via Load full history, never on ordinary scroll." You updated 4. Nit ( Once 1 to 3 are in, this is ready to merge. The split-pane gap you called out is fine to leave for a follow-up. |
A window cut at the tail size can be smaller than the browser's buffer while tmux still holds more. The downgrade guard reads that as "tmux has nothing more to give", which is true of an unbounded capture only, so a bounded window reaching it marked the session exhausted and removed Load full history from the banner. The bounded skip now runs first, so such a window never reaches the exhausted path, and it no longer writes banner state: relabelling it from the bounded payload would call a terminal holding all of a Load full history pull "the most recent 1 MiB". A skipped window that came back truncated cannot reach anything older than the browser shows, and every ask costs the server a synchronous capture-pane of the whole history (tail is applied after the capture), so it puts the session on the 60 s cooldown. An untruncated one keeps 4 s. _replayWouldShrinkBuffer takes optional pre-estimated rows so a megabyte capture is not scanned twice. CLAUDE.md's Full-scrollback replay entry no longer says Shell never pulls on ordinary scroll. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Thanks for the careful read, and for reproducing it with the harness. All three are in f6aa502, plus the nit. 1. Bounded window marking the session exhausted. You're right: the guard read a tail-cut window smaller than the browser as "tmux has nothing more to give". The bounded skip now runs before the downgrade guard and no longer writes banner state, so a window cut at the tail size can't reach the exhausted path, and a skip right after Load full history leaves the banner as that load set it. The new tests use the real 2. Server capture cost. You're right that "the worst case is what a tab switch carries" holds for the client only, since 3. CLAUDE.md. The Full-scrollback replay entry now describes the bounded scroll pull. I also updated the matching paragraph in 4. Nit. Full suite is green (8309 passed), with typecheck, lint and format. I'll send the split-pane gap as a separate PR. |
Summary
catof a file longer than the screen) leaves the browser with about one screen of scrollback: tmux repaints the burst instead of scrolling it (the mechanism measured in Scrollback in terminal not working #205). tmux still holds every line. Other modes recover it by re-pulling?full=1when the wheel reaches the top; Shell declines that gesture outright (fix(terminal): bound shell history replay #331) to keep a multi-megabyte replay off xterm's main thread, leaving Load full history as the only path. That button renders only once a replay was truncated, so a Shell tab with under 1 MiB of output has no way to scroll back at all.?full=1&tail=${TERMINAL_TAIL_SIZE}: the same 1 MiB a tab switch already loads, but of the scrollback instead of the visible frame. The route already appliestailafter the capture and marks the cuttruncationReason: 'tail', so a longer history still gets the banner and its unbounded pull. No server change, and the fix(terminal): bound shell history replay #331 bound holds: the worst case is the payload a tab switch already carries.terminal-split.js) has no scroll-to-top pull at all, so the same symptom reproduces there.Test plan
npm run typecheck,npm run lint,npm run format:check,npm run check:frontend-syntaxnpm test(full suite, 8303 passed): newtest/shell-scroll-history-pull.test.tsruns the real method extracted fromapp.jswith the real row estimators (its two new-behaviour cases fail against master); the static guard intest/history-truncation-notice.test.tsnow pins the bounded URLcatof a 160-line file in a 38-row Shell pane left 45 browser rows; one wheel-up pulled the window and the buffer held 164, and scrolling kept working through new output. Two Shell tabs switched back and forth twice: each switch drops to the bounded select replay (unchanged), and the first wheel-up restores all 164 rows.🤖 Generated with Claude Code