Add `fold_map::Snapshot::text_summary_for_range`

Antonio Scandurra created

Change summary

zed/src/editor/buffer.rs               |  6 ++
zed/src/editor/display_map/fold_map.rs | 64 ++++++++++++++++++++++++++++
2 files changed, 69 insertions(+), 1 deletion(-)

Detailed changes

zed/src/editor/buffer.rs 🔗

@@ -1992,7 +1992,11 @@ impl Snapshot {
         }
     }
 
-    pub fn text_summary_for_range(&self, range: Range<usize>) -> TextSummary {
+    pub fn text_summary_for_range<T>(&self, range: Range<T>) -> TextSummary
+    where
+        T: ToOffset,
+    {
+        let range = range.start.to_offset(self.content())..range.end.to_offset(self.content());
         self.content().text_summary_for_range(range)
     }
 

zed/src/editor/display_map/fold_map.rs 🔗

@@ -405,6 +405,47 @@ impl Snapshot {
         self.transforms.summary().display
     }
 
+    pub fn text_summary_for_range(&self, range: Range<DisplayPoint>) -> TextSummary {
+        let mut summary = TextSummary::default();
+
+        let mut cursor = self.transforms.cursor::<DisplayPoint, Point>();
+        cursor.seek(&range.start, Bias::Right, &());
+        if let Some(transform) = cursor.item() {
+            let start_in_transform = range.start.0 - cursor.seek_start().0;
+            let end_in_transform =
+                cmp::min(range.end, cursor.seek_end(&())).0 - cursor.seek_start().0;
+            if let Some(display_text) = transform.display_text {
+                summary = TextSummary::from(
+                    &display_text
+                        [start_in_transform.column as usize..end_in_transform.column as usize],
+                );
+            } else {
+                let buffer_start = *cursor.sum_start() + start_in_transform;
+                let buffer_end = *cursor.sum_start() + end_in_transform;
+                summary = self.buffer.text_summary_for_range(buffer_start..buffer_end);
+            }
+        }
+
+        if range.end > cursor.seek_end(&()) {
+            cursor.next(&());
+            summary += &cursor
+                .summary::<TransformSummary>(&range.end, Bias::Right, &())
+                .display;
+            if let Some(transform) = cursor.item() {
+                let end_in_transform = range.end.0 - cursor.seek_start().0;
+                if let Some(display_text) = transform.display_text {
+                    summary += TextSummary::from(&display_text[..end_in_transform.column as usize]);
+                } else {
+                    let buffer_start = *cursor.sum_start();
+                    let buffer_end = *cursor.sum_start() + end_in_transform;
+                    summary += self.buffer.text_summary_for_range(buffer_start..buffer_end);
+                }
+            }
+        }
+
+        summary
+    }
+
     pub fn len(&self) -> usize {
         self.transforms.summary().display.bytes
     }
@@ -1023,6 +1064,7 @@ mod tests {
     use super::*;
     use crate::editor::buffer::ToPoint;
     use crate::test::sample_text;
+    use std::mem;
 
     #[gpui::test]
     fn test_basic_folds(cx: &mut gpui::MutableAppContext) {
@@ -1406,6 +1448,28 @@ mod tests {
                     );
                 }
 
+                let text = snapshot.text();
+                for _ in 0..5 {
+                    let start_row = rng.gen_range(0..=snapshot.max_point().row());
+                    let start_column = rng.gen_range(0..=snapshot.line_len(start_row));
+                    let end_row = rng.gen_range(0..=snapshot.max_point().row());
+                    let end_column = rng.gen_range(0..=snapshot.line_len(end_row));
+                    let mut start =
+                        snapshot.clip_point(DisplayPoint::new(start_row, start_column), Bias::Left);
+                    let mut end =
+                        snapshot.clip_point(DisplayPoint::new(end_row, end_column), Bias::Right);
+                    if start > end {
+                        mem::swap(&mut start, &mut end);
+                    }
+
+                    let lines = start..end;
+                    let bytes = snapshot.to_display_offset(start)..snapshot.to_display_offset(end);
+                    assert_eq!(
+                        snapshot.text_summary_for_range(lines),
+                        TextSummary::from(&text[bytes.start.0..bytes.end.0])
+                    )
+                }
+
                 let mut text = initial_snapshot.text();
                 for (snapshot, edits) in snapshot_edits.drain(..) {
                     let new_text = snapshot.text();