Cache TUI transcript block heights to fix long-transcript scroll lag#13592
Conversation
|
@warp-dev-github-integration[bot] I'm starting a first review of this pull request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR adds width-aware caching for TUI rich-content block heights to avoid remeasuring stable transcript agent blocks on every viewport pass.
Concerns
⚠️ Stable-width completed agent blocks can still change height from local TUI interactions such as expanding/collapsing thinking, shell-command, or file-edit sections, but those click handlers notify without marking the rich content dirty. The new cache gate can therefore preserve stale heights after interaction.⚠️ This is a user-facing TUI behavior/performance change, but the PR description does not include acceptable TUI visual evidence such as a terminal transcript,render_to_lines/TuiBuffer::to_linessnapshot diff, or./script/run-tuicapture demonstrating the transcript behavior end to end. Please attach one before merge.
Verdict
Found: 0 critical, 2 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
|
Addressed both review concerns in b68fde9. 1. Stale height on collapse/expand (important): toggles of finished thinking/shell/file-edit sections now invalidate the block's cached height (shared 2. TUI visual evidence (headless Validation: Note on the earlier red Windows check: that failure ( |
|
/oz-review |
b68fde9 to
2325f75
Compare
This stack of pull requests is managed by Graphite. Learn more about stacking. |

Description
Fixes scrolling/viewport lag in the warp-tui transcript view with long transcripts containing many AI blocks (collapsible thinking items, agent shell commands, etc.).
Root cause (viewporting inefficiency, not scroll handling). On every frame (each scroll tick and idle repaint),
TuiBlockListViewportSource::visible_itemsre-measured every agent block in a viewport±20-row overhang band by fully rebuilding and laying out each block's element tree viaTuiAIBlock::desired_height— with no height cache keyed by width. The block list already storedlast_laid_out_height, but the viewport threw that cache away for the measurement decision. As transcripts grow (bigger/more thinking + shell blocks), the fixed per-frame band cost balloons and scrolling feels laggy. This mirrors the GUI blocklist prior art, except the GUI re-lays-out retained elements (cheap when unchanged) while the TUI rebuilt immediate-mode trees from scratch every frame.Fix. Gate the overhang re-measure on staleness. A non-dirty band block is re-measured only when its cached height cannot be trusted:
At a stable width with nothing streaming, the cached
last_laid_out_heightis reused, so height write-back short-circuits and the extramodel.lock()acquisitions are skipped. Off-band blocks keep their cached height until they scroll into the band, matching the existing GUI overhang behavior.To persist the width across frames (the viewport source is reconstructed every render),
RichContentItemgains ameasured_width, recorded by the row-based (TUI) height-update path; the GUI pixel path leaves itNoneand is unaffected.Linked Issue
ready-to-specorready-to-implement.Investigation + approval thread: https://warpdev.slack.com/archives/C0BCE7AELJ2/p1783722795932879?thread_ts=1783722795.932879&cid=C0BCE7AELJ2
Testing
Validation (all with
CARGO_BUILD_JOBS=1):cargo nextest run -p warp_tui— 132 passed (incl. new tests below)cargo nextest run -p warpui_core— 310 passedcargo nextest run -p warpblock-list / rich-content tests — 85 passed./script/format --check— cleancargo clippy --workspace --exclude warp_completer --all-targets --tests -- -D warnings— cleanNew / updated tests (in
crates/warp_tui/src/tui_block_list_viewport_source_tests.rs):tui_transcript_scroll_reuses_cached_heights_at_stable_width(new regression guard): a non-dirty, non-streaming block seeded with a wrong height at a stable width is not re-measured (no resize emitted), but is re-measured on a width change and when marked dirty. This fails before the fix (the old code re-measured every frame and corrected the seeded height) and passes after.tui_agent_streaming_block_remeasured_at_stable_width(new): a streaming block is still re-measured at a stable width, so live height growth (e.g. an expanded running shell command) stays reflected.tui_agent_overhang_remeasures_visible_non_dirty_heightupdated to the new contract: re-measures on first measure (no recorded width), and a subsequent same-width frame does not re-measure.Performance evidence: a headless benchmark over 30 agent blocks showed steady-state frames drop from ~1790µs/frame to the ~56µs/frame cached-reuse baseline (~32× less redundant work per frame in a debug build).
UI verification note: the authenticated warp-tui transcript view cannot be driven non-interactively in the cloud runner (interactive device-auth only), so no
computer_usescreenshot is included. The deterministic regression test plus the headless benchmark are the gates; a human/CI check on a real device is: open a long transcript with many thinking/shell blocks and confirm smooth wheel/drag scrolling with correct heights (including while a command streams with its output expanded)../script/runAgent Mode
Conversation: https://staging.warp.dev/conversation/e38f6ef0-8090-4128-b2d9-078b2aa2e539
Run: https://oz.staging.warp.dev/runs/019f4e2e-143c-74ca-92b9-568681f403af
This PR was generated with Oz.