5.2 KiB
5.2 KiB
Plan: Rider-style 3-pane merge editor
Spec: docs/superpowers/specs/2026-06-19-rider-merge-editor-design.md
TDD, one focused commit per task (Conventional Commits, feat(merge): …).
Build with -c Release per project (a running Worker locks Debug).
Run ClaudeDo.Ui.Tests (and Localization.Tests for Task 6). No real claude CLI in tests.
Stage ONLY the files each task touches, by explicit path (parallel sessions leave WIP).
Backend + seam stay unchanged. Implementer/reviewer subagents use sonnet.
Task 1 — VM: active-file model + 3-pane reconstruction + readout
ConflictResolverViewModel / ConflictModels.cs, additive (seam untouched).
- Add
ActiveFile(MergeFile?),SelectFileCommand(MergeFile), default to first file after load. KeepFiles,Current/CurrentIndex/Next/Previous(focused conflict for the header arrows),CanContinue, binary guard, planning routing — all unchanged. - Add computed, per
ActiveFile:ActiveOursText= concat(stable.Text | conflict.Ours)ActiveTheirsText= concat(stable.Text | conflict.Theirs)ActiveResultText= concat(stable.Text | conflict.Resolution ?? conflict.Ours)ActiveConflicts= ordered descriptors (block + segment index) for the view.
PositionText→"{conflicts} conflicts · {resolved} resolved"for the active file; keepCanContinue= every file resolved AND no binary.- Switching files raises a change event the view listens to (reuse/extend
CurrentChanged→ e.g.ActiveFileChanged). - Tests (Ui.Tests): reconstruction text for ours/theirs/result (result seeds unresolved
with Ours); resolving a block updates
ActiveResultText+ readout; switching files preserves each block'sResolution;CanContinueblocks until all files resolved; binary file still blocks. Keep all existing tests green.
Task 2 — View: 3-pane AXAML shell + document assembly + synced scroll
Views/Conflicts/ConflictResolverView.axaml(.cs). Visual — verified by running.
- Replace AXAML: ModalShell host kept; header row (◀/▶ focus arrows bound to
Previous/Next, file switcher
ItemsControl/ComboBoxoverFilesbound toSelectFileCommand, right-alignedPositionText);Grid ColumnDefinitions="*,*,*"of three bordered panes with headers Ours · current (merge target) / Result / Theirs · incoming (task) (drop Base); footer Continue (IsEnabled=CanContinue) / Abort; binary banner (kept);Escape→Abort (kept). - Code-behind: build three
TextDocuments fromActiveFilesegments, recording each conflict's start line + line count per document; install TextMate per pane by file extension; rebuild onActiveFileChanged; Ours/TheirsIsReadOnly=true. - Proportional synced vertical scroll across the three panes (re-entrancy guard).
- Push Result edits back to the active block
Resolution(refined in Task 4).
Task 3 — Result pane: read-only stable, editable conflicts
ConflictResolverView.axaml.cs + a small IReadOnlySectionProvider helper.
- Track each conflict's result span in a
TextSegmentCollection<…>over the Result document (anchors auto-adjust on edit). IReadOnlySectionProvider:CanInsertonly strictly inside a conflict span;GetDeletableSegmentsintersects with conflict spans only. Stable text becomes immutable; conflict regions stay editable.- Editing inside a conflict span writes the span text back to the block
Resolutionand flips it resolved (updates readout +CanContinue).
Task 4 — Color blocks (IBackgroundRenderer) + accept overlay
ConflictResolverView.axaml.cs + renderer/overlay helpers.
IBackgroundRendererper pane: unresolved conflict = red (Blood tint), resolved = green/muted, Ours side = Moss tint, Theirs side = Accent tint — driven by recorded spans + blockIsResolved.- Between-pane overlay Canvas (Ours|Result and Result|Theirs):
›accept-ours /‹accept-theirs +✕dismiss per conflict, positioned at the block'sTextViewvisual top, recomputed on scroll/resize. Click →block.AcceptOurs/AcceptTheirsand replace the tracked Result span; resolved blocks recolor.
Task 5 — Polish: readout, focus arrows scroll-to-conflict, resolved styling
- ◀/▶ arrows move
Currentand scroll all three panes to that conflict. M conflicts · K resolvedlive readout; Continue tooltip/hint when blocked.- Resolved conflict recolors and drops its accept overlay; unresolved stays red. (Fold into Task 4 if small.)
Task 6 — Localization + tokens
- Add
conflictResolver.*keys (pane headers, readout, accept tooltips, hints) tolocales/en.jsonANDlocales/de.json(keep key parity). - Add Tokens.axaml color tokens only if a needed conflict/resolved shade is missing.
- Run Localization.Tests (parity) + a quick scan for hard-coded strings in the view.
Task 7 — Verify
- Build
ClaudeDo.App+ClaudeDo.Ui-c Release; runUi.Tests+Localization.Tests. - Update
src/ClaudeDo.Ui/CLAUDE.md(Planning/Conflicts paragraph → new 3-pane editor). - Visual verification gap (flag to Mika): run the app, trigger a real conflict (single-task approve + planning unit-merge) and confirm panes/colors/accept/scroll/ gating/binary render correctly — cannot be asserted in tests.