v1.1.1: theme-token diff card with old/new line-number gutter; hunks carry oldStart/newStart/rows

This commit is contained in:
Agent committed 2026-10-11 00:42:38 +00:00
1 parent 0dae0ee53d
commit 583aa9a10b
5 files changed
+137 -45

No files matched your search

+18 -11
View File
@@ -1,4 +1,6 @@
// 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'
@@ -7,16 +9,16 @@ export function hunkDiffs(path, before, after, context = 3) {
const b = splitLines(after).lines
const map = lineMap(a, b)
// Walk both sides, emitting ops: '=' common, '-' removed, '+' added.
const ops = []
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]])
while (j < bj) ops.push(['+', b[j++ - 1]])
ops.push(['=', a[i - 1]]); i++; j++
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]])
while (j <= b.length) ops.push(['+', b[j++ - 1]])
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 = []
@@ -27,12 +29,17 @@ export function hunkDiffs(path, before, after, context = 3) {
else spans.push([s, e])
}
return spans.map(([s, e]) => {
const oldL = []; const newL = []
const oldL = []; const newL = []; const rows = []
let oldStart = null; let newStart = null
for (let k = s; k <= e; k++) {
const [op, text] = ops[k]
if (op !== '+') oldL.push(text)
if (op !== '-') newL.push(text)
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])
}
return { path, oldText: oldL.length ? oldL.join('\n') : null, newText: newL.join('\n') }
// 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 }
})
}