Fix panic when editing diff (#24298)

Conrad Irwin created

Release Notes:

- N/A

Change summary

crates/multi_buffer/src/multi_buffer.rs       |  24 +---
crates/multi_buffer/src/multi_buffer_tests.rs | 101 +++++++++++++++++++++
2 files changed, 110 insertions(+), 15 deletions(-)

Detailed changes

crates/multi_buffer/src/multi_buffer.rs 🔗

@@ -1424,24 +1424,19 @@ impl MultiBuffer {
         cx: &mut Context<Self>,
     ) {
         let buffer_snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
-        let (mut insert_after, excerpt_ids) =
-            if let Some(existing) = self.buffers_by_path.get(&path) {
-                (*existing.last().unwrap(), existing.clone())
-            } else {
-                (
-                    self.buffers_by_path
-                        .range(..path.clone())
-                        .next_back()
-                        .map(|(_, value)| *value.last().unwrap())
-                        .unwrap_or(ExcerptId::min()),
-                    Vec::default(),
-                )
-            };
+
+        let mut insert_after = self
+            .buffers_by_path
+            .range(..path.clone())
+            .next_back()
+            .map(|(_, value)| *value.last().unwrap())
+            .unwrap_or(ExcerptId::min());
+        let existing = self.buffers_by_path.get(&path).cloned().unwrap_or_default();
 
         let (new, _) = build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
 
         let mut new_iter = new.into_iter().peekable();
-        let mut existing_iter = excerpt_ids.into_iter().peekable();
+        let mut existing_iter = existing.into_iter().peekable();
 
         let mut new_excerpt_ids = Vec::new();
         let mut to_remove = Vec::new();
@@ -1495,7 +1490,6 @@ impl MultiBuffer {
             // maybe merge overlapping excerpts?
             // it's hard to distinguish between a manually expanded excerpt, and one that
             // got smaller because of a missing diff.
-            //
             if existing_start == new.context.start && existing_end == new.context.end {
                 new_excerpt_ids.append(&mut self.insert_excerpts_after(
                     insert_after,

crates/multi_buffer/src/multi_buffer_tests.rs 🔗

@@ -1578,6 +1578,107 @@ fn test_repeatedly_expand_a_diff_hunk(cx: &mut TestAppContext) {
     );
 }
 
+#[gpui::test]
+fn test_set_excerpts_for_buffer_ordering(cx: &mut TestAppContext) {
+    let buf1 = cx.new(|cx| {
+        Buffer::local(
+            indoc! {
+            "zero
+            one
+            two
+            two.five
+            three
+            four
+            five
+            six
+            seven
+            eight
+            nine
+            ten
+            eleven
+            ",
+            },
+            cx,
+        )
+    });
+    let path1: PathKey = PathKey::namespaced("0", Path::new("/"));
+
+    let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadWrite));
+    multibuffer.update(cx, |multibuffer, cx| {
+        multibuffer.set_excerpts_for_path(
+            path1.clone(),
+            buf1.clone(),
+            vec![
+                Point::row_range(1..2),
+                Point::row_range(6..7),
+                Point::row_range(11..12),
+            ],
+            1,
+            cx,
+        );
+    });
+
+    assert_excerpts_match(
+        &multibuffer,
+        cx,
+        indoc! {
+            "-----
+            zero
+            one
+            two
+            two.five
+            -----
+            four
+            five
+            six
+            seven
+            -----
+            nine
+            ten
+            eleven
+            "
+        },
+    );
+
+    buf1.update(cx, |buffer, cx| buffer.edit([(0..5, "")], None, cx));
+
+    multibuffer.update(cx, |multibuffer, cx| {
+        multibuffer.set_excerpts_for_path(
+            path1.clone(),
+            buf1.clone(),
+            vec![
+                Point::row_range(0..2),
+                Point::row_range(5..6),
+                Point::row_range(10..11),
+            ],
+            1,
+            cx,
+        );
+    });
+
+    assert_excerpts_match(
+        &multibuffer,
+        cx,
+        indoc! {
+            "-----
+             one
+             two
+             two.five
+             three
+             -----
+             four
+             five
+             six
+             seven
+             -----
+             nine
+             ten
+             eleven
+            "
+        },
+    );
+}
+
 #[gpui::test]
 fn test_set_excerpts_for_buffer(cx: &mut TestAppContext) {
     let buf1 = cx.new(|cx| {