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:
+22
-9
@@ -146,7 +146,10 @@ fn resolver_keeps_unsaved_result_and_undo_then_saves_and_retains_resolved_file()
|
||||
]);
|
||||
session.execute("resolve");
|
||||
ready(&mut session);
|
||||
assert_eq!(session.editor().context().text, draft);
|
||||
let seeded = format!("draft\n{}", Fixture::text("left"));
|
||||
assert_eq!(session.editor().context().text, seeded);
|
||||
assert_ne!(seeded, draft);
|
||||
assert!(session.editor().dirty());
|
||||
assert_eq!(
|
||||
fs::read_to_string(fixture.root.join("first.txt")).unwrap(),
|
||||
original_disk
|
||||
@@ -164,23 +167,33 @@ fn resolver_keeps_unsaved_result_and_undo_then_saves_and_retains_resolved_file()
|
||||
]),
|
||||
operation
|
||||
);
|
||||
session.handle(Input::Char('u'));
|
||||
assert_eq!(session.editor().context().text, draft);
|
||||
session.handle(Input::Char('U'));
|
||||
assert_eq!(session.editor().context().text, seeded);
|
||||
let source = session.editor().resolver().unwrap().files[0]
|
||||
.sources
|
||||
.iter()
|
||||
.position(|source| !source.base)
|
||||
.enumerate()
|
||||
.filter(|(_, source)| !source.base)
|
||||
.nth(1)
|
||||
.unwrap()
|
||||
.0
|
||||
+ 1;
|
||||
session.execute(&format!("resolve.use_source {source}"));
|
||||
assert_ne!(session.editor().context().text, draft);
|
||||
assert!(session.editor().context().text.starts_with("draft\n"));
|
||||
let chosen = session.editor().context().text;
|
||||
assert_ne!(chosen, seeded);
|
||||
assert!(chosen.starts_with("draft\n"));
|
||||
assert!(chosen.contains("context_15\n"));
|
||||
session.handle(Input::Char('u'));
|
||||
assert_eq!(session.editor().context().text, draft);
|
||||
session.execute(&format!("resolve.use_source {source}"));
|
||||
session.execute("resolve.next");
|
||||
assert_eq!(session.editor().context().text, seeded);
|
||||
session.execute(&format!("resolve.use_source {source}"));
|
||||
let cursor = session.editor().cursor();
|
||||
let resolved_text = session.editor().context().text;
|
||||
assert!(resolved_text.starts_with("draft\n"));
|
||||
assert!(resolved_text.contains("context_15\n"));
|
||||
session.execute("resolve.view.toggle");
|
||||
session.execute("resolve.view.toggle");
|
||||
assert_eq!(session.editor().context().text, resolved_text);
|
||||
assert_eq!(session.editor().cursor(), cursor);
|
||||
session.execute("w");
|
||||
ready(&mut session);
|
||||
let resolver = session.editor().resolver().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user