Repository navigation
chat: resizing the pane holds the conversation still - #14
Merged
Merged
Conversation
A width change turned every off-screen spacer back into a message that laid out empty for a frame, moving the conversation by their total height. Off-screen messages now stay spacers at their last height through a width change, and one coming back keeps its height for its first frame. Following the bottom uses this frame's viewport height, so a taller pane no longer overshoots into dvui's bounce back and drops following. A bubble's hug width is kept by width as well as version, so it grows back when the pane widens. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
foxnne
marked this pull request as ready for review
October 16, 2026 15:15
foxnne
added a commit
to fizzyedit/fizzy
that referenced
this pull request
Oct 16, 2026
#454) A chat streaming a reply in (fizzyedit/chat) jittered: the conversation dropped by a line and came back, many times a turn. The cause is in the markdown service's inline render (`drawInline`, which a chat bubble uses). `renderTopLevel` pins a block's emitted height to its height-table entry. That keeps a virtualized preview still while blocks come back from spacers. `drawInline` passes no viewport, so nothing is virtualized and every block is laid out every frame, but the pin still applied. A streamed reply changes its text on every chunk, and the chat's type-in changes it on every frame. Each change re-parses, which clears the table: 1. Frame A: the edited block has no entry and is laid out at its real height. If its text layout is new (a paragraph that just started), the measurement is filed `.deferred`, which keeps the estimate. 2. Frame B: the block is pinnable (`.deferred`), so the pin emits the estimate, which is a line or so short. 3. Frame C: real again. The caller sees H, then H minus a line, then H. With the chat following the bottom, the whole conversation moved down by that line and back. The fix gates both pins on `virtualize`, so a render with no viewport emits what it lays out. The preview pane, which always has a viewport, is unchanged. How it was seen: fizzy from main (Debug, macOS) in a sandbox profile, with this markdown dylib in place of the bundled one. A temporary driver in the chat plugin streamed 8 scripted turns, in 4 to 40 byte chunks every 20 to 140 ms. A per-frame log recorded each message row's rect, min size and the scroll position. | over 20 s of streaming | before | after | |---|---|---| | frames the conversation moved back down | 15 | 0 | | content-height changes that were shrinks | 22 of 78 | 0 of 36 | | frames a message's row was a frame behind its own size | 75 | 35 (only growth, one frame late, as dvui lays out) | Example, one reply's row height across three frames with the same text: 98.1, then 80.0, then 98.1 before; 98.1 throughout after. Test: the headless integration test's inline-render check now streams a reply in 9 bytes a frame and fails if the height ever drops. Without the fix it fails ("shrank from 36.4 to 19.6 at byte 18"); with it, `zig build test-integration` passes 53/53 steps, and so do `zig build test` and `scripts/check-fmt.sh`. `check-web`, `test-sdk-version` and the full app build were left to CI: no SDK or build file changes. No plan step; a fix found while measuring the chat. The chat's own resize fixes are fizzyedit/chat#14 and don't depend on this. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
chat: resizing the pane holds the conversation still
A drag of the pane's edge, sideways or up and down, moved the whole conversation by
hundreds of pixels for a frame, stopped following the bottom on alternate frames, and laid
every message out again on every frame. Three causes, all in View.zig:
turned every off-screen spacer back into a message. dvui had forgotten those rows' sizes,
so each laid out empty for a frame, and everything below moved up by their total height.
The fix from chat: scrolling up holds still while messages above lay out again #3 for scrolling up kept the height only when it was still valid, which a new
width never is. Now a message coming back from a spacer always keeps its last height for
that frame.
laid out at the new width when they come into view, and the anchor holds the reader through
that, as it does for any reflow. A drag lays out only what is on screen.
viewport past the end. The newest line sat a frame behind the edge, and dvui's bounce back
from the overshoot read as the person scrolling up. The height now comes from a box made
before the scroll area.
Also: a bubble's hug width was cached by version alone, clamped to the width at that time.
A message that arrived while the pane was narrow stayed narrow after the pane widened. It is
now kept by version and width.
How it was seen: fizzy from main (Debug, macOS) with a sandbox profile. A temporary driver,
left out of this PR, opened a Sample chat and streamed 8 scripted turns (17 messages) into it
the way an agent does. Tapes dragged the sidebar split from 864 to 569 to 1049 px and back,
and dragged the bottom panel down. A per-frame log recorded each message row's screen rect
and the scroll state.
Still one frame late, and not changed here: a message whose wrap changes during a drag is
laid out at its old height for one frame (dvui places a child at last frame's size). That
shows as a single step, not a bounce.
Streaming jitter, the other half of the report, is the markdown plugin's inline render
emitting a block's estimated height for a frame after each re-parse. That fix is
fizzyedit/fizzy#454. Nothing in this PR is needed for it.
🤖 Generated with Claude Code