multi_buffer: Cleanup min/max excerpt id clipping

Lukas Wirth created

Change summary

crates/multi_buffer/src/multi_buffer.rs | 68 +++++++++++++-------------
1 file changed, 35 insertions(+), 33 deletions(-)

Detailed changes

crates/multi_buffer/src/multi_buffer.rs 🔗

@@ -1306,8 +1306,10 @@ impl MultiBuffer {
         let snapshot = self.read(cx);
         let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>(());
         for selection in selections {
-            let start_locator = snapshot.excerpt_locator_for_id(selection.start.excerpt_id);
-            let end_locator = snapshot.excerpt_locator_for_id(selection.end.excerpt_id);
+            let start_id = snapshot.clip_excerpt_id(selection.start.excerpt_id);
+            let start_locator = snapshot.excerpt_locator_for_id(start_id);
+            let end_id = snapshot.clip_excerpt_id(selection.end.excerpt_id);
+            let end_locator = snapshot.excerpt_locator_for_id(end_id);
 
             cursor.seek(&Some(start_locator), Bias::Left);
             while let Some(excerpt) = cursor.item()
@@ -1315,10 +1317,10 @@ impl MultiBuffer {
             {
                 let mut start = excerpt.range.context.start;
                 let mut end = excerpt.range.context.end;
-                if excerpt.id == selection.start.excerpt_id {
+                if excerpt.id == start_id {
                     start = selection.start.text_anchor;
                 }
-                if excerpt.id == selection.end.excerpt_id {
+                if excerpt.id == end_id {
                     end = selection.end.text_anchor;
                 }
                 selections_by_buffer
@@ -1501,13 +1503,14 @@ impl MultiBuffer {
         direction: ExpandExcerptDirection,
         cx: &mut Context<Self>,
     ) {
+        let snapshot = self.snapshot(cx);
         let grouped = ids
             .into_iter()
+            .map(|id| snapshot.clip_excerpt_id(id))
             .chunk_by(|id| self.paths_by_excerpt.get(id).cloned())
             .into_iter()
             .flat_map(|(k, v)| Some((k?, v.into_iter().collect::<Vec<_>>())))
             .collect::<Vec<_>>();
-        let snapshot = self.snapshot(cx);
 
         for (path, ids) in grouped.into_iter() {
             let Some(excerpt_ids) = self.excerpts_by_path.get(&path) else {
@@ -1951,7 +1954,7 @@ impl MultiBuffer {
         });
 
         let mut snapshot = self.snapshot.borrow_mut();
-
+        let prev_excerpt_id = snapshot.clip_excerpt_id(prev_excerpt_id);
         let mut prev_locator = snapshot.excerpt_locator_for_id(prev_excerpt_id).clone();
         let mut new_excerpt_ids = mem::take(&mut snapshot.excerpt_ids);
         let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>(());
@@ -4911,16 +4914,14 @@ impl MultiBufferSnapshot {
         let mut cursor = self
             .excerpts
             .cursor::<Dimensions<Option<&Locator>, ExcerptOffset>>(());
-        let locator = self.excerpt_locator_for_id(anchor.excerpt_id);
+        let excerpt_id = self.clip_excerpt_id(anchor.excerpt_id);
+        let locator = self.excerpt_locator_for_id(excerpt_id);
 
         cursor.seek(&Some(locator), Bias::Left);
-        if cursor.item().is_none() && anchor.excerpt_id == ExcerptId::max() {
-            cursor.prev();
-        }
 
         let mut position = cursor.start().1;
         if let Some(excerpt) = cursor.item()
-            && (excerpt.id == anchor.excerpt_id || anchor.excerpt_id == ExcerptId::max())
+            && excerpt.id == excerpt_id
         {
             let excerpt_buffer_start = excerpt
                 .buffer
@@ -4958,21 +4959,19 @@ impl MultiBufferSnapshot {
 
         let mut summaries = Vec::new();
         while let Some(anchor) = anchors.peek() {
-            let excerpt_id = self.latest_excerpt_id(anchor.excerpt_id);
+            let excerpt_id = self.clip_excerpt_id(anchor.excerpt_id);
+            let excerpt_id = self.latest_excerpt_id(excerpt_id);
 
             let excerpt_anchors = anchors.peeking_take_while(|anchor| {
-                self.latest_excerpt_id(anchor.excerpt_id) == excerpt_id
+                self.latest_excerpt_id(self.clip_excerpt_id(anchor.excerpt_id)) == excerpt_id
             });
 
             let locator = self.excerpt_locator_for_id(excerpt_id);
             cursor.seek_forward(locator, Bias::Left);
-            if cursor.item().is_none() && excerpt_id == ExcerptId::max() {
-                cursor.prev();
-            }
 
             let excerpt_start_position = D::from_text_summary(&cursor.start().text);
             if let Some(excerpt) = cursor.item() {
-                if excerpt.id != excerpt_id && excerpt_id != ExcerptId::max() {
+                if excerpt.id != excerpt_id {
                     let position = self.resolve_summary_for_anchor(
                         &Anchor::min(),
                         excerpt_start_position,
@@ -6197,14 +6196,9 @@ impl MultiBufferSnapshot {
         let mut cursor = self
             .excerpts
             .cursor::<Dimensions<Option<&Locator>, ExcerptDimension<Point>>>(());
+        let excerpt_id = self.clip_excerpt_id(excerpt_id);
         let locator = self.excerpt_locator_for_id(excerpt_id);
-        let mut sought_exact = cursor.seek(&Some(locator), Bias::Left);
-        if cursor.item().is_none() && excerpt_id == ExcerptId::max() {
-            sought_exact = true;
-            cursor.prev();
-        } else if excerpt_id == ExcerptId::min() {
-            sought_exact = true;
-        }
+        let sought_exact = cursor.seek(&Some(locator), Bias::Left);
         if sought_exact {
             let start = cursor.start().1.clone();
             let end = cursor.end().1;
@@ -6225,17 +6219,10 @@ impl MultiBufferSnapshot {
 
     fn excerpt(&self, excerpt_id: ExcerptId) -> Option<&Excerpt> {
         let mut cursor = self.excerpts.cursor::<Option<&Locator>>(());
+        let excerpt_id = self.clip_excerpt_id(excerpt_id);
         let locator = self.excerpt_locator_for_id(excerpt_id);
         cursor.seek(&Some(locator), Bias::Left);
-        if let Some(excerpt) = cursor.item()
-            && excerpt.id == excerpt_id
-        {
-            return Some(excerpt);
-        } else if cursor.item().is_none() && excerpt_id == ExcerptId::max() {
-            cursor.prev();
-            return cursor.item();
-        }
-        None
+        cursor.item().filter(|excerpt| excerpt.id == excerpt_id)
     }
 
     /// Returns the excerpt containing range and its offset start within the multibuffer or none if `range` spans multiple excerpts
@@ -6445,6 +6432,21 @@ impl MultiBufferSnapshot {
             prev_transform = Some(item);
         }
     }
+
+    fn clip_excerpt_id(&self, excerpt_id: ExcerptId) -> ExcerptId {
+        // todo, are first and last always valid?
+        if excerpt_id == ExcerptId::min() {
+            self.excerpts
+                .first()
+                .map_or(excerpt_id, |excerpt| excerpt.id)
+        } else if excerpt_id == ExcerptId::max() {
+            self.excerpts
+                .last()
+                .map_or(excerpt_id, |excerpt| excerpt.id)
+        } else {
+            excerpt_id
+        }
+    }
 }
 
 impl<'a, D> MultiBufferCursor<'a, D>