Commit graph

1 commit

Author SHA1 Message Date
Souta
cd03cbf03e feat(plugin): Phase E2-α.2 — DiffEngine + ThreeWayMergeModal (0.4.30)
UI half of the 3-way merge feature. Hand-rolls a line-level diff
(LCS + backtrack, no npm dep so the bundle-size guard stays
comfortable) and an Obsidian Modal that shows ancestor / mine /
theirs side-by-side with adds + deletes highlighted.

Pieces:

- `plugin/src/conflict/DiffEngine.ts`
  - `diffLines(a, b): DiffChunk[]` — runs LCS on line arrays then
    backtracks to a list of {kind, lines} chunks, merging adjacent
    same-kind ops. `Int32Array` for the DP matrix to keep big
    inputs cheap (a 500-line × 500-line diff stays well under
    100 ms — verified via the perf-sanity test).
  - Boundary cases handled: empty inputs return zero or one chunk
    of the appropriate kind; identical inputs return one `eq` chunk.

- `plugin/src/ui/ThreeWayMergeModal.ts`
  - Modal subclass with the prompt() Promise pattern this codebase
    uses elsewhere (PendingPluginsModal / WriteConflictModal).
  - 3-pane layout via grid: ancestor (plain), mine (diff vs ancestor),
    theirs (diff vs ancestor). Adds tinted green, deletes tinted red
    + strikethrough.
  - Collapsible 'Edit merged' textarea pre-filled with mine; user can
    hand-merge and click 'Save merged'.
  - Buttons: Cancel / Keep theirs / Save merged / Keep mine (default).
    Escape + outside-click default to cancel — never silently picks
    a side.

- `plugin/tests/DiffEngine.test.ts` — 12 cases: empty boundaries,
  identity, pure add / pure del, line replacement, chunk-grouping
  invariant (no two adjacent chunks share a kind), reconstruction
  invariant (diff is lossless), 500-line perf sanity.

Modal isn't unit-tested — Obsidian's `Modal` is .d.ts only, so
behaviour gets verified via manual smoke. The next PR (E2-α.3)
wires the adapter conflict path so the modal can be exercised
end-to-end against the docker test sshd.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 14:37:36 +09:00