Start on implementing filtering support for `Cursor::prev`

Antonio Scandurra created

Change summary

crates/editor/src/multi_buffer.rs |   2 
crates/gpui/src/elements/list.rs  |   6 
crates/sum_tree/src/cursor.rs     | 138 +++++++++++++-------------------
crates/sum_tree/src/sum_tree.rs   |   6 
crates/text/src/rope.rs           |   2 
5 files changed, 64 insertions(+), 90 deletions(-)

Detailed changes

crates/editor/src/multi_buffer.rs 🔗

@@ -1700,7 +1700,7 @@ impl MultiBufferSnapshot {
     }
 
     pub fn text_summary(&self) -> TextSummary {
-        self.excerpts.summary().text
+        self.excerpts.summary().text.clone()
     }
 
     pub fn text_summary_for_range<'a, D, O>(&'a self, range: Range<O>) -> D

crates/gpui/src/elements/list.rs 🔗

@@ -614,7 +614,7 @@ mod tests {
         let (size, _) = list.layout(constraint, &mut presenter.build_layout_context(false, cx));
         assert_eq!(size, vec2f(100., 40.));
         assert_eq!(
-            state.0.borrow().items.summary(),
+            state.0.borrow().items.summary().clone(),
             ListItemSummary {
                 count: 3,
                 rendered_count: 3,
@@ -649,7 +649,7 @@ mod tests {
         state.splice(1..2, 2);
         state.splice(4..4, 1);
         assert_eq!(
-            state.0.borrow().items.summary(),
+            state.0.borrow().items.summary().clone(),
             ListItemSummary {
                 count: 5,
                 rendered_count: 2,
@@ -662,7 +662,7 @@ mod tests {
             list.layout(constraint, &mut presenter.build_layout_context(false, cx));
         assert_eq!(size, vec2f(100., 40.));
         assert_eq!(
-            state.0.borrow().items.summary(),
+            state.0.borrow().items.summary().clone(),
             ListItemSummary {
                 count: 5,
                 rendered_count: 5,

crates/sum_tree/src/cursor.rs 🔗

@@ -134,55 +134,73 @@ where
     }
 
     pub fn prev(&mut self, cx: &<T::Summary as Summary>::Context) {
-        assert!(self.did_seek, "Must seek before calling this method");
+        self.prev_internal(|_| true, cx)
+    }
 
+    fn prev_internal<F>(&mut self, mut filter_node: F, cx: &<T::Summary as Summary>::Context)
+    where
+        F: FnMut(&T::Summary) -> bool,
+    {
         if self.at_end {
             self.position = D::default();
-            self.descend_to_last_item(self.tree, cx);
             self.at_end = self.tree.is_empty();
+            if !self.tree.is_empty() {
+                self.stack.push(StackEntry {
+                    tree: self.tree,
+                    index: self.tree.0.child_summaries().len(),
+                    position: D::from_summary(self.tree.summary(), cx),
+                });
+            }
         } else {
-            while let Some(entry) = self.stack.pop() {
-                if entry.index > 0 {
-                    let new_index = entry.index - 1;
+            assert!(self.did_seek, "Must seek before calling this method");
+        }
 
-                    if let Some(StackEntry { position, .. }) = self.stack.last() {
-                        self.position = position.clone();
-                    } else {
-                        self.position = D::default();
-                    }
+        let mut descending = false;
+        while !self.stack.is_empty() {
+            if let Some(StackEntry { position, .. }) = self.stack.iter().rev().skip(1).next() {
+                self.position = position.clone();
+            } else {
+                self.position = D::default();
+            }
 
-                    match entry.tree.0.as_ref() {
-                        Node::Internal {
-                            child_trees,
-                            child_summaries,
-                            ..
-                        } => {
-                            for summary in &child_summaries[0..new_index] {
-                                self.position.add_summary(summary, cx);
-                            }
-                            self.stack.push(StackEntry {
-                                tree: entry.tree,
-                                index: new_index,
-                                position: self.position.clone(),
-                            });
-                            self.descend_to_last_item(&child_trees[new_index], cx);
-                        }
-                        Node::Leaf { item_summaries, .. } => {
-                            for item_summary in &item_summaries[0..new_index] {
-                                self.position.add_summary(item_summary, cx);
-                            }
-                            self.stack.push(StackEntry {
-                                tree: entry.tree,
-                                index: new_index,
-                                position: self.position.clone(),
-                            });
-                        }
-                    }
+            let mut entry = self.stack.last_mut().unwrap();
+            if !descending {
+                if entry.index == 0 {
+                    self.stack.pop();
+                    continue;
+                } else {
+                    entry.index -= 1;
+                }
+            }
 
-                    break;
+            for summary in &entry.tree.0.child_summaries()[..entry.index] {
+                self.position.add_summary(summary, cx);
+            }
+            entry.position = self.position.clone();
+
+            descending = filter_node(&entry.tree.0.child_summaries()[entry.index]);
+            match entry.tree.0.as_ref() {
+                Node::Internal { child_trees, .. } => {
+                    if descending {
+                        let tree = &child_trees[entry.index];
+                        self.stack.push(StackEntry {
+                            position: D::default(),
+                            tree,
+                            index: tree.0.child_summaries().len() - 1,
+                        })
+                    }
+                }
+                Node::Leaf { .. } => {
+                    if descending {
+                        break;
+                    }
                 }
             }
         }
+
+        if self.stack.is_empty() {
+            self.position = D::default();
+        }
     }
 
     pub fn next(&mut self, cx: &<T::Summary as Summary>::Context) {
@@ -274,50 +292,6 @@ where
         self.at_end = self.stack.is_empty();
         debug_assert!(self.stack.is_empty() || self.stack.last().unwrap().tree.0.is_leaf());
     }
-
-    fn descend_to_last_item(
-        &mut self,
-        mut subtree: &'a SumTree<T>,
-        cx: &<T::Summary as Summary>::Context,
-    ) {
-        self.did_seek = true;
-        if subtree.is_empty() {
-            return;
-        }
-
-        loop {
-            match subtree.0.as_ref() {
-                Node::Internal {
-                    child_trees,
-                    child_summaries,
-                    ..
-                } => {
-                    for summary in &child_summaries[0..child_summaries.len() - 1] {
-                        self.position.add_summary(summary, cx);
-                    }
-
-                    self.stack.push(StackEntry {
-                        tree: subtree,
-                        index: child_trees.len() - 1,
-                        position: self.position.clone(),
-                    });
-                    subtree = child_trees.last().unwrap();
-                }
-                Node::Leaf { item_summaries, .. } => {
-                    let last_index = item_summaries.len() - 1;
-                    for item_summary in &item_summaries[0..last_index] {
-                        self.position.add_summary(item_summary, cx);
-                    }
-                    self.stack.push(StackEntry {
-                        tree: subtree,
-                        index: last_index,
-                        position: self.position.clone(),
-                    });
-                    break;
-                }
-            }
-        }
-    }
 }
 
 impl<'a, T, D> Cursor<'a, T, D>

crates/sum_tree/src/sum_tree.rs 🔗

@@ -242,10 +242,10 @@ impl<T: Item> SumTree<T> {
         extent
     }
 
-    pub fn summary(&self) -> T::Summary {
+    pub fn summary(&self) -> &T::Summary {
         match self.0.as_ref() {
-            Node::Internal { summary, .. } => summary.clone(),
-            Node::Leaf { summary, .. } => summary.clone(),
+            Node::Internal { summary, .. } => summary,
+            Node::Leaf { summary, .. } => summary,
         }
     }
 

crates/text/src/rope.rs 🔗

@@ -115,7 +115,7 @@ impl Rope {
     }
 
     pub fn summary(&self) -> TextSummary {
-        self.chunks.summary()
+        self.chunks.summary().clone()
     }
 
     pub fn len(&self) -> usize {