Extract an `ExcerptRange` containing a `context` field in `multi_buffer`

Antonio Scandurra created

This lays the groundwork for adding an optional `primary` field that can
be supplied to provide the "jump to" feature.

Change summary

crates/diagnostics/src/diagnostics.rs      |   7 
crates/editor/src/display_map/block_map.rs |   4 
crates/editor/src/editor.rs                |  42 ++
crates/editor/src/movement.rs              |  10 
crates/editor/src/multi_buffer.rs          | 266 ++++++++++++++++-------
crates/search/src/buffer_search.rs         |   2 
6 files changed, 231 insertions(+), 100 deletions(-)

Detailed changes

crates/diagnostics/src/diagnostics.rs 🔗

@@ -5,7 +5,8 @@ use collections::{BTreeMap, HashSet};
 use editor::{
     diagnostic_block_renderer,
     display_map::{BlockDisposition, BlockId, BlockProperties, RenderBlock},
-    highlight_diagnostic_message, Autoscroll, Editor, ExcerptId, MultiBuffer, ToOffset,
+    highlight_diagnostic_message, Autoscroll, Editor, ExcerptId, ExcerptRange, MultiBuffer,
+    ToOffset,
 };
 use gpui::{
     actions, elements::*, fonts::TextStyle, impl_internal_actions, platform::CursorStyle,
@@ -348,7 +349,9 @@ impl ProjectDiagnosticsEditor {
                                 .insert_excerpts_after(
                                     &prev_excerpt_id,
                                     buffer.clone(),
-                                    [excerpt_start..excerpt_end],
+                                    [ExcerptRange {
+                                        context: excerpt_start..excerpt_end,
+                                    }],
                                     excerpts_cx,
                                 )
                                 .pop()

crates/editor/src/display_map/block_map.rs 🔗

@@ -2,7 +2,7 @@ use super::{
     wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot},
     TextHighlights,
 };
-use crate::{Anchor, ToPoint as _};
+use crate::{Anchor, ExcerptRange, ToPoint as _};
 use collections::{Bound, HashMap, HashSet};
 use gpui::{ElementBox, RenderContext};
 use language::{BufferSnapshot, Chunk, Patch};
@@ -98,7 +98,7 @@ pub enum TransformBlock {
     Custom(Arc<Block>),
     ExcerptHeader {
         buffer: BufferSnapshot,
-        range: Range<text::Anchor>,
+        range: ExcerptRange<text::Anchor>,
         height: u8,
         starts_new_buffer: bool,
     },

crates/editor/src/editor.rs 🔗

@@ -36,7 +36,8 @@ use language::{
 };
 use multi_buffer::MultiBufferChunks;
 pub use multi_buffer::{
-    Anchor, AnchorRangeExt, ExcerptId, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint,
+    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
+    ToPoint,
 };
 use ordered_float::OrderedFloat;
 use project::{HoverBlock, Project, ProjectTransaction};
@@ -2833,11 +2834,11 @@ impl Editor {
                             let start = highlight
                                 .range
                                 .start
-                                .max(&excerpt_range.start, cursor_buffer_snapshot);
+                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
                             let end = highlight
                                 .range
                                 .end
-                                .min(&excerpt_range.end, cursor_buffer_snapshot);
+                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
                             if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
                                 continue;
                             }
@@ -7718,12 +7719,16 @@ mod tests {
             let mut multibuffer = MultiBuffer::new(0);
             multibuffer.push_excerpts(
                 toml_buffer.clone(),
-                [Point::new(0, 0)..Point::new(2, 0)],
+                [ExcerptRange {
+                    context: Point::new(0, 0)..Point::new(2, 0),
+                }],
                 cx,
             );
             multibuffer.push_excerpts(
                 rust_buffer.clone(),
-                [Point::new(0, 0)..Point::new(1, 0)],
+                [ExcerptRange {
+                    context: Point::new(0, 0)..Point::new(1, 0),
+                }],
                 cx,
             );
             multibuffer
@@ -9595,8 +9600,12 @@ mod tests {
             multibuffer.push_excerpts(
                 buffer.clone(),
                 [
-                    Point::new(0, 0)..Point::new(0, 4),
-                    Point::new(1, 0)..Point::new(1, 4),
+                    ExcerptRange {
+                        context: Point::new(0, 0)..Point::new(0, 4),
+                    },
+                    ExcerptRange {
+                        context: Point::new(1, 0)..Point::new(1, 4),
+                    },
                 ],
                 cx,
             );
@@ -9634,6 +9643,9 @@ mod tests {
                 [aaaa
                 (bbbb]
                 cccc)"});
+        let excerpt_ranges = excerpt_ranges
+            .into_iter()
+            .map(|context| ExcerptRange { context });
         let buffer = cx.add_model(|cx| Buffer::new(0, initial_text, cx));
         let multibuffer = cx.add_model(|cx| {
             let mut multibuffer = MultiBuffer::new(0);
@@ -9687,8 +9699,12 @@ mod tests {
                 .push_excerpts(
                     buffer.clone(),
                     [
-                        Point::new(0, 0)..Point::new(1, 4),
-                        Point::new(1, 0)..Point::new(2, 4),
+                        ExcerptRange {
+                            context: Point::new(0, 0)..Point::new(1, 4),
+                        },
+                        ExcerptRange {
+                            context: Point::new(1, 0)..Point::new(2, 4),
+                        },
                     ],
                     cx,
                 )
@@ -9771,8 +9787,12 @@ mod tests {
                 .push_excerpts(
                     buffer.clone(),
                     [
-                        Point::new(0, 0)..Point::new(1, 4),
-                        Point::new(1, 0)..Point::new(2, 4),
+                        ExcerptRange {
+                            context: Point::new(0, 0)..Point::new(1, 4),
+                        },
+                        ExcerptRange {
+                            context: Point::new(1, 0)..Point::new(2, 4),
+                        },
                     ],
                     cx,
                 )

crates/editor/src/movement.rs 🔗

@@ -272,7 +272,7 @@ pub fn surrounding_word(map: &DisplaySnapshot, position: DisplayPoint) -> Range<
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::{test::marked_display_snapshot, Buffer, DisplayMap, MultiBuffer};
+    use crate::{test::marked_display_snapshot, Buffer, DisplayMap, ExcerptRange, MultiBuffer};
     use language::Point;
     use settings::Settings;
 
@@ -494,8 +494,12 @@ mod tests {
             multibuffer.push_excerpts(
                 buffer.clone(),
                 [
-                    Point::new(0, 0)..Point::new(1, 4),
-                    Point::new(2, 0)..Point::new(3, 2),
+                    ExcerptRange {
+                        context: Point::new(0, 0)..Point::new(1, 4),
+                    },
+                    ExcerptRange {
+                        context: Point::new(2, 0)..Point::new(3, 2),
+                    },
                 ],
                 cx,
             );

crates/editor/src/multi_buffer.rs 🔗

@@ -104,7 +104,7 @@ pub struct ExcerptBoundary {
     pub id: ExcerptId,
     pub row: u32,
     pub buffer: BufferSnapshot,
-    pub range: Range<text::Anchor>,
+    pub range: ExcerptRange<text::Anchor>,
     pub starts_new_buffer: bool,
 }
 
@@ -113,12 +113,17 @@ struct Excerpt {
     id: ExcerptId,
     buffer_id: usize,
     buffer: BufferSnapshot,
-    range: Range<text::Anchor>,
+    range: ExcerptRange<text::Anchor>,
     max_buffer_row: u32,
     text_summary: TextSummary,
     has_trailing_newline: bool,
 }
 
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct ExcerptRange<T> {
+    pub context: Range<T>,
+}
+
 #[derive(Clone, Debug, Default)]
 struct ExcerptSummary {
     excerpt_id: ExcerptId,
@@ -215,7 +220,13 @@ impl MultiBuffer {
     pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
         let mut this = Self::new(buffer.read(cx).replica_id());
         this.singleton = true;
-        this.push_excerpts(buffer, [text::Anchor::MIN..text::Anchor::MAX], cx);
+        this.push_excerpts(
+            buffer,
+            [ExcerptRange {
+                context: text::Anchor::MIN..text::Anchor::MAX,
+            }],
+            cx,
+        );
         this.snapshot.borrow_mut().singleton = true;
         this
     }
@@ -343,8 +354,12 @@ impl MultiBuffer {
             }
             let start_excerpt = cursor.item().expect("start offset out of bounds");
             let start_overshoot = range.start - cursor.start();
-            let buffer_start =
-                start_excerpt.range.start.to_offset(&start_excerpt.buffer) + start_overshoot;
+            let buffer_start = start_excerpt
+                .range
+                .context
+                .start
+                .to_offset(&start_excerpt.buffer)
+                + start_overshoot;
 
             cursor.seek(&range.end, Bias::Right, &());
             if cursor.item().is_none() && range.end == *cursor.start() {
@@ -352,7 +367,12 @@ impl MultiBuffer {
             }
             let end_excerpt = cursor.item().expect("end offset out of bounds");
             let end_overshoot = range.end - cursor.start();
-            let buffer_end = end_excerpt.range.start.to_offset(&end_excerpt.buffer) + end_overshoot;
+            let buffer_end = end_excerpt
+                .range
+                .context
+                .start
+                .to_offset(&end_excerpt.buffer)
+                + end_overshoot;
 
             if start_excerpt.id == end_excerpt.id {
                 buffer_edits
@@ -360,10 +380,18 @@ impl MultiBuffer {
                     .or_insert(Vec::new())
                     .push((buffer_start..buffer_end, new_text, true));
             } else {
-                let start_excerpt_range =
-                    buffer_start..start_excerpt.range.end.to_offset(&start_excerpt.buffer);
-                let end_excerpt_range =
-                    end_excerpt.range.start.to_offset(&end_excerpt.buffer)..buffer_end;
+                let start_excerpt_range = buffer_start
+                    ..start_excerpt
+                        .range
+                        .context
+                        .end
+                        .to_offset(&start_excerpt.buffer);
+                let end_excerpt_range = end_excerpt
+                    .range
+                    .context
+                    .start
+                    .to_offset(&end_excerpt.buffer)
+                    ..buffer_end;
                 buffer_edits
                     .entry(start_excerpt.buffer_id)
                     .or_insert(Vec::new())
@@ -383,7 +411,7 @@ impl MultiBuffer {
                         .entry(excerpt.buffer_id)
                         .or_insert(Vec::new())
                         .push((
-                            excerpt.range.to_offset(&excerpt.buffer),
+                            excerpt.range.context.to_offset(&excerpt.buffer),
                             new_text.clone(),
                             false,
                         ));
@@ -523,8 +551,8 @@ impl MultiBuffer {
                     break;
                 }
 
-                let mut start = excerpt.range.start.clone();
-                let mut end = excerpt.range.end.clone();
+                let mut start = excerpt.range.context.start.clone();
+                let mut end = excerpt.range.context.end.clone();
                 if excerpt.id == selection.start.excerpt_id {
                     start = selection.start.text_anchor.clone();
                 }
@@ -644,7 +672,7 @@ impl MultiBuffer {
     pub fn push_excerpts<O>(
         &mut self,
         buffer: ModelHandle<Buffer>,
-        ranges: impl IntoIterator<Item = Range<O>>,
+        ranges: impl IntoIterator<Item = ExcerptRange<O>>,
         cx: &mut ModelContext<Self>,
     ) -> Vec<ExcerptId>
     where
@@ -692,7 +720,9 @@ impl MultiBuffer {
                 }
             }
 
-            excerpt_ranges.push(excerpt_start..excerpt_end);
+            excerpt_ranges.push(ExcerptRange {
+                context: excerpt_start..excerpt_end,
+            });
             range_counts.push(ranges_in_excerpt);
         }
 
@@ -722,7 +752,7 @@ impl MultiBuffer {
         &mut self,
         prev_excerpt_id: &ExcerptId,
         buffer: ModelHandle<Buffer>,
-        ranges: impl IntoIterator<Item = Range<O>>,
+        ranges: impl IntoIterator<Item = ExcerptRange<O>>,
         cx: &mut ModelContext<Self>,
     ) -> Vec<ExcerptId>
     where
@@ -786,8 +816,10 @@ impl MultiBuffer {
             if let Err(ix) = buffer_state.excerpts.binary_search(&id) {
                 buffer_state.excerpts.insert(ix, id.clone());
             }
-            let range = buffer_snapshot.anchor_before(&range.start)
-                ..buffer_snapshot.anchor_after(&range.end);
+            let range = ExcerptRange {
+                context: buffer_snapshot.anchor_before(&range.context.start)
+                    ..buffer_snapshot.anchor_after(&range.context.end),
+            };
             let excerpt = Excerpt::new(
                 id.clone(),
                 buffer_id,
@@ -846,7 +878,7 @@ impl MultiBuffer {
         &self,
         buffer: &ModelHandle<Buffer>,
         cx: &AppContext,
-    ) -> Vec<(ExcerptId, Range<text::Anchor>)> {
+    ) -> Vec<(ExcerptId, ExcerptRange<text::Anchor>)> {
         let mut excerpts = Vec::new();
         let snapshot = self.read(cx);
         let buffers = self.buffers.borrow();
@@ -894,7 +926,7 @@ impl MultiBuffer {
                     .unwrap()
                     .buffer
                     .clone(),
-                excerpt.range.clone(),
+                excerpt.range.context.clone(),
             )
         })
     }
@@ -914,7 +946,7 @@ impl MultiBuffer {
         }
 
         cursor.item().map(|excerpt| {
-            let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
+            let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
             let buffer_point = excerpt_start + offset - *cursor.start();
             let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone();
 
@@ -943,7 +975,7 @@ impl MultiBuffer {
             if excerpt.has_trailing_newline {
                 end_before_newline -= 1;
             }
-            let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
+            let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
             let start = excerpt_start + (cmp::max(start, *cursor.start()) - *cursor.start());
             let end = excerpt_start + (cmp::min(end, end_before_newline) - *cursor.start());
             let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone();
@@ -1234,7 +1266,7 @@ impl MultiBuffer {
                     buffer
                         .edits_since_in_range::<usize>(
                             old_excerpt.buffer.version(),
-                            old_excerpt.range.clone(),
+                            old_excerpt.range.context.clone(),
                         )
                         .map(|mut edit| {
                             let excerpt_old_start = cursor.start().1;
@@ -1384,7 +1416,9 @@ impl MultiBuffer {
                         let end_ix =
                             buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
                         let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
-                        start_ix..end_ix
+                        ExcerptRange {
+                            context: start_ix..end_ix,
+                        }
                     })
                     .collect::<Vec<_>>();
                 log::info!(
@@ -1393,7 +1427,7 @@ impl MultiBuffer {
                     ranges,
                     ranges
                         .iter()
-                        .map(|range| &buffer_text[range.clone()])
+                        .map(|range| &buffer_text[range.context.clone()])
                         .collect::<Vec<_>>()
                 );
 
@@ -1465,7 +1499,7 @@ impl MultiBufferSnapshot {
         cursor.seek(&offset, Bias::Left, &());
         let mut excerpt_chunks = cursor.item().map(|excerpt| {
             let end_before_footer = cursor.start() + excerpt.text_summary.bytes;
-            let start = excerpt.range.start.to_offset(&excerpt.buffer);
+            let start = excerpt.range.context.start.to_offset(&excerpt.buffer);
             let end = start + (cmp::min(offset, end_before_footer) - cursor.start());
             excerpt.buffer.reversed_chunks_in_range(start..end)
         });
@@ -1476,7 +1510,7 @@ impl MultiBufferSnapshot {
                 excerpt_chunks = Some(
                     excerpt
                         .buffer
-                        .reversed_chunks_in_range(excerpt.range.clone()),
+                        .reversed_chunks_in_range(excerpt.range.context.clone()),
                 );
             }
 
@@ -1581,7 +1615,7 @@ impl MultiBufferSnapshot {
         let mut cursor = self.excerpts.cursor::<usize>();
         cursor.seek(&offset, Bias::Right, &());
         let overshoot = if let Some(excerpt) = cursor.item() {
-            let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
+            let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
             let buffer_offset = excerpt
                 .buffer
                 .clip_offset(excerpt_start + (offset - cursor.start()), bias);
@@ -1600,7 +1634,7 @@ impl MultiBufferSnapshot {
         let mut cursor = self.excerpts.cursor::<Point>();
         cursor.seek(&point, Bias::Right, &());
         let overshoot = if let Some(excerpt) = cursor.item() {
-            let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
+            let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
             let buffer_point = excerpt
                 .buffer
                 .clip_point(excerpt_start + (point - cursor.start()), bias);
@@ -1621,7 +1655,7 @@ impl MultiBufferSnapshot {
         let overshoot = if let Some(excerpt) = cursor.item() {
             let excerpt_start = excerpt
                 .buffer
-                .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
+                .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
             let buffer_point = excerpt
                 .buffer
                 .clip_point_utf16(excerpt_start + (point - cursor.start()), bias);
@@ -1690,8 +1724,8 @@ impl MultiBufferSnapshot {
         if let Some(excerpt) = cursor.item() {
             let (start_offset, start_point) = cursor.start();
             let overshoot = offset - start_offset;
-            let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
-            let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
+            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
+            let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
             let buffer_point = excerpt
                 .buffer
                 .offset_to_point(excerpt_start_offset + overshoot);
@@ -1711,8 +1745,8 @@ impl MultiBufferSnapshot {
         if let Some(excerpt) = cursor.item() {
             let (start_offset, start_point) = cursor.start();
             let overshoot = offset - start_offset;
-            let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
-            let excerpt_start_point = excerpt.range.start.to_point_utf16(&excerpt.buffer);
+            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
+            let excerpt_start_point = excerpt.range.context.start.to_point_utf16(&excerpt.buffer);
             let buffer_point = excerpt
                 .buffer
                 .offset_to_point_utf16(excerpt_start_offset + overshoot);
@@ -1732,8 +1766,9 @@ impl MultiBufferSnapshot {
         if let Some(excerpt) = cursor.item() {
             let (start_offset, start_point) = cursor.start();
             let overshoot = point - start_offset;
-            let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
-            let excerpt_start_point_utf16 = excerpt.range.start.to_point_utf16(&excerpt.buffer);
+            let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
+            let excerpt_start_point_utf16 =
+                excerpt.range.context.start.to_point_utf16(&excerpt.buffer);
             let buffer_point = excerpt
                 .buffer
                 .point_to_point_utf16(excerpt_start_point + overshoot);
@@ -1753,8 +1788,8 @@ impl MultiBufferSnapshot {
         if let Some(excerpt) = cursor.item() {
             let (start_point, start_offset) = cursor.start();
             let overshoot = point - start_point;
-            let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
-            let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
+            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
+            let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
             let buffer_offset = excerpt
                 .buffer
                 .point_to_offset(excerpt_start_point + overshoot);
@@ -1774,10 +1809,10 @@ impl MultiBufferSnapshot {
         if let Some(excerpt) = cursor.item() {
             let (start_point, start_offset) = cursor.start();
             let overshoot = point - start_point;
-            let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
+            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
             let excerpt_start_point = excerpt
                 .buffer
-                .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
+                .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
             let buffer_offset = excerpt
                 .buffer
                 .point_utf16_to_offset(excerpt_start_point + overshoot);
@@ -1811,8 +1846,8 @@ impl MultiBufferSnapshot {
         cursor.seek(&Point::new(row, 0), Bias::Right, &());
         if let Some(excerpt) = cursor.item() {
             let overshoot = row - cursor.start().row;
-            let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
-            let excerpt_end = excerpt.range.end.to_point(&excerpt.buffer);
+            let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
+            let excerpt_end = excerpt.range.context.end.to_point(&excerpt.buffer);
             let buffer_row = excerpt_start.row + overshoot;
             let line_start = Point::new(buffer_row, 0);
             let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
@@ -1847,7 +1882,7 @@ impl MultiBufferSnapshot {
                 end_before_newline -= 1;
             }
 
-            let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
+            let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
             let start_in_excerpt = excerpt_start + (range.start - cursor.start());
             let end_in_excerpt =
                 excerpt_start + (cmp::min(end_before_newline, range.end) - cursor.start());
@@ -1881,7 +1916,7 @@ impl MultiBufferSnapshot {
             if let Some(excerpt) = cursor.item() {
                 range.end = cmp::max(*cursor.start(), range.end);
 
-                let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
+                let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
                 let end_in_excerpt = excerpt_start + (range.end - cursor.start());
                 summary.add_assign(
                     &excerpt
@@ -1907,8 +1942,9 @@ impl MultiBufferSnapshot {
         let mut 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.start.summary::<D>(&excerpt.buffer);
-                let excerpt_buffer_end = excerpt.range.end.summary::<D>(&excerpt.buffer);
+                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),
@@ -1954,8 +1990,10 @@ impl MultiBufferSnapshot {
             let position = D::from_text_summary(&cursor.start().text);
             if let Some(excerpt) = cursor.item() {
                 if excerpt.id == *excerpt_id {
-                    let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
-                    let excerpt_buffer_end = excerpt.range.end.summary::<D>(&excerpt.buffer);
+                    let excerpt_buffer_start =
+                        excerpt.range.context.start.summary::<D>(&excerpt.buffer);
+                    let excerpt_buffer_end =
+                        excerpt.range.context.end.summary::<D>(&excerpt.buffer);
                     summaries.extend(
                         excerpt
                             .buffer
@@ -2036,10 +2074,14 @@ impl MultiBufferSnapshot {
                     anchor = if let Some(excerpt) = next_excerpt {
                         let mut text_anchor = excerpt
                             .range
+                            .context
                             .start
                             .bias(anchor.text_anchor.bias, &excerpt.buffer);
-                        if text_anchor.cmp(&excerpt.range.end, &excerpt.buffer).is_gt() {
-                            text_anchor = excerpt.range.end.clone();
+                        if text_anchor
+                            .cmp(&excerpt.range.context.end, &excerpt.buffer)
+                            .is_gt()
+                        {
+                            text_anchor = excerpt.range.context.end.clone();
                         }
                         Anchor {
                             buffer_id: Some(excerpt.buffer_id),
@@ -2049,13 +2091,14 @@ impl MultiBufferSnapshot {
                     } else if let Some(excerpt) = prev_excerpt {
                         let mut text_anchor = excerpt
                             .range
+                            .context
                             .end
                             .bias(anchor.text_anchor.bias, &excerpt.buffer);
                         if text_anchor
-                            .cmp(&excerpt.range.start, &excerpt.buffer)
+                            .cmp(&excerpt.range.context.start, &excerpt.buffer)
                             .is_lt()
                         {
-                            text_anchor = excerpt.range.start.clone();
+                            text_anchor = excerpt.range.context.start.clone();
                         }
                         Anchor {
                             buffer_id: Some(excerpt.buffer_id),
@@ -2106,7 +2149,7 @@ impl MultiBufferSnapshot {
                 bias = Bias::Right;
             }
 
-            let buffer_start = excerpt.range.start.to_offset(&excerpt.buffer);
+            let buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
             let text_anchor =
                 excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
             Anchor {
@@ -2239,8 +2282,11 @@ impl MultiBufferSnapshot {
                     return None;
                 }
 
-                let excerpt_buffer_start =
-                    start_excerpt.range.start.to_offset(&start_excerpt.buffer);
+                let excerpt_buffer_start = start_excerpt
+                    .range
+                    .context
+                    .start
+                    .to_offset(&start_excerpt.buffer);
                 let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
 
                 let start_in_buffer =
@@ -2340,8 +2386,11 @@ impl MultiBufferSnapshot {
                     return None;
                 }
 
-                let excerpt_buffer_start =
-                    start_excerpt.range.start.to_offset(&start_excerpt.buffer);
+                let excerpt_buffer_start = start_excerpt
+                    .range
+                    .context
+                    .start
+                    .to_offset(&start_excerpt.buffer);
                 let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
 
                 let start_in_buffer =
@@ -2427,7 +2476,8 @@ impl MultiBufferSnapshot {
         cursor
             .take_while(move |excerpt| excerpt.id <= range.end.excerpt_id)
             .flat_map(move |excerpt| {
-                let mut query_range = excerpt.range.start.clone()..excerpt.range.end.clone();
+                let mut query_range =
+                    excerpt.range.context.start.clone()..excerpt.range.context.end.clone();
                 if excerpt.id == range.start.excerpt_id {
                     query_range.start = range.start.text_anchor.clone();
                 }
@@ -2619,13 +2669,14 @@ impl Excerpt {
         id: ExcerptId,
         buffer_id: usize,
         buffer: BufferSnapshot,
-        range: Range<text::Anchor>,
+        range: ExcerptRange<text::Anchor>,
         has_trailing_newline: bool,
     ) -> Self {
         Excerpt {
             id,
-            max_buffer_row: range.end.to_point(&buffer).row,
-            text_summary: buffer.text_summary_for_range::<TextSummary, _>(range.to_offset(&buffer)),
+            max_buffer_row: range.context.end.to_point(&buffer).row,
+            text_summary: buffer
+                .text_summary_for_range::<TextSummary, _>(range.context.to_offset(&buffer)),
             buffer_id,
             buffer,
             range,
@@ -2638,7 +2689,7 @@ impl Excerpt {
         range: Range<usize>,
         language_aware: bool,
     ) -> ExcerptChunks<'a> {
-        let content_start = self.range.start.to_offset(&self.buffer);
+        let content_start = self.range.context.start.to_offset(&self.buffer);
         let chunks_start = content_start + range.start;
         let chunks_end = content_start + cmp::min(range.end, self.text_summary.bytes);
 
@@ -2660,7 +2711,7 @@ impl Excerpt {
     }
 
     fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
-        let content_start = self.range.start.to_offset(&self.buffer);
+        let content_start = self.range.context.start.to_offset(&self.buffer);
         let bytes_start = content_start + range.start;
         let bytes_end = content_start + cmp::min(range.end, self.text_summary.bytes);
         let footer_height = if self.has_trailing_newline
@@ -2680,10 +2731,16 @@ impl Excerpt {
     }
 
     fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
-        if text_anchor.cmp(&self.range.start, &self.buffer).is_lt() {
-            self.range.start.clone()
-        } else if text_anchor.cmp(&self.range.end, &self.buffer).is_gt() {
-            self.range.end.clone()
+        if text_anchor
+            .cmp(&self.range.context.start, &self.buffer)
+            .is_lt()
+        {
+            self.range.context.start.clone()
+        } else if text_anchor
+            .cmp(&self.range.context.end, &self.buffer)
+            .is_gt()
+        {
+            self.range.context.end.clone()
         } else {
             text_anchor
         }
@@ -2693,11 +2750,13 @@ impl Excerpt {
         Some(self.buffer_id) == anchor.buffer_id
             && self
                 .range
+                .context
                 .start
                 .cmp(&anchor.text_anchor, &self.buffer)
                 .is_le()
             && self
                 .range
+                .context
                 .end
                 .cmp(&anchor.text_anchor, &self.buffer)
                 .is_ge()
@@ -2802,7 +2861,7 @@ impl<'a> MultiBufferRows<'a> {
 
         if let Some(excerpt) = self.excerpts.item() {
             let overshoot = row - self.excerpts.start().row;
-            let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer).row;
+            let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
             self.buffer_row_range.start = excerpt_start + overshoot;
             self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
         }
@@ -2822,7 +2881,7 @@ impl<'a> Iterator for MultiBufferRows<'a> {
             self.excerpts.item()?;
             self.excerpts.next(&());
             let excerpt = self.excerpts.item()?;
-            self.buffer_row_range.start = excerpt.range.start.to_point(&excerpt.buffer).row;
+            self.buffer_row_range.start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
             self.buffer_row_range.end =
                 self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
         }
@@ -3079,7 +3138,13 @@ mod tests {
 
         let subscription = multibuffer.update(cx, |multibuffer, cx| {
             let subscription = multibuffer.subscribe();
-            multibuffer.push_excerpts(buffer_1.clone(), [Point::new(1, 2)..Point::new(2, 5)], cx);
+            multibuffer.push_excerpts(
+                buffer_1.clone(),
+                [ExcerptRange {
+                    context: Point::new(1, 2)..Point::new(2, 5),
+                }],
+                cx,
+            );
             assert_eq!(
                 subscription.consume().into_inner(),
                 [Edit {
@@ -3088,8 +3153,20 @@ mod tests {
                 }]
             );
 
-            multibuffer.push_excerpts(buffer_1.clone(), [Point::new(3, 3)..Point::new(4, 4)], cx);
-            multibuffer.push_excerpts(buffer_2.clone(), [Point::new(3, 1)..Point::new(3, 3)], cx);
+            multibuffer.push_excerpts(
+                buffer_1.clone(),
+                [ExcerptRange {
+                    context: Point::new(3, 3)..Point::new(4, 4),
+                }],
+                cx,
+            );
+            multibuffer.push_excerpts(
+                buffer_2.clone(),
+                [ExcerptRange {
+                    context: Point::new(3, 1)..Point::new(3, 3),
+                }],
+                cx,
+            );
             assert_eq!(
                 subscription.consume().into_inner(),
                 [Edit {
@@ -3253,7 +3330,7 @@ mod tests {
                         boundary.row,
                         boundary
                             .buffer
-                            .text_for_range(boundary.range)
+                            .text_for_range(boundary.range.context)
                             .collect::<String>(),
                         boundary.starts_new_buffer,
                     )
@@ -3334,8 +3411,8 @@ mod tests {
         let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
         let multibuffer = cx.add_model(|cx| {
             let mut multibuffer = MultiBuffer::new(0);
-            multibuffer.push_excerpts(buffer_1.clone(), [0..4], cx);
-            multibuffer.push_excerpts(buffer_2.clone(), [0..5], cx);
+            multibuffer.push_excerpts(buffer_1.clone(), [ExcerptRange { context: 0..4 }], cx);
+            multibuffer.push_excerpts(buffer_2.clone(), [ExcerptRange { context: 0..5 }], cx);
             multibuffer
         });
         let old_snapshot = multibuffer.read(cx).snapshot(cx);
@@ -3385,7 +3462,7 @@ mod tests {
         buffer_1.update(cx, |buffer, cx| buffer.edit([(4..4, "123")], cx));
         let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| {
             multibuffer
-                .push_excerpts(buffer_1.clone(), [0..7], cx)
+                .push_excerpts(buffer_1.clone(), [ExcerptRange { context: 0..7 }], cx)
                 .pop()
                 .unwrap()
         });
@@ -3397,7 +3474,15 @@ mod tests {
         let (excerpt_id_2, excerpt_id_3) = multibuffer.update(cx, |multibuffer, cx| {
             multibuffer.remove_excerpts([&excerpt_id_1], cx);
             let mut ids = multibuffer
-                .push_excerpts(buffer_2.clone(), [0..4, 6..10, 12..16], cx)
+                .push_excerpts(
+                    buffer_2.clone(),
+                    [
+                        ExcerptRange { context: 0..4 },
+                        ExcerptRange { context: 6..10 },
+                        ExcerptRange { context: 12..16 },
+                    ],
+                    cx,
+                )
                 .into_iter();
             (ids.next().unwrap(), ids.next().unwrap())
         });
@@ -3437,7 +3522,12 @@ mod tests {
         let excerpt_id_5 = multibuffer.update(cx, |multibuffer, cx| {
             multibuffer.remove_excerpts([&excerpt_id_3], cx);
             multibuffer
-                .insert_excerpts_after(&excerpt_id_3, buffer_2.clone(), [5..8], cx)
+                .insert_excerpts_after(
+                    &excerpt_id_3,
+                    buffer_2.clone(),
+                    [ExcerptRange { context: 5..8 }],
+                    cx,
+                )
                 .pop()
                 .unwrap()
         });
@@ -3584,7 +3674,9 @@ mod tests {
                             .insert_excerpts_after(
                                 &prev_excerpt_id,
                                 buffer_handle.clone(),
-                                [start_ix..end_ix],
+                                [ExcerptRange {
+                                    context: start_ix..end_ix,
+                                }],
                                 cx,
                             )
                             .pop()
@@ -3893,8 +3985,20 @@ mod tests {
         let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
         let group_interval = multibuffer.read(cx).history.group_interval;
         multibuffer.update(cx, |multibuffer, cx| {
-            multibuffer.push_excerpts(buffer_1.clone(), [0..buffer_1.read(cx).len()], cx);
-            multibuffer.push_excerpts(buffer_2.clone(), [0..buffer_2.read(cx).len()], cx);
+            multibuffer.push_excerpts(
+                buffer_1.clone(),
+                [ExcerptRange {
+                    context: 0..buffer_1.read(cx).len(),
+                }],
+                cx,
+            );
+            multibuffer.push_excerpts(
+                buffer_2.clone(),
+                [ExcerptRange {
+                    context: 0..buffer_2.read(cx).len(),
+                }],
+                cx,
+            );
         });
 
         let mut now = Instant::now();

crates/search/src/buffer_search.rs 🔗

@@ -485,7 +485,7 @@ impl BufferSearchBar {
                         );
                     } else {
                         for excerpt in buffer.excerpt_boundaries_in_range(0..buffer.len()) {
-                            let excerpt_range = excerpt.range.to_offset(&excerpt.buffer);
+                            let excerpt_range = excerpt.range.context.to_offset(&excerpt.buffer);
                             let rope = excerpt.buffer.as_rope().slice(excerpt_range.clone());
                             ranges.extend(query.search(&rope).await.into_iter().map(|range| {
                                 let start = excerpt