// Hunk diffs for the DSH diff card ({path, oldText, newText} per hunk, 3 lines of context). // Each hunk also carries `oldStart`/`newStart` (1-based file lines of its first row) and `rows` // ([op, text] with op '=', '-', '+') so a client can draw a line-number gutter. import { lineMap } from './store.js' import { splitLines } from './text.js' export function hunkDiffs(path, before, after, context = 3) { const a = splitLines(before).lines const b = splitLines(after).lines const map = lineMap(a, b) // Walk both sides, emitting ops: '=' common, '-' removed, '+' added. const ops = [] // [op, text, oldLine|null, newLine|null] let i = 1; let j = 1 const pairs = [...map.entries()].sort((x, y) => x[0] - y[0]) for (const [ai, bj] of pairs) { while (i < ai) { ops.push(['-', a[i - 1], i, null]); i++ } while (j < bj) { ops.push(['+', b[j - 1], null, j]); j++ } ops.push(['=', a[i - 1], i, j]); i++; j++ } while (i <= a.length) { ops.push(['-', a[i - 1], i, null]); i++ } while (j <= b.length) { ops.push(['+', b[j - 1], null, j]); j++ } const changed = ops.map((o, k) => (o[0] !== '=' ? k : -1)).filter((k) => k >= 0) if (!changed.length) return [] const spans = [] for (const k of changed) { const s = Math.max(0, k - context); const e = Math.min(ops.length - 1, k + context) const last = spans.at(-1) if (last && s <= last[1] + 1) last[1] = Math.max(last[1], e) else spans.push([s, e]) } return spans.map(([s, e]) => { const oldL = []; const newL = []; const rows = [] let oldStart = null; let newStart = null for (let k = s; k <= e; k++) { const [op, text, ol, nl] = ops[k] if (op !== '+') { oldL.push(text); oldStart ??= ol } if (op !== '-') { newL.push(text); newStart ??= nl } rows.push([op, text]) } // A pure insertion/deletion side has no line of its own: anchor it next to its neighbour. oldStart ??= Math.max(1, (ops.slice(0, s).findLast((o) => o[2] !== null)?.[2] ?? 0) + 1) newStart ??= Math.max(1, (ops.slice(0, s).findLast((o) => o[3] !== null)?.[3] ?? 0) + 1) return { path, oldText: oldL.length ? oldL.join('\n') : null, newText: newL.join('\n'), oldStart, newStart, rows } }) }