Skip to content

fix(cli): keep chat parser at full height so zarvis typing isn't laggy - #128

Merged
edwin-zvs merged 1 commit into
mainfrom
fix-zarvis-typing-lag-2
May 22, 2026
Merged

edwin-zvs merged 1 commit into
mainfrom
fix-zarvis-typing-lag-2

Conversation

@edwin-zvs

Copy link
Copy Markdown
Contributor

Problem

Typing into a zarvis prompt was still laggy after #127.

#127 cut the steady-state replay_full cost (per-frame history re-scan), but the actual typing path was never about steady state. As the user types, the zarvis editor pane grows and the chat area shrinks, so render_terminal handed ItemHistory::replay a smaller rows on nearly every keystroke. replay_full treats any rows change as a full O(history) vt100 rebuild.

Measured on a modest 300-cycle (~600-item) session in a debug build: ~26 ms per keystroke just for the chat rebuild — and it scales linearly with session length, so a long session is far worse. #127's steady-state test kept rows constant, which is exactly why it passed while the lag remained.

(The keystroke→EditorState daemon round-trip is ~1.3 ms — confirmed by driving a real ollama-backed zarvis session over the socket — so the bottleneck was entirely the client-side render.)

Fix

Solve it in the render layer rather than the parser. Render the chat at the stable full pane height and display only its bottom chat_area.height rows; the editor pane covers the rest. Editor growth no longer changes the rows passed to replay, so the chat parser is never resized — and never rebuilt — per keystroke. Cost is independent of history size.

A naive set_size-on-shrink was rejected: vt100 truncates from the bottom, dropping the most recent lines (verified — it rendered content ~16 rows too high).

Tool-block hit-rects are translated from full-screen rows into chat-area-relative rows via translate_block_hits (blocks scrolled above the slice are dropped, partially-visible ones clipped, button zones survive only if the header row is visible). Sessions without an editor pane (claude/codex/shell) get row_offset = 0 — byte-for-byte identical behavior.

Tests

  • zarvis_editor_growth_does_not_resize_chat_parser — structural, timing-free: growing the editor buffer must not change the chat parser's dims, and the shrunk chat must still show the most-recent content.
  • translate_block_hits_shifts_clips_and_drops — hit-rect translation (identity / drop / clip / shift).
  • Full suite green: 129 unit + 1 integration; existing tool-block hit-rect and scroll tests unaffected.

🤖 Generated with Claude Code

#127 cut the steady-state replay_full cost, but typing was still slow.
The real culprit: as the user types, the zarvis editor pane grows and
`chat_area.height` shrinks, so render_terminal handed `replay` a smaller
`rows` on (nearly) every keystroke. replay_full treats any rows change
as a full O(history) vt100 rebuild — measured at ~26 ms/keystroke on a
modest 300-cycle session in debug, and it scales linearly with history
size. #127's steady-state test kept rows constant, so it never exercised
this path.

Fix it in the render layer instead of the parser: render the chat at the
stable full pane height and show only its bottom `chat_area.height` rows
(the editor pane covers the rest). Editor growth no longer changes the
rows passed to `replay`, so the parser is never resized — and never
rebuilt — per keystroke. A naive `set_size`-shrink was rejected: vt100
truncates from the bottom, dropping the most recent lines.

Tool-block hit-rects are translated from full-screen rows into
chat-area-relative rows (`translate_block_hits`); blocks scrolled above
the slice are dropped, partially-visible ones clipped. No-editor-pane
sessions (claude/codex/shell) get row_offset 0 — identical behavior.

Tests: structural guard that editor growth doesn't resize the chat
parser (and the shrunk chat still shows the newest content), plus unit
coverage for the hit-rect translation.
@edwin-zvs
edwin-zvs merged commit c63f3f2 into main May 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant