From 384e2539f10f97080b6c2890fef29848656ed2aa Mon Sep 17 00:00:00 2001 From: Christian Rey Villablanca <43104891+chryzxc@users.noreply.github.com> Date: Tue, 28 Jul 2026 23:28:46 +0800 Subject: [PATCH 1/3] fix: show complete diff previews --- ...preview-block-grouping-regression.test.mjs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/regression/diff-preview-block-grouping-regression.test.mjs b/tests/regression/diff-preview-block-grouping-regression.test.mjs index 0654035..c0a73f1 100644 --- a/tests/regression/diff-preview-block-grouping-regression.test.mjs +++ b/tests/regression/diff-preview-block-grouping-regression.test.mjs @@ -30,6 +30,37 @@ const messageHandlerSource = readSource( "messageHandler.ts", ); +const diffPreviewStepSource = readSource( + [joinFromRoot("webview", "shared", "src", "chat", "components", "activity-steps", "DiffPreviewStep.tsx")], + "DiffPreviewStep.tsx", +); + +const activityDiffExcerptSource = readSource( + [joinFromRoot("webview", "shared", "src", "chat", "components", "ActivityDiffExcerpt.tsx")], + "ActivityDiffExcerpt.tsx", +); + +test("diff preview keeps the complete patch instead of applying a fixed line cap", () => { + assert.match( + diffPreviewStepSource, + /const excerptLines = diffLines\.filter\(\(line, index\) => index !== firstHunkIndex\)/, + "the parser should retain context and all later hunks", + ); + assert.doesNotMatch( + diffPreviewStepSource, + /slice\(0,\s*40\)/, + "the parser must not truncate patches at 40 lines", + ); +}); + +test("diff excerpt resets line numbering for every hunk header", () => { + assert.match( + activityDiffExcerptSource, + /if \(line\.startsWith\("@@"\)\)[\s\S]*?parseHunkHeader\(line\)[\s\S]*?oldN = oldStart[\s\S]*?newN = newStart/s, + "each hunk header should reset old and new line counters", + ); +}); + // ── parseCentralizedSessionDiffEvent ───────────────────────────────── test("parseCentralizedSessionDiffEvent handles both session.diff and message.updated event types", () => { From 9f267c00858d8859744c7bdf9509af24018bfcef Mon Sep 17 00:00:00 2001 From: Christian Rey Villablanca <43104891+chryzxc@users.noreply.github.com> Date: Tue, 28 Jul 2026 23:28:58 +0800 Subject: [PATCH 2/3] fix: show complete diff previews --- .../chat/components/ActivityDiffExcerpt.tsx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/webview/shared/src/chat/components/ActivityDiffExcerpt.tsx b/webview/shared/src/chat/components/ActivityDiffExcerpt.tsx index 9d77143..20336c4 100644 --- a/webview/shared/src/chat/components/ActivityDiffExcerpt.tsx +++ b/webview/shared/src/chat/components/ActivityDiffExcerpt.tsx @@ -23,11 +23,25 @@ function computeLineNumbers( if (parsedHeader.length > 0) { result.push({ old: null, new: null, line: parsedHeader, isHeader: true }); } - const { oldStart, newStart } = + let { oldStart, newStart } = parsedHeader.length > 0 ? parseHunkHeader(parsedHeader) : { oldStart: 1, newStart: 1 }; let oldN = oldStart; let newN = newStart; - for (const line of lines) { + for (const [index, line] of lines.entries()) { + if (line.startsWith("@@")) { + // A complete patch can contain multiple hunks. Reset numbering at each + // subsequent header instead of treating it as a source-code line. + ({ oldStart, newStart } = parseHunkHeader(line)); + oldN = oldStart; + newN = newStart; + result.push({ old: null, new: null, line, isHeader: true }); + continue; + } + // Older callers may include the first header in `lines` as well as in + // `header`; avoid rendering that header twice. + if (index === 0 && parsedHeader.length > 0 && line === parsedHeader) { + continue; + } if (line.startsWith("+") && !line.startsWith("+++")) { result.push({ old: null, new: newN++, line, isHeader: false }); } else if (line.startsWith("-") && !line.startsWith("---")) { From 95a5de98a8a9bf5c30c01b71987ea9613b13629c Mon Sep 17 00:00:00 2001 From: Christian Rey Villablanca <43104891+chryzxc@users.noreply.github.com> Date: Tue, 28 Jul 2026 23:29:01 +0800 Subject: [PATCH 3/3] fix: show complete diff previews --- .../components/activity-steps/DiffPreviewStep.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/webview/shared/src/chat/components/activity-steps/DiffPreviewStep.tsx b/webview/shared/src/chat/components/activity-steps/DiffPreviewStep.tsx index baa99ce..c4d29af 100644 --- a/webview/shared/src/chat/components/activity-steps/DiffPreviewStep.tsx +++ b/webview/shared/src/chat/components/activity-steps/DiffPreviewStep.tsx @@ -148,8 +148,6 @@ function parsePatchTextToExcerpt(patchText?: string): DiffExcerpt | undefined { return undefined; } - const header = lines.find((line) => line.startsWith("@@")) || undefined; - const diffLines = lines.filter( (line) => !line.startsWith("*** Begin Patch") && @@ -163,13 +161,19 @@ function parsePatchTextToExcerpt(patchText?: string): DiffExcerpt | undefined { !line.startsWith("+++ "), ); - const previewLines = diffLines.slice(0, 40); + const firstHunkIndex = diffLines.findIndex((line) => line.startsWith("@@")); + const header = firstHunkIndex >= 0 ? diffLines[firstHunkIndex] : undefined; + + // Keep the complete unified diff, including context and every hunk. The + // modal provides scrolling, so truncating here would hide later changes. + // The first hunk header is supplied separately through `header`. + const excerptLines = diffLines.filter((line, index) => index !== firstHunkIndex); const added = diffLines.filter((line) => line.startsWith("+") && !line.startsWith("+++")).length; const deleted = diffLines.filter((line) => line.startsWith("-") && !line.startsWith("---")).length; return { header, - lines: previewLines, + lines: excerptLines, added, deleted, };