fix(ui): render whole-file patches as complete diffs (#30516)

This commit is contained in:
Brendan Allan
2026-06-03 07:29:23 +00:00
committed by GitHub
parent 01cc475923
commit 707166ae4a
3 changed files with 80 additions and 4 deletions
+57 -2
View File
@@ -60,13 +60,68 @@ function fileDiffFromPatch(file: string, patch: string) {
return hit
}
const input = patchInput(file, patch)
const value = (input ? parsePatchFiles(input)[0]?.files[0] : undefined) ?? emptyFileDiff(file)
const contents = completePatchContents(patch)
const input = contents ? undefined : patchInput(file, patch)
const value = contents
? fileDiffFromContent(file, contents.before, contents.after)
: (input ? parsePatchFiles(input)[0]?.files[0] : undefined) ?? emptyFileDiff(file)
patchFileDiffCache.set(key, value)
while (patchFileDiffCache.size > diffCacheLimit) patchFileDiffCache.delete(patchFileDiffCache.keys().next().value!)
return value
}
function completePatchContents(patch: string) {
try {
const parsed = parsePatch(patch)[0]
if (!parsed || (!parsed.index && !parsed.oldFileName && !parsed.newFileName)) return
// Snapshot and VCS producers request full context. Tool patches use jsdiff's shorter default context.
if (!patch.startsWith("diff --git ") && !/^--- [^\n]*\t\r?\n\+\+\+ [^\n]*\t(?:\r?\n|$)/m.test(patch)) return
// Full patches collapse into one leading hunk. Separated hunks omit ranges and must stay partial.
if (parsed.hunks.length !== 1) return
const hunk = parsed.hunks[0]
if (!hunk || hunk.oldStart > 1 || hunk.newStart > 1) return
const before: Array<{ text: string; newline: boolean }> = []
const after: Array<{ text: string; newline: boolean }> = []
let previous: "-" | "+" | " " | undefined
for (const line of hunk.lines) {
if (line.startsWith("\\")) {
if (previous === "-" || previous === " ") {
const value = before.at(-1)
if (value) value.newline = false
}
if (previous === "+" || previous === " ") {
const value = after.at(-1)
if (value) value.newline = false
}
continue
}
if (line.startsWith("-")) {
before.push({ text: line.slice(1), newline: true })
previous = "-"
continue
}
if (line.startsWith("+")) {
after.push({ text: line.slice(1), newline: true })
previous = "+"
continue
}
if (!line.startsWith(" ")) return
before.push({ text: line.slice(1), newline: true })
after.push({ text: line.slice(1), newline: true })
previous = " "
}
const text = (lines: Array<{ text: string; newline: boolean }>) =>
lines.map((line) => line.text + (line.newline ? "\n" : "")).join("")
return { before: text(before), after: text(after) }
} catch {
return
}
}
function patchInput(file: string, patch: string) {
try {
const parsed = parsePatch(patch)[0]