fix(terminal): anchor input prompt to viewport bottom during alt-screen streaming (#9365)#10752
Draft
lonexreb wants to merge 1 commit into
Draft
fix(terminal): anchor input prompt to viewport bottom during alt-screen streaming (#9365)#10752lonexreb wants to merge 1 commit into
lonexreb wants to merge 1 commit into
Conversation
…en streaming (warpdotdev#9365) When Claude Code (and other CLI agents) run inside Warp's alt-screen mode, the Warp input prompt can render in the middle of the streaming output rather than at the bottom of the viewport. Lines above the prompt get visually clipped and remain truncated in the scrollback. ## Root cause When the input box visibility flips while alt-screen is active, the rendered alt-screen viewport changes size. The output area is wrapped in `TerminalSizeElement` which fires `resize_tx` asynchronously from `after_layout`, so the PTY eventually receives SIGWINCH with the new row count. However, heavy-streaming alt-screen apps such as Claude Code can paint into rows that exist in the alt-screen grid from the previous (larger) layout before processing SIGWINCH. The result: rows beyond the new visible viewport are still in the grid, and when the next paint occurs they appear "above" Warp's input prompt while new content is drawn below it. This race is analogous to the one solved by `resize_alt_screen_redundantly` for the alt-screen entry/exit case (`TerminalModeSwapped`). The same belt-and-suspenders refresh wasn't applied to the four input-visibility-flip paths: - `tag_agent_in` (app/src/terminal/view.rs:7319) - `tag_agent_out` (app/src/terminal/view.rs:7339) - `open_cli_agent_rich_input` (app/src/terminal/view/use_agent_footer/mod.rs:1003) - `close_cli_agent_rich_input_impl` (app/src/terminal/view/use_agent_footer/mod.rs:584) ## Fix Introduce `TerminalView::refresh_size_if_alt_screen_active` and call it from the four state-transition sites above. The helper synchronously runs a `Refresh`-style `SizeUpdate` so the model size, PTY winsize, and alt-screen grid converge before the next paint. The change is additive: when the terminal is in blocklist mode, the helper is a no-op. When alt-screen is inactive, no extra work is done. ## Tests Added `refresh_size_if_alt_screen_active_only_refreshes_in_alt_screen` in `app/src/terminal/view_tests.rs` covering both branches of the helper: - blocklist mode: no-op, pane size unchanged - alt-screen mode: refresh executes without panic, pane size preserved
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.
Closes #9365
Summary
When Claude Code (and other CLI coding agents) stream long output inside Warp's alt-screen mode, Warp's input prompt occasionally renders in the middle of the streaming output rather than at the viewport bottom; lines above the prompt get clipped and remain truncated in the scrollback. This PR adds a synchronous size refresh on the input-visibility transitions that occur during alt-screen, so the PTY winsize and the alt-screen grid converge before the next paint.
Filed as draft because the bug is a streaming/layout race that I could not reproduce in a local Warp build (Metal toolchain not available in this environment — see Manual testing note below). The change is conservative and additive, but live verification against a real Claude Code session is required before promoting out of draft.
Manual testing note
This worktree runs on macOS with Command Line Tools only (no full Xcode toolchain).
cargo check -p warp_terminalfails at compiling Metal shaders (xcrun: error: unable to find utility "metal"), which is the project-known constraint for building the desktop app outside a developer machine with Xcode installed. The change is small, file-local, and uses an existing internal pattern (refresh_size), and the new unit test exercises both branches of the helper. A teammate with the Metal toolchain should run the full Claude Code repro from the issue (heavy-streaming refactor + type-check) to confirm the visual symptom is resolved.Root cause
The user input box (and the rich CLI-agent input panel) can become visible or hidden mid-stream when the agent grabs control, gets tagged in/out, or when the user opens/closes the CLI-agent rich input. In alt-screen mode, the output area is wrapped in
TerminalSizeElementwhich firesresize_txfromafter_layout, so the PTY eventually receivesSIGWINCHwith the new row count.However, a heavy-streaming alt-screen app such as Claude Code can paint into rows that the alt-screen grid still holds from the previous (larger) layout before processing
SIGWINCH. When the next Warp paint occurs, those stale rows appear above Warp's input prompt while new content is drawn below it.This race is the same one the existing
resize_alt_screen_redundantlyhelper solves for theTerminalModeSwapped(alt-screen entry/exit) path. The same belt-and-suspenders refresh wasn't applied to the four input-visibility-flip paths:tag_agent_in—app/src/terminal/view.rs:7319tag_agent_out—app/src/terminal/view.rs:7339open_cli_agent_rich_input—app/src/terminal/view/use_agent_footer/mod.rs:1003close_cli_agent_rich_input_impl—app/src/terminal/view/use_agent_footer/mod.rs:584Change
TerminalView::refresh_size_if_alt_screen_activeruns aRefresh-styleSizeUpdateonly whenmodel.is_alt_screen_active().ctx.notify().TerminalView::refresh_sizevisibility loosened from private topub(in crate::terminal)so the siblingview/use_agent_footer/mod.rsimpl TerminalViewblock can invoke it.Test plan
refresh_size_if_alt_screen_active_only_refreshes_in_alt_screencovers both branches (blocklist mode = no-op, alt-screen mode = refresh runs and pane size is preserved).🤖 Generated with Claude Code