Insert empty isomorphic transforms on empty lines

Nathan Sobo , Max Brunsfeld , and Antonio Scandurra created

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
Co-Authored-By: Antonio Scandurra <me@as-cii.com>

Change summary

crates/editor/src/display_map/block_map.rs | 41 +++++++++++++++++++----
1 file changed, 33 insertions(+), 8 deletions(-)

Detailed changes

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

@@ -104,16 +104,14 @@ pub struct BufferRows<'a> {
 
 impl BlockMap {
     pub fn new(buffer: ModelHandle<Buffer>, wrap_snapshot: WrapSnapshot) -> Self {
-        let mut transforms = SumTree::new();
-        let lines = wrap_snapshot.text_summary().lines;
-        if !lines.is_zero() {
-            transforms.push(Transform::isomorphic(lines), &());
-        }
         Self {
             buffer,
             next_block_id: AtomicUsize::new(0),
             blocks: Vec::new(),
-            transforms: Mutex::new(transforms),
+            transforms: Mutex::new(SumTree::from_item(
+                Transform::isomorphic(wrap_snapshot.text_summary().lines),
+                &(),
+            )),
             wrap_snapshot: Mutex::new(wrap_snapshot),
         }
     }
@@ -242,8 +240,13 @@ impl BlockMap {
                         Point::new(block_row, wrap_snapshot.line_len(block_row))
                     }
                 };
+
                 let extent_before_block = block_insertion_point - new_transforms.summary().input;
                 push_isomorphic(&mut new_transforms, extent_before_block);
+                if block.disposition == BlockDisposition::Below {
+                    ensure_last_is_isomorphic_or_below_block(&mut new_transforms);
+                }
+
                 new_transforms.push(Transform::block(block.clone()), &());
             }
 
@@ -260,6 +263,7 @@ impl BlockMap {
         }
 
         new_transforms.push_tree(cursor.suffix(&()), &());
+        ensure_last_is_isomorphic_or_below_block(&mut new_transforms);
         debug_assert_eq!(new_transforms.summary().input, wrap_snapshot.max_point().0);
 
         drop(cursor);
@@ -267,6 +271,17 @@ impl BlockMap {
     }
 }
 
+fn ensure_last_is_isomorphic_or_below_block(tree: &mut SumTree<Transform>) {
+    if tree.last().map_or(true, |transform| {
+        transform
+            .block
+            .as_ref()
+            .map_or(false, |block| block.disposition.is_above())
+    }) {
+        tree.push(Transform::isomorphic(Point::zero()), &())
+    }
+}
+
 fn push_isomorphic(tree: &mut SumTree<Transform>, extent: Point) {
     if extent.is_zero() {
         return;
@@ -690,6 +705,7 @@ impl<'a> Iterator for BufferRows<'a> {
         }
 
         let (buffer_row, _) = self.input_buffer_row.unwrap();
+
         log::info!(
             "Called next. Output row: {}, Input row: {}, Buffer row: {}",
             self.output_row,
@@ -771,6 +787,10 @@ impl BlockDisposition {
     fn is_above(&self) -> bool {
         matches!(self, BlockDisposition::Above)
     }
+
+    fn is_below(&self) -> bool {
+        matches!(self, BlockDisposition::Below)
+    }
 }
 
 // Count the number of bytes prior to a target point. If the string doesn't contain the target
@@ -1157,8 +1177,7 @@ mod tests {
                     }
                 }
 
-                let soft_wrapped =
-                    wraps_snapshot.to_tab_point(WrapPoint::new(row, 0)).column() != 0;
+                let soft_wrapped = wraps_snapshot.to_tab_point(WrapPoint::new(row, 0)).column() > 0;
                 expected_buffer_rows.push((buffer_row, false));
                 expected_text.push_str(input_line);
 
@@ -1178,6 +1197,12 @@ mod tests {
             }
 
             assert_eq!(blocks_snapshot.text(), expected_text);
+            for row in 0..=blocks_snapshot.wrap_snapshot.max_point().row() {
+                let wrap_point = WrapPoint::new(row, 0);
+                let block_point = blocks_snapshot.to_block_point(wrap_point);
+                assert_eq!(blocks_snapshot.to_wrap_point(block_point), wrap_point);
+            }
+
             assert_eq!(
                 blocks_snapshot.buffer_rows(0).collect::<Vec<_>>(),
                 expected_buffer_rows