From 71128d2ee6b55824c393f2b2b97f2504a86963c0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 2 Aug 2022 16:52:37 +0200 Subject: [PATCH 1/2] Compute diffs based on characters rather than lines Previously, a change on a given line would cause that whole line to be replaced. In turn, this caused anchors on that line to go to the start of that line because they would lie inside of a deleted region after applying the diff. By switching to a character-wise diff, we perform smaller edits to the buffer which stabilizes anchor positions. --- crates/language/src/buffer.rs | 2 +- crates/language/src/tests.rs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index e6b0d48820..353f3182c0 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -1006,7 +1006,7 @@ impl Buffer { let old_text = old_text.to_string(); let line_ending = LineEnding::detect(&new_text); LineEnding::normalize(&mut new_text); - let changes = TextDiff::from_lines(old_text.as_str(), new_text.as_str()) + let changes = TextDiff::from_chars(old_text.as_str(), new_text.as_str()) .iter_all_changes() .map(|c| (c.tag(), c.value().len())) .collect::>(); diff --git a/crates/language/src/tests.rs b/crates/language/src/tests.rs index 937ff06930..572f2b0ba8 100644 --- a/crates/language/src/tests.rs +++ b/crates/language/src/tests.rs @@ -183,20 +183,23 @@ fn test_edit_events(cx: &mut gpui::MutableAppContext) { async fn test_apply_diff(cx: &mut gpui::TestAppContext) { let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n"; let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); + let anchor = buffer.read_with(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3))); let text = "a\nccc\ndddd\nffffff\n"; let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await; buffer.update(cx, |buffer, cx| { buffer.apply_diff(diff, cx).unwrap(); + assert_eq!(buffer.text(), text); + assert_eq!(anchor.to_point(&buffer), Point::new(2, 3)); }); - cx.read(|cx| assert_eq!(buffer.read(cx).text(), text)); let text = "a\n1\n\nccc\ndd2dd\nffffff\n"; let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await; buffer.update(cx, |buffer, cx| { buffer.apply_diff(diff, cx).unwrap(); + assert_eq!(buffer.text(), text); + assert_eq!(anchor.to_point(&buffer), Point::new(4, 4)); }); - cx.read(|cx| assert_eq!(buffer.read(cx).text(), text)); } #[gpui::test] From fc141001344237fa9d3f5b6fca2e181a1653e3b4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 2 Aug 2022 18:48:17 +0200 Subject: [PATCH 2/2] Fix tests --- crates/project/src/project_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index 4c5e9ef8e1..3dc4e9359f 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -2498,7 +2498,7 @@ async fn test_buffer_file_changes_on_disk(cx: &mut gpui::TestAppContext) { .collect::>(); assert_eq!( anchor_positions, - [Point::new(1, 1), Point::new(3, 1), Point::new(4, 0)] + [Point::new(1, 1), Point::new(3, 1), Point::new(3, 5)] ); });