diff --git a/crates/buffer/src/anchor.rs b/crates/buffer/src/anchor.rs index c8a7eaed24..442e69406e 100644 --- a/crates/buffer/src/anchor.rs +++ b/crates/buffer/src/anchor.rs @@ -31,26 +31,26 @@ pub struct AnchorRangeMap { pub struct AnchorRangeSet(pub(crate) AnchorRangeMap<()>); pub struct AnchorRangeMultimap { - entries: SumTree>, + pub(crate) entries: SumTree>, pub(crate) version: clock::Global, pub(crate) start_bias: Bias, pub(crate) end_bias: Bias, } #[derive(Clone)] -struct AnchorRangeMultimapEntry { - range: FullOffsetRange, - value: T, +pub(crate) struct AnchorRangeMultimapEntry { + pub(crate) range: FullOffsetRange, + pub(crate) value: T, } #[derive(Clone, Debug)] -struct FullOffsetRange { - start: usize, - end: usize, +pub(crate) struct FullOffsetRange { + pub(crate) start: usize, + pub(crate) end: usize, } #[derive(Clone, Debug)] -struct AnchorRangeMultimapSummary { +pub(crate) struct AnchorRangeMultimapSummary { start: usize, end: usize, min_start: usize, @@ -165,46 +165,61 @@ impl AnchorRangeSet { } impl AnchorRangeMultimap { - fn intersecting_point_ranges<'a, O: ToOffset>( + fn intersecting_point_ranges<'a>( &'a self, - range: Range, - content: impl Into>, + range: Range, + content: &'a Content<'a>, inclusive: bool, ) -> impl Iterator, &T)> + 'a { use super::ToPoint as _; - let content = content.into(); - let start = range.start.to_full_offset(&content, self.start_bias); - let end = range.end.to_full_offset(&content, self.end_bias); let mut cursor = self.entries.filter::<_, usize>( - move |summary: &AnchorRangeMultimapSummary| { - if inclusive { - start <= summary.max_end && end >= summary.min_start - } else { - start < summary.max_end && end > summary.min_start + { + let mut endpoint = Anchor { + full_offset: 0, + bias: Bias::Right, + version: self.version.clone(), + }; + move |summary: &AnchorRangeMultimapSummary| { + endpoint.full_offset = summary.max_end; + endpoint.bias = self.end_bias; + let start_cmp = range.start.cmp(&endpoint, content).unwrap(); + + endpoint.full_offset = summary.min_start; + endpoint.bias = self.start_bias; + let end_cmp = range.end.cmp(&endpoint, content).unwrap(); + + if inclusive { + start_cmp <= Ordering::Equal && end_cmp >= Ordering::Equal + } else { + start_cmp == Ordering::Less && end_cmp == Ordering::Greater + } } }, &(), ); - let mut anchor = Anchor { - full_offset: 0, - bias: Bias::Left, - version: self.version.clone(), - }; - std::iter::from_fn(move || { - if let Some(item) = cursor.item() { - let ix = *cursor.start(); - anchor.full_offset = item.range.start; - anchor.bias = self.start_bias; - let start = anchor.to_point(&content); - anchor.full_offset = item.range.end; - anchor.bias = self.end_bias; - let end = anchor.to_point(&content); - let value = &item.value; - cursor.next(&()); - Some((ix, start..end, value)) - } else { - None + + std::iter::from_fn({ + let mut endpoint = Anchor { + full_offset: 0, + bias: Bias::Left, + version: self.version.clone(), + }; + move || { + if let Some(item) = cursor.item() { + let ix = *cursor.start(); + endpoint.full_offset = item.range.start; + endpoint.bias = self.start_bias; + let start = endpoint.to_point(content); + endpoint.full_offset = item.range.end; + endpoint.bias = self.end_bias; + let end = endpoint.to_point(content); + let value = &item.value; + cursor.next(&()); + Some((ix, start..end, value)) + } else { + None + } } }) } diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index 7203e0b1d7..c037c38697 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -20,6 +20,7 @@ use rpc::proto; pub use selection::*; use std::{ cmp, + collections::{BTreeMap, BTreeSet}, convert::{TryFrom, TryInto}, iter::Iterator, ops::Range, @@ -315,7 +316,7 @@ impl UndoMap { } } -struct Edits<'a, F: Fn(&FragmentSummary) -> bool> { +struct Edits<'a, F: FnMut(&FragmentSummary) -> bool> { visible_text: &'a Rope, deleted_text: &'a Rope, cursor: Option>, @@ -1836,6 +1837,56 @@ impl<'a> Content<'a> { AnchorRangeSet(self.anchor_range_map(entries.into_iter().map(|range| (range, ())))) } + pub fn anchor_range_multimap( + &self, + start_bias: Bias, + end_bias: Bias, + entries: E, + ) -> AnchorRangeMultimap + where + T: Clone, + E: IntoIterator, T)>, + O: ToOffset, + { + let mut items = Vec::new(); + let mut endpoints = BTreeMap::new(); + for (ix, (range, value)) in entries.into_iter().enumerate() { + items.push(AnchorRangeMultimapEntry { + range: FullOffsetRange { start: 0, end: 0 }, + value, + }); + endpoints + .entry((range.start.to_offset(self), start_bias)) + .or_insert(Vec::new()) + .push((ix, true)); + endpoints + .entry((range.end.to_offset(self), end_bias)) + .or_insert(Vec::new()) + .push((ix, false)); + } + + let mut cursor = self.fragments.cursor::(); + for ((endpoint, bias), item_ixs) in endpoints { + cursor.seek_forward(&endpoint, bias, &None); + let full_offset = cursor.start().deleted + endpoint; + for (item_ix, is_start) in item_ixs { + if is_start { + items[item_ix].range.start = full_offset; + } else { + items[item_ix].range.end = full_offset; + } + } + } + items.sort_unstable_by_key(|i| (i.range.start, i.range.end)); + + AnchorRangeMultimap { + entries: SumTree::from_iter(items, &()), + version: self.version.clone(), + start_bias, + end_bias, + } + } + fn full_offset_for_anchor(&self, anchor: &Anchor) -> usize { let cx = Some(anchor.version.clone()); let mut cursor = self @@ -1917,7 +1968,7 @@ impl<'a> RopeBuilder<'a> { } } -impl<'a, F: Fn(&FragmentSummary) -> bool> Iterator for Edits<'a, F> { +impl<'a, F: FnMut(&FragmentSummary) -> bool> Iterator for Edits<'a, F> { type Item = Edit; fn next(&mut self) -> Option { diff --git a/crates/editor/src/display_map/fold_map.rs b/crates/editor/src/display_map/fold_map.rs index 73e032e7f3..7a230aa165 100644 --- a/crates/editor/src/display_map/fold_map.rs +++ b/crates/editor/src/display_map/fold_map.rs @@ -720,7 +720,7 @@ fn intersecting_folds<'a, T>( folds: &'a SumTree, range: Range, inclusive: bool, -) -> FilterCursor<'a, impl 'a + Fn(&FoldSummary) -> bool, Fold, usize> +) -> FilterCursor<'a, impl 'a + FnMut(&FoldSummary) -> bool, Fold, usize> where T: ToOffset, { diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 426115bfd4..642bc596af 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -1190,7 +1190,6 @@ impl LocalWorktree { diagnostics: lsp::PublishDiagnosticsParams, cx: &mut ModelContext, ) { - // } } diff --git a/crates/sum_tree/src/cursor.rs b/crates/sum_tree/src/cursor.rs index 2185593328..11c2847a7f 100644 --- a/crates/sum_tree/src/cursor.rs +++ b/crates/sum_tree/src/cursor.rs @@ -184,9 +184,9 @@ where self.next_internal(|_| true, cx) } - fn next_internal(&mut self, filter_node: F, cx: &::Context) + fn next_internal(&mut self, mut filter_node: F, cx: &::Context) where - F: Fn(&T::Summary) -> bool, + F: FnMut(&T::Summary) -> bool, { let mut descend = false; @@ -509,24 +509,24 @@ where } } -pub struct FilterCursor<'a, F: Fn(&T::Summary) -> bool, T: Item, D> { +pub struct FilterCursor<'a, F: FnMut(&T::Summary) -> bool, T: Item, D> { cursor: Cursor<'a, T, D>, filter_node: F, } impl<'a, F, T, D> FilterCursor<'a, F, T, D> where - F: Fn(&T::Summary) -> bool, + F: FnMut(&T::Summary) -> bool, T: Item, D: Dimension<'a, T::Summary>, { pub fn new( tree: &'a SumTree, - filter_node: F, + mut filter_node: F, cx: &::Context, ) -> Self { let mut cursor = tree.cursor::(); - cursor.next_internal(&filter_node, cx); + cursor.next_internal(&mut filter_node, cx); Self { cursor, filter_node, @@ -542,7 +542,7 @@ where } pub fn next(&mut self, cx: &::Context) { - self.cursor.next_internal(&self.filter_node, cx); + self.cursor.next_internal(&mut self.filter_node, cx); } } diff --git a/crates/sum_tree/src/lib.rs b/crates/sum_tree/src/lib.rs index 2bbb567ba1..eeef956324 100644 --- a/crates/sum_tree/src/lib.rs +++ b/crates/sum_tree/src/lib.rs @@ -163,7 +163,7 @@ impl SumTree { cx: &::Context, ) -> FilterCursor where - F: Fn(&T::Summary) -> bool, + F: FnMut(&T::Summary) -> bool, U: Dimension<'a, T::Summary>, { FilterCursor::new(self, filter_node, cx)