Repository navigation
Keep long sessions responsive: block-grouped scrollback, longer inbound slices, O(1) hasFocus, buffered VFS appends - #463
Merged
Merged
Conversation
…(1) hasFocus, buffered appends (#457) - Scrollback rows now go into blocks of 100 (src/ui/output/outputRows.ts), and content-visibility sits on the full blocks instead of on every row. Blink tracked every row with its internal intersection observer, which became the largest cost per frame once scrollback passed ~10k lines. The trigger cursor, eviction, the split view, caret mode, scripted scrolling and OSC 8 line deletion all walk rows through the new helpers. Eviction drops whole blocks or one Range per partial block, and never leaves an empty block behind. The open tail block is never skipped, so its height stays exact while the reader is scrolled up. - Inbound slices now run up to 50 ms, or 12 ms when isInputPending reports waiting input, instead of yielding every 12 ms. Each yield could let a render frame through, so a large burst paid for a frame on nearly every slice. - hasFocus() now asks activeElement.closest('.command-input') instead of running a document-wide querySelector, which walked every scrollback row. - ProfileVFS keeps bytes appended to an existing file in memory and writes them in one go: after 500 ms, at 256 KB, before any read, stat, rewrite, rename or removal of the file, on flush/unmount, and when the page is hidden or closed. ZenFS rewrote the whole file on every append. stat() and exists() count the held tail, so io.open(f, "a") never forces a flush. Fixes #457 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014UBzjfaJoyFC6yixLRLJ7z
A hidden tab can be frozen and then discarded without a pagehide, and a frozen page runs no timer, so a tail appended after the tab was hidden was never written out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Um3ZSHRbGj1Rbf55rAQzdM
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.
Fixes #457. In long sessions, output and trigger replies fell seconds behind once scrollback passed about 10k lines, and
hasFocus()andioappends got slower over time.Changes
src/ui/output/outputRows.ts).content-visibility: autonow sits on each finished block instead of on every row, so the browser tracks about a hundredth as many elements per frame. All code that walks the rows goes through the new helpers: cursor ops, eviction, the sticky area, caret mode, user windows and miniconsoles. This is the issue's fallback suggestion, not full virtualisation.MudClientnow handles incoming data in slices of up to 50 ms, or 12 ms when input is waiting (isInputPending), instead of always 12 ms. Large bursts trigger far fewer layout and paint frames, and the order of the stream is unchanged.hasFocus()(§3): it checksdocument.activeElement.closest('.command-input')instead of searching the whole document, so its cost no longer grows with scrollback.ProfileVFSholds appends to existing files in memory, so chat logging (as EMCO does) no longer rewrites the whole file on every line.freezelistener was added in review: a hidden tab can be discarded without apagehideevent.scrollbackBlocks457,hasFocusCost457andvfsAppendTail457, plus updates toinboundSlicesandscrollbackRenderCost443.Overlap
#456's PR also edits
src/ui/output/OutputRenderer.ts, but not the same functions, and the two merge cleanly. Whichever lands second should rerunsplitViewEchoBurst456.Testing
yarn typecheckpasses.yarn test: 2 failures, neither caused by this branch:serverEncoding.test.ts(GBK euro sign) also fails on master.mapperParity295"stays fast on a large grid" is a timing test that fails only under load and passes when run alone.🤖 Generated with Claude Code
https://claude.ai/code/session_01Um3ZSHRbGj1Rbf55rAQzdM
Generated by Claude Code