Make unfolding inclusive

Nathan Sobo and Antonio Scandurra created

If the range *touches* the fold, we unfold. This was needed to fix the behavior for unfolding at the current selection position. Previously, there was some kind of translation issue that was allowing us to accidentally work the way we wanted without this.

Co-Authored-By: Antonio Scandurra <me@as-cii.com>

Change summary

zed/src/editor.rs                      | 17 +++++++----------
zed/src/editor/display_map/fold_map.rs | 15 +++++++++++----
2 files changed, 18 insertions(+), 14 deletions(-)

Detailed changes

zed/src/editor.rs 🔗

@@ -1020,11 +1020,8 @@ impl Editor {
             // Cut the text from the selected rows and paste it at the start of the previous line.
             if display_rows.start != 0 {
                 let start = Point::new(buffer_rows.start, 0).to_offset(buffer);
-                let end = Point::new(
-                    buffer_rows.end - 1,
-                    buffer.line_len(buffer_rows.end - 1),
-                )
-                .to_offset(buffer);
+                let end = Point::new(buffer_rows.end - 1, buffer.line_len(buffer_rows.end - 1))
+                    .to_offset(buffer);
 
                 let prev_row_display_start = DisplayPoint::new(display_rows.start - 1, 0);
                 let prev_row_buffer_start = display_map.prev_row_boundary(prev_row_display_start).1;
@@ -3842,25 +3839,25 @@ mod tests {
 
         view.update(cx, |view, cx| {
             view.split_selection_into_lines(&(), cx);
-            assert_eq!(view.text(cx), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i");
+            assert_eq!(view.text(cx), "aaaaa\nbbbbb\nccc…eeee\nfffff\nggggg\n…i");
             assert_eq!(
                 view.selection_ranges(cx),
                 [
                     DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
                     DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
-                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
-                    DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4)
+                    DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
+                    DisplayPoint::new(5, 4)..DisplayPoint::new(5, 4)
                 ]
             );
         });
 
         view.update(cx, |view, cx| {
-            view.select_display_ranges(&[DisplayPoint::new(4, 0)..DisplayPoint::new(0, 1)], cx)
+            view.select_display_ranges(&[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 1)], cx)
                 .unwrap();
             view.split_selection_into_lines(&(), cx);
             assert_eq!(
                 view.text(cx),
-                "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\n…i"
+                "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\nhhhhh\niiiii"
             );
             assert_eq!(
                 view.selection_ranges(cx),

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

@@ -154,7 +154,7 @@ impl<'a> FoldMapWriter<'a> {
         let buffer = self.0.buffer.read(cx).snapshot();
         for range in ranges.into_iter() {
             // Remove intersecting folds and add their ranges to edits that are passed to apply_edits.
-            let mut folds_cursor = intersecting_folds(&buffer, &self.0.folds, range);
+            let mut folds_cursor = intersecting_folds(&buffer, &self.0.folds, range, true);
             while let Some(fold) = folds_cursor.item() {
                 let offset_range = fold.0.start.to_offset(&buffer)..fold.0.end.to_offset(&buffer);
                 edits.push(buffer::Edit {
@@ -590,7 +590,7 @@ impl Snapshot {
     where
         T: ToOffset,
     {
-        let mut folds = intersecting_folds(&self.buffer_snapshot, &self.folds, range);
+        let mut folds = intersecting_folds(&self.buffer_snapshot, &self.folds, range, false);
         iter::from_fn(move || {
             let item = folds.item().map(|f| &f.0);
             folds.next(&self.buffer_snapshot);
@@ -722,6 +722,7 @@ fn intersecting_folds<'a, T>(
     buffer: &'a buffer::Snapshot,
     folds: &'a SumTree<Fold>,
     range: Range<T>,
+    inclusive: bool,
 ) -> FilterCursor<'a, impl 'a + Fn(&FoldSummary) -> bool, Fold, usize>
 where
     T: ToOffset,
@@ -730,8 +731,14 @@ where
     let end = buffer.anchor_after(range.end.to_offset(buffer));
     folds.filter::<_, usize>(
         move |summary| {
-            start.cmp(&summary.max_end, buffer).unwrap() == Ordering::Less
-                && end.cmp(&summary.min_start, buffer).unwrap() == Ordering::Greater
+            let start_cmp = start.cmp(&summary.max_end, buffer).unwrap();
+            let end_cmp = end.cmp(&summary.min_start, buffer).unwrap();
+
+            if inclusive {
+                start_cmp <= Ordering::Equal && end_cmp >= Ordering::Equal
+            } else {
+                start_cmp == Ordering::Less && end_cmp == Ordering::Greater
+            }
         },
         buffer,
     )