feat: resolve conflicts through focused two-way drafts

Replace the marker-filled three-pane resolver with a marker-free native
Draft versus frozen Alternative projected from current working text.
Preserve preexisting outside edits, native undo, dirty-save guards, all
sides/bases, and draft caret/viewports across separate History views.
Reuse DiffState alignment/highlighting/excerpts for Resolution and merge
its base-aligned rows for readonly three-way History. Hide explorer and
source-selector chrome by default.

Verified 926 tests plus actual terminal projection, History highlighting,
hunk choice, optional explorer, and guarded jj-confirmed save workflows.
Clippy completes with pre-existing warnings only. Smoke fixtures stay
unresolved in this ancestry; remove that ancestry before publication.

Size exception: approximately 1650 implementation added/deleted lines,
excluding tests/docs, kept coherent because native draft lifecycle and
aligned rendering must change together without parallel legacy modes.
This commit is contained in:
Valdemar Lorenzen
2026-10-14 16:40:23 +02:00
parent f2d505b952
commit ef4c38d8a7
12 changed files with 2292 additions and 421 deletions
+20
View File
@@ -611,6 +611,25 @@ impl EditorSession {
self.synchronize_documents();
}
pub(crate) fn set_resolver_viewport(
&mut self,
top: usize,
left_before: usize,
left_after: usize,
) {
self.editor
.set_resolver_viewport(top, left_before, left_after);
}
pub(crate) fn scroll_resolver(&mut self, focus: Focus, down: bool) {
self.editor.scroll_resolver_diff(focus, down);
}
pub(crate) fn scroll_resolver_horizontal(&mut self, focus: Focus, right: bool, width: usize) {
self.editor
.scroll_resolver_diff_horizontal(focus, right, width);
}
pub fn handle(&mut self, input: Input) {
if input == Input::Ctrl('r')
&& self
@@ -904,6 +923,7 @@ impl EditorSession {
}
fn synchronize_documents(&mut self) -> bool {
self.editor.refresh_resolver_comparison();
let blame_changed = self.poll_blame();
// Leaving a request's source invalidates it permanently, even if history returns there.
if let Some(requests) = self.requests.get_mut("core")