Repository navigation
fix(session-ui): reuse Pierre file views, window medium files, cache parsed diffs - #57551
Merged
Merged
Conversation
1 task done
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.
Three fixes to how session-ui drives
@pierre/diffs, from the Pierre speed research (Oct 20).1.
TextViewerupdates in placeBefore this change, every reactive change (contents,
overflow, any option) passedreset: true. That rancleanUp(), clearedcontainer.innerHTMLand built a newPierreFilewith a new shadow root. Now the instance is rebuilt only when its virtualizer changes, because a Pierre instance is bound to the virtualizer it was built with. Any other change goes throughsetOptionsandrender({ forceRender }), the same pathDiffVieweralready uses.2. Medium files and diffs are windowed
VIRTUALIZE_BYTES = 500_000(text) and> 500lines (v2 review diffs) are replaced by one sharedvirtualizeLineThreshold = 200. Pierre keeps the viewport plus 1,000 px of overscan on each side mounted, which is about 100 rows. At 200 lines, windowing breaks even on main-thread render time (crossover below), and above that it wins on both DOM size and render time.Two problems showed up once windowing covered these sizes, and both are fixed here:
pool.initialize()before they create the instance. This only matters on a cold start.fixDiffSelectionturned the off-screen range intonulland cleared it. Now the range is kept and Pierre applies it when those rows render.DiffVieweralso scrolls the selection into the window withgetLinePositionandVirtualizer.scrollTo. Text files already work: file links jump by scroll offset, andVirtualizedFilekeeps the selection.3. The parsed-diff cache is used
fileDiffFromContentcomputed acacheKeybut never read or wrote the cache, sonormalize()ranparseDiffFromFileagain on every call. Patch diffs and content diffs now share one LRU (the formerpatchFileDiffCache, nowfileDiffCache). Its keys carry a kind prefix, and it stays capped at 16 entries.Evidence
The research method, with the production
Fileandnormalizebundled by Vite in headless Chromium 153. Studio, one job, before and after built from the same tree (before=origin/betasources), median of 5 page loads. Warm mounts: the worker cache was filled first. DOM = elements in the light DOM plus the shadow root, and token-span counts vary with highlight timing, so mounted[data-line]rows are listed too. Render ms = synchronous mount plus a forced layout.Fix 1: prop change on a mounted text file (4
overflowtoggles + 4 appends per load)overflowtoggleoverflowtoggle (with fix 2)At 150 lines a full rebuild costs about as much as an in-place render. Keeping the instance mainly saves the shadow root, styles and selection state. The time savings show up once the file is large.
Fix 2: mount
onRendered¹ highlighted spans had landed when the after run counted. The windowed 2,500-line diff mounts 948 elements.
Trade-off: a windowed view first renders on the virtualizer's next frame. Below about 1,000 lines on a fast machine, the time until
onRenderedgoes up (about 120 ms minimum) even though main-thread work goes down.Crossover, forced
virtualizetrue/false, Mac mini under load, median of 5 (render ms, DOM elements):* at 100 lines the window already holds the whole diff.
Fix 3:
normalize()called 10× on the same content diff (bun, Studio)Tests
session-diff.test.ts: cache hit (samefileDiffidentity; fails before this change), miss on changed content or name, eviction after 16 newer entries.session-review-file-preview-v2-virtualize.test.ts: threshold boundary, and a 480-line diff virtualizes.component-tests/file-viewer.spec.ts(fixture, Storybook Playwright): theTextViewerkeeps the samediffs-containeracross anoverflowchange and an append. A 480-line file opens at the top with fewer than 200 rows mounted, keeps its selection and comment marks, and follows a line-number scroll jump. A windowed diff scrolls to an off-screen selection and marks it. 24/24 at--workers=2 --repeat-each=8.file,file-tool,session-review-commentsandline-comment-v2specs: 20/20.The session-ui package has no bun harness for rendering Solid components, which is why the instance-identity check is a fixture component test rather than a
bun test.Size
Code +139 / −69 (
file.tsx,session-diff.ts,virtualizer.ts, v2 threshold). Tests +161 / −5.Out of scope: the MutationObserver / rAF cleanup and the highlighter swap.
bun run checkonorigin/betacurrently fails ongui-extension-no-module-state-tsxinpackages/gui-extensions/src/details/popover.tsx(from #57528), which is not touched here.bun typecheckfor session-ui andbun run lint:changed origin/betaare clean.