feat: refresh diffs when selected jj bookmarks move
This commit is contained in:
+174
-16
@@ -4188,16 +4188,13 @@ impl Editor {
|
||||
{
|
||||
Some(buffers)
|
||||
}
|
||||
Operation::RefreshCheckout {
|
||||
follow_working: true,
|
||||
buffers,
|
||||
..
|
||||
} if self
|
||||
.diff
|
||||
.as_ref()
|
||||
.or(self.parked_diff.as_ref())
|
||||
.and_then(|diff| diff.after.as_ref())
|
||||
.is_some_and(|after| after.target == RevisionTarget::Working) =>
|
||||
Operation::RefreshCheckout { buffers, .. }
|
||||
if self
|
||||
.diff
|
||||
.as_ref()
|
||||
.or(self.parked_diff.as_ref())
|
||||
.and_then(|diff| diff.after.as_ref())
|
||||
.is_some_and(|after| after.target == RevisionTarget::Working) =>
|
||||
{
|
||||
Some(buffers)
|
||||
}
|
||||
@@ -4275,11 +4272,14 @@ impl Editor {
|
||||
}
|
||||
let preserved_view = (self.diff.as_ref().is_some_and(|diff| {
|
||||
diff.refresh_pending()
|
||||
&& diff
|
||||
.after
|
||||
.as_ref()
|
||||
.is_some_and(|after| after.target != RevisionTarget::Working)
|
||||
}) && !matches!(&result, Ok(Outcome::CheckoutRefresh(None))))
|
||||
&& (matches!(&result, Ok(Outcome::BookmarkRefresh(_)))
|
||||
|| diff
|
||||
.after
|
||||
.as_ref()
|
||||
.is_some_and(|after| after.target != RevisionTarget::Working))
|
||||
&& !matches!(&result, Ok(Outcome::CheckoutRefresh(None)))
|
||||
|| matches!(&result, Ok(Outcome::File { .. })) && diff.refresh_view.is_some()
|
||||
}))
|
||||
.then(|| self.active.view.inherit());
|
||||
let Some(diff) = &mut self.diff else {
|
||||
return false;
|
||||
@@ -4288,11 +4288,14 @@ impl Editor {
|
||||
return false;
|
||||
}
|
||||
let refresh = diff.refresh_pending();
|
||||
let previous_comparison = diff.comparison_id;
|
||||
if !diff.apply_result(id, result) {
|
||||
return false;
|
||||
}
|
||||
if refresh {
|
||||
self.pending_lsp_navigation = None;
|
||||
if diff.comparison_id != previous_comparison {
|
||||
self.pending_lsp_navigation = None;
|
||||
}
|
||||
self.diff_bound = None;
|
||||
} else if let Some(files) = &mut diff.files {
|
||||
files.set_view(self.file_explorer_view);
|
||||
@@ -15573,6 +15576,161 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bookmark_refresh_reloads_paths_and_preserves_view_until_lazy_content_arrives() {
|
||||
use crate::diff::{ChangedFile, Comparison, FileStatus};
|
||||
let directory = Directory::new();
|
||||
let mut editor = editor();
|
||||
historical_diff(
|
||||
&mut editor,
|
||||
&directory.0,
|
||||
vec!["old before".into(); 4],
|
||||
vec!["old after".into(); 4],
|
||||
);
|
||||
editor.diff.as_mut().unwrap().after.as_mut().unwrap().target = RevisionTarget::Bookmark {
|
||||
name: "topic".into(),
|
||||
remote: None,
|
||||
};
|
||||
editor.diff.as_mut().unwrap().focus = Focus::After;
|
||||
editor.bind_diff_buffer();
|
||||
editor.handle(Input::Char('j'));
|
||||
editor.diff.as_mut().unwrap().top = 2;
|
||||
editor.diff.as_mut().unwrap().left_after = 3;
|
||||
editor.diff.as_mut().unwrap().reviewed_files.insert(0);
|
||||
editor.diff.as_mut().unwrap().view_mode = ViewMode::Unified;
|
||||
let old_comparison = editor.diff().unwrap().comparison_id.unwrap();
|
||||
let old_snapshot = editor.buffer_id();
|
||||
let cursor = editor.cursor();
|
||||
let file = |path: &str, loaded| ChangedFile {
|
||||
path: path.into(),
|
||||
old_path: None,
|
||||
status: FileStatus::Modified,
|
||||
loaded,
|
||||
before: if loaded {
|
||||
vec!["new before".into(); 3]
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
after: if loaded {
|
||||
vec!["new after".into(); 3]
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
before_eof: false,
|
||||
after_eof: false,
|
||||
hunks: if loaded {
|
||||
crate::diff::line_hunks(
|
||||
&vec!["new before".into(); 3],
|
||||
false,
|
||||
&vec!["new after".into(); 3],
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
notice: None,
|
||||
};
|
||||
editor.queue_checkout_refreshes(false);
|
||||
let (_, refresh, _) = editor.take_next_diff_request().unwrap();
|
||||
assert!(editor.apply_diff_result(
|
||||
refresh,
|
||||
Ok(Outcome::BookmarkRefresh(Comparison {
|
||||
root: directory.0.clone(),
|
||||
before: "base".into(),
|
||||
after: "topic".into(),
|
||||
editable_paths: Default::default(),
|
||||
files: vec![file("a-new.txt", false), file("file.txt", false)],
|
||||
}))
|
||||
));
|
||||
let diff = editor.diff().unwrap();
|
||||
assert_eq!(diff.file, 1);
|
||||
assert_eq!(diff.focus, Focus::After);
|
||||
assert_eq!(diff.view_mode, ViewMode::Unified);
|
||||
assert!(diff.reviewed_files.is_empty());
|
||||
assert!(!diff.selected_file_loaded());
|
||||
assert!(!diff.comparison.as_ref().unwrap().files[0].loaded);
|
||||
assert_eq!(editor.buffer_id(), old_snapshot);
|
||||
let (_, load, operation) = editor.take_next_diff_request().unwrap();
|
||||
assert!(
|
||||
matches!(operation, Operation::LoadFile { comparison_id, file_index: 1 } if comparison_id == refresh)
|
||||
);
|
||||
assert!(editor.apply_diff_result(
|
||||
load,
|
||||
Ok(Outcome::File {
|
||||
comparison_id: refresh,
|
||||
file_index: 1,
|
||||
file: file("file.txt", true),
|
||||
})
|
||||
));
|
||||
assert_eq!(editor.lines(), ["new after"; 3]);
|
||||
assert_eq!(editor.cursor(), cursor);
|
||||
assert_eq!(editor.diff().unwrap().top, 2);
|
||||
assert_eq!(editor.diff().unwrap().left_after, 3);
|
||||
assert_ne!(editor.buffer_id(), old_snapshot);
|
||||
assert!(editor.mutation_blocked());
|
||||
assert!(!editor.apply_diff_result(refresh, Ok(Outcome::CheckoutRefresh(None))));
|
||||
assert_ne!(editor.diff().unwrap().comparison_id, Some(old_comparison));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bookmark_refresh_errors_recover_and_hidden_replacements_preserve_dirty_buffers() {
|
||||
let directory = Directory::new();
|
||||
let path = directory.path("file.txt");
|
||||
fs::write(&path, "original").unwrap();
|
||||
let mut editor = Editor::open(Some(path.clone()), vec![]).unwrap();
|
||||
working_diff(&mut editor, &directory.0, &["file.txt"]);
|
||||
editor.diff.as_mut().unwrap().after.as_mut().unwrap().target = RevisionTarget::Bookmark {
|
||||
name: "topic".into(),
|
||||
remote: None,
|
||||
};
|
||||
editor.diff.as_mut().unwrap().focus = Focus::After;
|
||||
editor.bind_diff_buffer();
|
||||
let dirty_buffer = editor.buffer_id();
|
||||
type_text(&mut editor, "ix");
|
||||
editor.diff.as_mut().unwrap().reviewed_files.insert(0);
|
||||
let comparison_id = editor.diff().unwrap().comparison_id;
|
||||
editor.queue_checkout_refreshes(false);
|
||||
let (_, request, _) = editor.take_next_diff_request().unwrap();
|
||||
assert!(editor.apply_diff_result(request, Err("bookmark is conflicted".into())));
|
||||
assert_eq!(editor.diff().unwrap().comparison_id, comparison_id);
|
||||
assert_eq!(editor.lines(), ["original"]);
|
||||
assert!(editor.diff().unwrap().reviewed_files.contains(&0));
|
||||
assert_eq!(editor.buffer(dirty_buffer).unwrap().lines, ["xoriginal"]);
|
||||
assert!(editor.buffer(dirty_buffer).unwrap().dirty());
|
||||
editor.queue_checkout_refreshes(false);
|
||||
let (_, recovery, _) = editor.take_next_diff_request().unwrap();
|
||||
assert!(editor.apply_diff_result(recovery, Ok(Outcome::CheckoutRefresh(None))));
|
||||
assert!(editor.diff().unwrap().error.is_none());
|
||||
assert_eq!(editor.diff().unwrap().comparison_id, comparison_id);
|
||||
assert!(editor.diff().unwrap().reviewed_files.contains(&0));
|
||||
|
||||
let hidden_tab = editor.tab_id();
|
||||
let owner = editor.pane_id();
|
||||
let old_snapshot = editor.buffer_id();
|
||||
editor.execute("tab.new");
|
||||
let visible_tab = editor.tab_id();
|
||||
editor.queue_checkout_refreshes(false);
|
||||
let (tab, request, _) = editor.take_next_diff_request().unwrap();
|
||||
assert_eq!(tab, hidden_tab);
|
||||
let mut replacement = editor.with_pane(owner, |editor| {
|
||||
editor.diff.as_mut().unwrap().comparison.take().unwrap()
|
||||
});
|
||||
replacement.files[0].after = vec!["moved bookmark".into()];
|
||||
assert!(editor.apply_diff_result(request, Ok(Outcome::BookmarkRefresh(replacement))));
|
||||
assert_eq!(editor.tab_id(), visible_tab);
|
||||
assert_eq!(editor.buffer_id(), old_snapshot);
|
||||
assert_eq!(editor.lines(), ["original"]);
|
||||
assert!(editor.mutation_blocked());
|
||||
assert_eq!(editor.buffer(dirty_buffer).unwrap().lines, ["xoriginal"]);
|
||||
assert!(editor.buffer(dirty_buffer).unwrap().dirty());
|
||||
editor.with_pane(owner, |editor| {
|
||||
assert_eq!(editor.lines(), ["moved bookmark"]);
|
||||
assert!(editor.diff().unwrap().reviewed_files.is_empty());
|
||||
assert!(editor.mutation_blocked());
|
||||
});
|
||||
assert_eq!(fs::read_to_string(&path).unwrap(), "original");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completed_working_refresh_serializes_lazy_selection_and_invalidates_pending_navigation() {
|
||||
for request_kind in [
|
||||
|
||||
Reference in New Issue
Block a user