From 5ecf06e0ed4a634048530ac99db68f718b5e014e Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Sun, 19 Jul 2026 21:13:08 -0500 Subject: [PATCH] perf(desktop): virtualize the review-pane diff (no more full-Shiki freeze) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Selecting a large changed file in the review pane froze it: FileDiffPanel with no fullText + no showLineNumbers rendered SyntaxDiff over EVERY line — a full Shiki highlight + thousands of mounted DOM nodes — because windowing was tied to showLineNumbers/fullText and the review call had neither. Decouple windowing from the gutter: - `windowed = showLineNumbers || virtualized`; windowed paths always render the fixed-row chunked body (TokenizedDiffBody chunked / PreviewDiffRows), never SyntaxDiff, so only visible rows mount. - New `virtualized` prop → windowed scroller WITHOUT the line-number gutter. - Review passes `virtualized` + the preview's fill className. Preview (showLineNumbers + fullText) and tool-card (compact) render byte-for-byte as before — the gutter body just reads the same chunked window it already used, and the no-fullText+highlight case (previously SyntaxDiff) now windows too. tsc + eslint clean. Visual paths preserved by construction; needs an in-app eyeball on a large review diff. --- .../src/app/right-sidebar/review/index.tsx | 2 +- .../src/components/chat/diff-lines.tsx | 57 ++++++++++++++----- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/apps/desktop/src/app/right-sidebar/review/index.tsx b/apps/desktop/src/app/right-sidebar/review/index.tsx index 2e50a1f874f5..9fc203c81674 100644 --- a/apps/desktop/src/app/right-sidebar/review/index.tsx +++ b/apps/desktop/src/app/right-sidebar/review/index.tsx @@ -202,7 +202,7 @@ export function ReviewPane() { ) : null ) : diff ? ( - + ) : (
{c.noDiff}
)} diff --git a/apps/desktop/src/components/chat/diff-lines.tsx b/apps/desktop/src/components/chat/diff-lines.tsx index eef495c7c54c..179e327a39d0 100644 --- a/apps/desktop/src/components/chat/diff-lines.tsx +++ b/apps/desktop/src/components/chat/diff-lines.tsx @@ -559,9 +559,20 @@ interface FileDiffPanelProps { /** Render an old/new line-number gutter (the full preview diff). The compact * tool-card + inline review diff leave this off. */ showLineNumbers?: boolean + /** Window the rows (fixed-row virtualization) WITHOUT a gutter — for a large + * diff in a scrolling pane (the review panel), so only visible rows mount + * instead of highlighting every line. `showLineNumbers` implies windowing. */ + virtualized?: boolean } -export function FileDiffPanel({ className, diff, fullText, path, showLineNumbers = false }: FileDiffPanelProps) { +export function FileDiffPanel({ + className, + diff, + fullText, + path, + showLineNumbers = false, + virtualized = false +}: FileDiffPanelProps) { const lines = React.useMemo( () => (fullText != null ? parseFullFileDiff(diff, fullText) : parseDiff(diff)), [diff, fullText] @@ -580,32 +591,50 @@ export function FileDiffPanel({ className, diff, fullText, path, showLineNumbers const language = shikiLanguageForFilename(path) const canHighlight = Boolean(language) && !exceedsHighlightBudget(fullText ?? diff) + const windowed = showLineNumbers || virtualized - // Full-file preview: we own the rows (tokens rendered inside) so blank lines - // can't collapse. Compact tool/review diffs let Shiki own the rows. - const body = !canHighlight ? ( - showLineNumbers ? ( - - ) : ( - - ) - ) : fullText != null ? ( + // Windowed: we own fixed-height rows and render only the visible chunks, so a + // large diff never mounts (or Shiki-highlights) every line. Compact tool cards + // are small/clamped, so they let Shiki own the rows (SyntaxDiff). + const windowedBody = canHighlight ? ( + ) : ( + + ) + + const compactBody = !canHighlight ? ( + + ) : fullText != null ? ( + ) : ( ) - if (!showLineNumbers) { + if (!windowed) { return (
- {body} + {compactBody} +
+ ) + } + + // Windowed but no gutter (the review panel): a fixed-row scroller so only the + // visible rows render, killing the full-Shiki-of-every-line freeze on large + // diffs. The gutter variant (below) adds line numbers on top of the same window. + if (!showLineNumbers) { + return ( +
+
+
{windowedBody}
+
+
) } @@ -638,7 +667,7 @@ export function FileDiffPanel({ className, diff, fullText, path, showLineNumbers ))} {afterRows > 0 &&
}
-
{body}
+
{windowedBody}