Introduce Content::anchor_range_multimap

This commit is contained in:
Antonio Scandurra 2021-10-26 14:27:19 +02:00
parent 5dc47c625e
commit e8a2885721
6 changed files with 115 additions and 50 deletions

View file

@ -31,26 +31,26 @@ pub struct AnchorRangeMap<T> {
pub struct AnchorRangeSet(pub(crate) AnchorRangeMap<()>); pub struct AnchorRangeSet(pub(crate) AnchorRangeMap<()>);
pub struct AnchorRangeMultimap<T: Clone> { pub struct AnchorRangeMultimap<T: Clone> {
entries: SumTree<AnchorRangeMultimapEntry<T>>, pub(crate) entries: SumTree<AnchorRangeMultimapEntry<T>>,
pub(crate) version: clock::Global, pub(crate) version: clock::Global,
pub(crate) start_bias: Bias, pub(crate) start_bias: Bias,
pub(crate) end_bias: Bias, pub(crate) end_bias: Bias,
} }
#[derive(Clone)] #[derive(Clone)]
struct AnchorRangeMultimapEntry<T> { pub(crate) struct AnchorRangeMultimapEntry<T> {
range: FullOffsetRange, pub(crate) range: FullOffsetRange,
value: T, pub(crate) value: T,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct FullOffsetRange { pub(crate) struct FullOffsetRange {
start: usize, pub(crate) start: usize,
end: usize, pub(crate) end: usize,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct AnchorRangeMultimapSummary { pub(crate) struct AnchorRangeMultimapSummary {
start: usize, start: usize,
end: usize, end: usize,
min_start: usize, min_start: usize,
@ -165,46 +165,61 @@ impl AnchorRangeSet {
} }
impl<T: Clone> AnchorRangeMultimap<T> { impl<T: Clone> AnchorRangeMultimap<T> {
fn intersecting_point_ranges<'a, O: ToOffset>( fn intersecting_point_ranges<'a>(
&'a self, &'a self,
range: Range<O>, range: Range<Anchor>,
content: impl Into<Content<'a>>, content: &'a Content<'a>,
inclusive: bool, inclusive: bool,
) -> impl Iterator<Item = (usize, Range<Point>, &T)> + 'a { ) -> impl Iterator<Item = (usize, Range<Point>, &T)> + 'a {
use super::ToPoint as _; 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>( let mut cursor = self.entries.filter::<_, usize>(
move |summary: &AnchorRangeMultimapSummary| { {
if inclusive { let mut endpoint = Anchor {
start <= summary.max_end && end >= summary.min_start full_offset: 0,
} else { bias: Bias::Right,
start < summary.max_end && end > summary.min_start 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, std::iter::from_fn({
bias: Bias::Left, let mut endpoint = Anchor {
version: self.version.clone(), full_offset: 0,
}; bias: Bias::Left,
std::iter::from_fn(move || { version: self.version.clone(),
if let Some(item) = cursor.item() { };
let ix = *cursor.start(); move || {
anchor.full_offset = item.range.start; if let Some(item) = cursor.item() {
anchor.bias = self.start_bias; let ix = *cursor.start();
let start = anchor.to_point(&content); endpoint.full_offset = item.range.start;
anchor.full_offset = item.range.end; endpoint.bias = self.start_bias;
anchor.bias = self.end_bias; let start = endpoint.to_point(content);
let end = anchor.to_point(&content); endpoint.full_offset = item.range.end;
let value = &item.value; endpoint.bias = self.end_bias;
cursor.next(&()); let end = endpoint.to_point(content);
Some((ix, start..end, value)) let value = &item.value;
} else { cursor.next(&());
None Some((ix, start..end, value))
} else {
None
}
} }
}) })
} }

View file

@ -20,6 +20,7 @@ use rpc::proto;
pub use selection::*; pub use selection::*;
use std::{ use std::{
cmp, cmp,
collections::{BTreeMap, BTreeSet},
convert::{TryFrom, TryInto}, convert::{TryFrom, TryInto},
iter::Iterator, iter::Iterator,
ops::Range, 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, visible_text: &'a Rope,
deleted_text: &'a Rope, deleted_text: &'a Rope,
cursor: Option<FilterCursor<'a, F, Fragment, FragmentTextSummary>>, cursor: Option<FilterCursor<'a, F, Fragment, FragmentTextSummary>>,
@ -1836,6 +1837,56 @@ impl<'a> Content<'a> {
AnchorRangeSet(self.anchor_range_map(entries.into_iter().map(|range| (range, ())))) AnchorRangeSet(self.anchor_range_map(entries.into_iter().map(|range| (range, ()))))
} }
pub fn anchor_range_multimap<T, E, O>(
&self,
start_bias: Bias,
end_bias: Bias,
entries: E,
) -> AnchorRangeMultimap<T>
where
T: Clone,
E: IntoIterator<Item = (Range<O>, 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::<FragmentTextSummary>();
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 { fn full_offset_for_anchor(&self, anchor: &Anchor) -> usize {
let cx = Some(anchor.version.clone()); let cx = Some(anchor.version.clone());
let mut cursor = self 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; type Item = Edit;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {

View file

@ -720,7 +720,7 @@ fn intersecting_folds<'a, T>(
folds: &'a SumTree<Fold>, folds: &'a SumTree<Fold>,
range: Range<T>, range: Range<T>,
inclusive: bool, inclusive: bool,
) -> FilterCursor<'a, impl 'a + Fn(&FoldSummary) -> bool, Fold, usize> ) -> FilterCursor<'a, impl 'a + FnMut(&FoldSummary) -> bool, Fold, usize>
where where
T: ToOffset, T: ToOffset,
{ {

View file

@ -1190,7 +1190,6 @@ impl LocalWorktree {
diagnostics: lsp::PublishDiagnosticsParams, diagnostics: lsp::PublishDiagnosticsParams,
cx: &mut ModelContext<Worktree>, cx: &mut ModelContext<Worktree>,
) { ) {
//
} }
} }

View file

@ -184,9 +184,9 @@ where
self.next_internal(|_| true, cx) self.next_internal(|_| true, cx)
} }
fn next_internal<F>(&mut self, filter_node: F, cx: &<T::Summary as Summary>::Context) fn next_internal<F>(&mut self, mut filter_node: F, cx: &<T::Summary as Summary>::Context)
where where
F: Fn(&T::Summary) -> bool, F: FnMut(&T::Summary) -> bool,
{ {
let mut descend = false; 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>, cursor: Cursor<'a, T, D>,
filter_node: F, filter_node: F,
} }
impl<'a, F, T, D> FilterCursor<'a, F, T, D> impl<'a, F, T, D> FilterCursor<'a, F, T, D>
where where
F: Fn(&T::Summary) -> bool, F: FnMut(&T::Summary) -> bool,
T: Item, T: Item,
D: Dimension<'a, T::Summary>, D: Dimension<'a, T::Summary>,
{ {
pub fn new( pub fn new(
tree: &'a SumTree<T>, tree: &'a SumTree<T>,
filter_node: F, mut filter_node: F,
cx: &<T::Summary as Summary>::Context, cx: &<T::Summary as Summary>::Context,
) -> Self { ) -> Self {
let mut cursor = tree.cursor::<D>(); let mut cursor = tree.cursor::<D>();
cursor.next_internal(&filter_node, cx); cursor.next_internal(&mut filter_node, cx);
Self { Self {
cursor, cursor,
filter_node, filter_node,
@ -542,7 +542,7 @@ where
} }
pub fn next(&mut self, cx: &<T::Summary as Summary>::Context) { pub fn next(&mut self, cx: &<T::Summary as Summary>::Context) {
self.cursor.next_internal(&self.filter_node, cx); self.cursor.next_internal(&mut self.filter_node, cx);
} }
} }

View file

@ -163,7 +163,7 @@ impl<T: Item> SumTree<T> {
cx: &<T::Summary as Summary>::Context, cx: &<T::Summary as Summary>::Context,
) -> FilterCursor<F, T, U> ) -> FilterCursor<F, T, U>
where where
F: Fn(&T::Summary) -> bool, F: FnMut(&T::Summary) -> bool,
U: Dimension<'a, T::Summary>, U: Dimension<'a, T::Summary>,
{ {
FilterCursor::new(self, filter_node, cx) FilterCursor::new(self, filter_node, cx)