fix: preserve review comments across unrelated edits

This commit is contained in:
Valdemar Lorenzen
2026-10-20 14:58:56 +02:00
parent 2727425518
commit 31203889bb
10 changed files with 422 additions and 147 deletions
+85 -13
View File
@@ -3282,6 +3282,85 @@ fn editing_a_reviewed_working_file_persists_its_invalidation() {
assert!(store.load(&root, id).unwrap().reviewed_files.is_empty());
}
#[test]
fn review_navigation_maps_working_ranges_and_preserves_stale_snapshots() {
use crate::review::{Anchor, Comment, Side};
let directory = Directory::new();
let root = directory.0.canonicalize().unwrap();
fs::write(root.join("file.txt"), "header\nunique target\ntail\n").unwrap();
let mut editor = editor();
working_diff(&mut editor, &root, &["file.txt"]);
editor.handle(Input::Enter);
editor
.diff
.as_mut()
.unwrap()
.comparison
.as_mut()
.unwrap()
.revisions[1] = "working:old".into();
editor.diff.as_mut().unwrap().local_review.document = crate::review::Review::new(root);
let anchor = Anchor {
revision: "working:old".into(),
path: "file.txt".into(),
side: Side::After,
start: TextPosition { row: 1, column: 7 },
end: TextPosition { row: 1, column: 13 },
content: editor.lines().join("\n"),
};
editor
.diff
.as_mut()
.unwrap()
.local_review
.document
.comments
.push(Comment {
id: 1,
anchor: anchor.clone(),
body: "Feedback".into(),
resolved: false,
});
editor
.apply(vec![Effect::Replace(
"inserted\nheader\nprefix unique target\ntail\n".into(),
)])
.unwrap();
editor.refresh_live_diff();
editor
.diff
.as_mut()
.unwrap()
.comparison
.as_mut()
.unwrap()
.revisions[1] = "working:new".into();
editor.execute("diff.review.edit 1");
let owner = editor.diff_owner.unwrap();
editor.select_pane(owner);
assert_eq!(editor.cursor(), Cursor { row: 2, column: 14 });
assert_eq!(
editor.diff.as_ref().unwrap().local_review.document.comments[0].anchor,
anchor
);
editor
.apply(vec![Effect::Replace(
"inserted\nheader\nprefix unique changed\ntail\n".into(),
)])
.unwrap();
editor.refresh_live_diff();
set_carets(&mut editor, &[(0, 0)], 0);
editor.execute("diff.review.edit 1");
assert!(editor.message().contains("stale"));
editor.select_pane(owner);
assert_eq!(editor.cursor(), Cursor::default());
assert_eq!(
editor.diff.as_ref().unwrap().local_review.document.comments[0].anchor,
anchor
);
}
#[test]
fn sqlite_reviews_autosave_restore_select_and_keep_exports_independent() {
use crate::review::{Review, Store, Verdict};
@@ -3362,10 +3441,11 @@ fn sqlite_reviews_autosave_restore_select_and_keep_exports_independent() {
assert_eq!(restored.storage_id, Some(id));
assert_eq!(restored.comments[0].body, "First feedback revised");
assert!(
!reopened
reopened
.workspace_diff()
.unwrap()
.review_anchor_current(&restored.comments[0].anchor)
.review_anchor_range(&restored.comments[0].anchor)
.is_none()
);
reopened.execute("diff.review.new");
let second_id = reopened
@@ -3777,7 +3857,7 @@ fn precise_review_ranges_capture_graphemes_and_navigate_to_their_start() {
};
assert_eq!(anchor.start, start);
assert_eq!(anchor.end, end);
assert!(diff.review_anchor_current(anchor));
assert!(diff.review_anchor_range(anchor).is_some());
editor.handle(Input::Escape);
assert_eq!(editor.pane_id(), owner);
assert_eq!(
@@ -3906,7 +3986,7 @@ fn local_review_visual_commands_and_palette_preserve_both_side_ranges() {
Side::After
}
);
assert!(diff.review_anchor_current(&anchor));
assert!(diff.review_anchor_range(&anchor).is_some());
let source_pane = editor.diff_owner.unwrap();
editor.select_pane(source_pane);
editor
@@ -7511,15 +7591,7 @@ mod system_clipboard {
let mut store = Store::open(&storage).unwrap();
store.save(&mut review).unwrap();
let id = review.storage_id.unwrap();
let expected = format!(
"Repository: {}\nReview {id} (revision 1): Review summary\n \
Verdict: changes_requested; 1 unresolved, 1 resolved (2 total)\n\
\nComment 1 [unresolved] file.txt (before) 0:1–1:1 @ base\n\
e\u{301}👩‍💻\n界\nFirst\nfeedback\n\
\nComment 2 [resolved] other.rs (after) 0:0–0:3 @ stale\n\
old\nResolved feedback\n",
root.display(),
);
let expected = review.format_text(true);
let mut editor = fixture.editor();
editor.set_clipboard_mode(mode).unwrap();
editor.clipboard = vec!["internal".into()];