Allow buffer search to search deleted hunks (#23632)

Conrad Irwin created

Closes #ISSUE

Release Notes:

- N/A

Change summary

crates/editor/src/items.rs              | 56 +++++++++++++-------
crates/multi_buffer/src/multi_buffer.rs | 74 ++++++++++++++++----------
2 files changed, 80 insertions(+), 50 deletions(-)

Detailed changes

crates/editor/src/items.rs 🔗

@@ -1507,26 +1507,42 @@ impl SearchableItem for Editor {
                 search_within_ranges
             };
 
-            for (search_buffer, search_range, excerpt_id) in
-                buffer.ranges_to_buffer_ranges(search_within_ranges.into_iter())
-            {
-                ranges.extend(
-                    query
-                        .search(search_buffer, Some(search_range.clone()))
-                        .await
-                        .into_iter()
-                        .map(|match_range| {
-                            let start =
-                                search_buffer.anchor_after(search_range.start + match_range.start);
-                            let end =
-                                search_buffer.anchor_before(search_range.start + match_range.end);
-                            Anchor::range_in_buffer(
-                                excerpt_id,
-                                search_buffer.remote_id(),
-                                start..end,
-                            )
-                        }),
-                );
+            for range in search_within_ranges {
+                for (search_buffer, search_range, excerpt_id, deleted_hunk_anchor) in
+                    buffer.range_to_buffer_ranges_with_deleted_hunks(range)
+                {
+                    ranges.extend(
+                        query
+                            .search(search_buffer, Some(search_range.clone()))
+                            .await
+                            .into_iter()
+                            .map(|match_range| {
+                                if let Some(deleted_hunk_anchor) = deleted_hunk_anchor {
+                                    let start = search_buffer
+                                        .anchor_after(search_range.start + match_range.start);
+                                    let end = search_buffer
+                                        .anchor_before(search_range.start + match_range.end);
+                                    Anchor {
+                                        diff_base_anchor: Some(start),
+                                        ..deleted_hunk_anchor
+                                    }..Anchor {
+                                        diff_base_anchor: Some(end),
+                                        ..deleted_hunk_anchor
+                                    }
+                                } else {
+                                    let start = search_buffer
+                                        .anchor_after(search_range.start + match_range.start);
+                                    let end = search_buffer
+                                        .anchor_before(search_range.start + match_range.end);
+                                    Anchor::range_in_buffer(
+                                        excerpt_id,
+                                        search_buffer.remote_id(),
+                                        start..end,
+                                    )
+                                }
+                            }),
+                    );
+                }
             }
 
             ranges

crates/multi_buffer/src/multi_buffer.rs 🔗

@@ -3376,6 +3376,49 @@ impl MultiBufferSnapshot {
         result
     }
 
+    pub fn range_to_buffer_ranges_with_deleted_hunks<T: ToOffset>(
+        &self,
+        range: Range<T>,
+    ) -> impl Iterator<Item = (&BufferSnapshot, Range<usize>, ExcerptId, Option<Anchor>)> + '_ {
+        let start = range.start.to_offset(&self);
+        let end = range.end.to_offset(&self);
+
+        let mut cursor = self.cursor::<usize>();
+        cursor.seek(&start);
+
+        std::iter::from_fn(move || {
+            let region = cursor.region()?;
+            if region.range.start > end {
+                return None;
+            }
+            let start_overshoot = start.saturating_sub(region.range.start);
+            let end_overshoot = end.saturating_sub(region.range.start);
+            let start = region
+                .buffer_range
+                .end
+                .min(region.buffer_range.start + start_overshoot);
+            let end = region
+                .buffer_range
+                .end
+                .min(region.buffer_range.start + end_overshoot);
+
+            let region_excerpt_id = region.excerpt.id;
+            let deleted_hunk_anchor = if region.is_main_buffer {
+                None
+            } else {
+                Some(self.anchor_before(region.range.start))
+            };
+            let result = (
+                region.buffer,
+                start..end,
+                region_excerpt_id,
+                deleted_hunk_anchor,
+            );
+            cursor.next();
+            Some(result)
+        })
+    }
+
     /// Retrieves buffer metadata for the given range, and converts it into multi-buffer
     /// coordinates.
     ///
@@ -4205,36 +4248,7 @@ impl MultiBufferSnapshot {
     where
         D: TextDimension + Ord + Sub<D, Output = D>,
     {
-        let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&());
-        let locator = self.excerpt_locator_for_id(anchor.excerpt_id);
-
-        cursor.seek(locator, Bias::Left, &());
-        if cursor.item().is_none() {
-            cursor.next(&());
-        }
-
-        let mut excerpt_position = D::from_text_summary(&cursor.start().text);
-        if let Some(excerpt) = cursor.item() {
-            if excerpt.id == anchor.excerpt_id {
-                let excerpt_buffer_start =
-                    excerpt.range.context.start.summary::<D>(&excerpt.buffer);
-                let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer);
-                let buffer_position = cmp::min(
-                    excerpt_buffer_end,
-                    anchor.text_anchor.summary::<D>(&excerpt.buffer),
-                );
-                if buffer_position > excerpt_buffer_start {
-                    excerpt_position.add_assign(&(buffer_position - excerpt_buffer_start));
-                }
-            }
-        }
-
-        let mut diff_transforms_cursor = self
-            .diff_transforms
-            .cursor::<(ExcerptDimension<D>, OutputDimension<D>)>(&());
-        diff_transforms_cursor.seek(&ExcerptDimension(excerpt_position), Bias::Left, &());
-
-        self.resolve_summary_for_anchor(anchor, excerpt_position, &mut diff_transforms_cursor)
+        self.summaries_for_anchors([anchor])[0]
     }
 
     fn resolve_summary_for_anchor<D>(