Finish removing anchor collections from MultiBuffer

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2021-12-10 15:58:37 +01:00
parent d9da8effd4
commit 9c74deb9ec
6 changed files with 181 additions and 415 deletions

View File

@ -28,7 +28,7 @@ pub struct Summary {
} }
impl DiagnosticSet { impl DiagnosticSet {
pub fn from_sorted_entries<I>(iter: I, buffer: &text::Snapshot) -> Self pub fn from_sorted_entries<I>(iter: I, buffer: &text::BufferSnapshot) -> Self
where where
I: IntoIterator<Item = DiagnosticEntry<Anchor>>, I: IntoIterator<Item = DiagnosticEntry<Anchor>>,
{ {
@ -37,7 +37,7 @@ impl DiagnosticSet {
} }
} }
pub fn new<I>(iter: I, buffer: &text::Snapshot) -> Self pub fn new<I>(iter: I, buffer: &text::BufferSnapshot) -> Self
where where
I: IntoIterator<Item = DiagnosticEntry<PointUtf16>>, I: IntoIterator<Item = DiagnosticEntry<PointUtf16>>,
{ {
@ -62,7 +62,7 @@ impl DiagnosticSet {
pub fn range<'a, T, O>( pub fn range<'a, T, O>(
&'a self, &'a self,
range: Range<T>, range: Range<T>,
buffer: &'a text::Snapshot, buffer: &'a text::BufferSnapshot,
inclusive: bool, inclusive: bool,
) -> impl 'a + Iterator<Item = DiagnosticEntry<O>> ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
where where
@ -101,7 +101,7 @@ impl DiagnosticSet {
pub fn group<'a, O: FromAnchor>( pub fn group<'a, O: FromAnchor>(
&'a self, &'a self,
group_id: usize, group_id: usize,
buffer: &'a text::Snapshot, buffer: &'a text::BufferSnapshot,
) -> impl 'a + Iterator<Item = DiagnosticEntry<O>> { ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>> {
self.iter() self.iter()
.filter(move |entry| entry.diagnostic.group_id == group_id) .filter(move |entry| entry.diagnostic.group_id == group_id)
@ -124,7 +124,7 @@ impl sum_tree::Item for DiagnosticEntry<Anchor> {
} }
impl DiagnosticEntry<Anchor> { impl DiagnosticEntry<Anchor> {
pub fn resolve<O: FromAnchor>(&self, buffer: &text::Snapshot) -> DiagnosticEntry<O> { pub fn resolve<O: FromAnchor>(&self, buffer: &text::BufferSnapshot) -> DiagnosticEntry<O> {
DiagnosticEntry { DiagnosticEntry {
range: O::from_anchor(&self.range.start, buffer) range: O::from_anchor(&self.range.start, buffer)
..O::from_anchor(&self.range.end, buffer), ..O::from_anchor(&self.range.end, buffer),
@ -146,7 +146,7 @@ impl Default for Summary {
} }
impl sum_tree::Summary for Summary { impl sum_tree::Summary for Summary {
type Context = text::Snapshot; type Context = text::BufferSnapshot;
fn add_summary(&mut self, other: &Self, buffer: &Self::Context) { fn add_summary(&mut self, other: &Self, buffer: &Self::Context) {
if other if other

View File

@ -1,32 +1,36 @@
mod anchor; mod anchor;
mod location;
mod selection; mod selection;
use self::location::*;
use crate::{ use crate::{
buffer::{self, Buffer, Chunk, ToOffset as _, ToPoint as _}, buffer::{self, Buffer, Chunk, ToOffset as _, ToPoint as _},
BufferSnapshot, Diagnostic, File, Language, BufferSnapshot, Diagnostic, File, Language,
}; };
pub use anchor::{Anchor, AnchorRangeExt};
use anyhow::Result; use anyhow::Result;
use clock::ReplicaId; use clock::ReplicaId;
use collections::HashMap; use collections::HashMap;
use gpui::{AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task}; use gpui::{AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task};
use parking_lot::{Mutex, MutexGuard}; use parking_lot::{Mutex, MutexGuard};
use smallvec::SmallVec; pub use selection::SelectionSet;
use std::{cmp, io, ops::Range, sync::Arc, time::SystemTime}; use std::{
cmp, io,
ops::{Range, Sub},
sync::Arc,
time::SystemTime,
};
use sum_tree::{Bias, Cursor, SumTree}; use sum_tree::{Bias, Cursor, SumTree};
use text::{ use text::{
locator::Locator,
rope::TextDimension, rope::TextDimension,
subscription::{Subscription, Topic}, subscription::{Subscription, Topic},
AnchorRangeExt as _, Edit, Point, PointUtf16, Selection, SelectionSetId, TextSummary, AnchorRangeExt as _, Edit, Point, PointUtf16, Selection, SelectionSetId, TextSummary,
}; };
use theme::SyntaxTheme; use theme::SyntaxTheme;
pub use anchor::{Anchor, AnchorRangeExt, AnchorRangeMap, AnchorRangeSet};
pub use selection::SelectionSet;
const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize]; const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize];
pub type ExcerptId = Locator;
#[derive(Default)] #[derive(Default)]
pub struct MultiBuffer { pub struct MultiBuffer {
snapshot: Mutex<MultiBufferSnapshot>, snapshot: Mutex<MultiBufferSnapshot>,
@ -314,10 +318,10 @@ impl MultiBuffer {
let mut edits = Vec::new(); let mut edits = Vec::new();
let mut new_excerpts = SumTree::new(); let mut new_excerpts = SumTree::new();
let mut cursor = snapshot.excerpts.cursor::<(ExcerptId, usize)>(); let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>();
for (id, buffer_state) in excerpts_to_edit { for (id, buffer_state) in excerpts_to_edit {
new_excerpts.push_tree(cursor.slice(id, Bias::Left, &()), &()); new_excerpts.push_tree(cursor.slice(&Some(id), Bias::Left, &()), &());
let old_excerpt = cursor.item().unwrap(); let old_excerpt = cursor.item().unwrap();
let buffer = buffer_state.buffer.read(cx); let buffer = buffer_state.buffer.read(cx);
@ -411,36 +415,6 @@ impl MultiBuffer {
self.snapshot.lock().anchor_at(position, bias) self.snapshot.lock().anchor_at(position, bias)
} }
pub fn anchor_range_map<T, E>(
&self,
start_bias: Bias,
end_bias: Bias,
entries: E,
) -> AnchorRangeMap<T>
where
E: IntoIterator<Item = (Range<usize>, T)>,
{
let entries = entries.into_iter().peekable();
let mut child_maps = SmallVec::new();
if let Some((range, _)) = entries.peek() {
let mut cursor = self.snapshot.lock().excerpts.cursor::<ExcerptSummary>();
cursor.seek(&range.start, Bias::Right, &());
let mut excerpt_end = cursor.end(&());
// child_maps.push
// for entry in entries {}
}
AnchorRangeMap { child_maps }
}
pub fn anchor_range_set<E>(&self, start_bias: Bias, end_bias: Bias, ranges: E) -> AnchorRangeSet
where
E: IntoIterator<Item = Range<usize>>,
{
todo!()
}
pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize { pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
self.snapshot.lock().clip_offset(offset, bias) self.snapshot.lock().clip_offset(offset, bias)
} }
@ -863,6 +837,77 @@ impl MultiBufferSnapshot {
summary summary
} }
fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
where
D: TextDimension + Ord + Sub<D, Output = D>,
{
let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
cursor.seek(&Some(&anchor.excerpt_id), Bias::Left, &());
if let Some(excerpt) = cursor.item() {
if excerpt.id == anchor.excerpt_id {
let mut excerpt_start = D::from_text_summary(&cursor.start().text);
excerpt_start.add_summary(&excerpt.header_summary(), &());
let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
let buffer_point = anchor.text_anchor.summary::<D>(&excerpt.buffer);
if buffer_point > excerpt_buffer_start {
excerpt_start.add_assign(&(buffer_point - excerpt_buffer_start));
}
return excerpt_start;
}
}
D::from_text_summary(&cursor.start().text)
}
fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
where
D: TextDimension + Ord + Sub<D, Output = D>,
I: 'a + IntoIterator<Item = &'a Anchor>,
{
let mut anchors = anchors.into_iter().peekable();
let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
let mut summaries = Vec::new();
while let Some(anchor) = anchors.peek() {
let excerpt_id = &anchor.excerpt_id;
cursor.seek(&Some(excerpt_id), Bias::Left, &());
if let Some(excerpt) = cursor.item() {
let excerpt_exists = excerpt.id == *excerpt_id;
let excerpt_anchors = std::iter::from_fn(|| {
let anchor = anchors.peek()?;
if anchor.excerpt_id == *excerpt_id {
Some(&anchors.next().unwrap().text_anchor)
} else {
None
}
});
if excerpt_exists {
let mut excerpt_start = D::from_text_summary(&cursor.start().text);
excerpt_start.add_summary(&excerpt.header_summary(), &());
let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
summaries.extend(
excerpt
.buffer
.summaries_for_anchors::<D, _>(excerpt_anchors)
.map(move |summary| {
let mut excerpt_start = excerpt_start.clone();
let excerpt_buffer_start = excerpt_buffer_start.clone();
if summary > excerpt_buffer_start {
excerpt_start.add_assign(&(summary - excerpt_buffer_start));
}
excerpt_start
}),
);
} else {
excerpt_anchors.for_each(drop);
}
} else {
break;
}
}
summaries
}
pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor { pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
self.anchor_at(position, Bias::Left) self.anchor_at(position, Bias::Left)
} }
@ -923,12 +968,12 @@ impl MultiBufferSnapshot {
fn buffer_snapshot_for_excerpt<'a>( fn buffer_snapshot_for_excerpt<'a>(
&'a self, &'a self,
excerpt_id: &ExcerptId, excerpt_id: &'a ExcerptId,
) -> Option<&'a BufferSnapshot> { ) -> Option<&'a BufferSnapshot> {
let mut cursor = self.excerpts.cursor::<ExcerptId>(); let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
cursor.seek(excerpt_id, Bias::Left, &()); cursor.seek(&Some(excerpt_id), Bias::Left, &());
if let Some(excerpt) = cursor.item() { if let Some(excerpt) = cursor.item() {
if cursor.start() == excerpt_id { if *cursor.start() == Some(excerpt_id) {
return Some(&excerpt.buffer); return Some(&excerpt.buffer);
} }
} }
@ -1020,9 +1065,9 @@ impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
} }
} }
impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Location { impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Option<&'a ExcerptId> {
fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering { fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
Ord::cmp(self, &cursor_location.excerpt_id) Ord::cmp(self, &Some(&cursor_location.excerpt_id))
} }
} }
@ -1038,10 +1083,9 @@ impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
} }
} }
impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Location { impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a ExcerptId> {
fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) { fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
debug_assert!(summary.excerpt_id > *self); *self = Some(&summary.excerpt_id);
*self = summary.excerpt_id.clone();
} }
} }

View File

@ -1,27 +1,18 @@
use super::{location::*, ExcerptSummary, MultiBufferSnapshot, ToOffset, ToPoint}; use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToPoint};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use smallvec::SmallVec;
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
ops::{Range, Sub}, ops::{Range, Sub},
}; };
use sum_tree::Bias; use sum_tree::Bias;
use text::{rope::TextDimension, AnchorRangeExt as _, Point}; use text::{rope::TextDimension, Point};
#[derive(Clone, Eq, PartialEq, Debug, Hash)] #[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub struct Anchor { pub struct Anchor {
excerpt_id: ExcerptId, pub(crate) excerpt_id: ExcerptId,
text_anchor: text::Anchor, pub(crate) text_anchor: text::Anchor,
} }
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct AnchorRangeMap<T> {
pub(crate) child_maps: SmallVec<[(ExcerptId, text::AnchorRangeMap<T>); 1]>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AnchorRangeSet(AnchorRangeMap<()>);
impl Anchor { impl Anchor {
pub fn min() -> Self { pub fn min() -> Self {
Self { Self {
@ -75,234 +66,11 @@ impl Anchor {
self.clone() self.clone()
} }
pub fn summary<'a, D>(&self, snapshot: &'a MultiBufferSnapshot) -> D pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
where where
D: TextDimension + Ord + Sub<D, Output = D>, D: TextDimension + Ord + Sub<D, Output = D>,
{ {
let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>(); snapshot.summary_for_anchor(self)
cursor.seek(&self.excerpt_id, Bias::Left, &());
if let Some(excerpt) = cursor.item() {
if excerpt.id == self.excerpt_id {
let mut excerpt_start = D::from_text_summary(&cursor.start().text);
excerpt_start.add_summary(&excerpt.header_summary(), &());
let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
let buffer_point = self.text_anchor.summary::<D>(&excerpt.buffer);
if buffer_point > excerpt_buffer_start {
excerpt_start.add_assign(&(buffer_point - excerpt_buffer_start));
}
return excerpt_start;
}
}
D::from_text_summary(&cursor.start().text)
}
}
impl<T> AnchorRangeMap<T> {
pub fn len(&self) -> usize {
self.child_maps
.iter()
.map(|(_, text_map)| text_map.len())
.sum()
}
pub fn ranges<'a, D>(
&'a self,
snapshot: &'a MultiBufferSnapshot,
) -> impl Iterator<Item = (Range<D>, &'a T)> + 'a
where
D: TextDimension + Clone,
{
let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>();
self.child_maps
.iter()
.filter_map(move |(excerpt_id, text_map)| {
cursor.seek_forward(excerpt_id, Bias::Left, &());
if let Some(excerpt) = cursor.item() {
if excerpt.id == *excerpt_id {
let mut excerpt_start = D::from_text_summary(&cursor.start().text);
excerpt_start.add_summary(&excerpt.header_summary(), &());
return Some(text_map.ranges::<D>(&excerpt.buffer).map(
move |(range, value)| {
let mut full_range = excerpt_start.clone()..excerpt_start.clone();
full_range.start.add_assign(&range.start);
full_range.end.add_assign(&range.end);
(full_range, value)
},
));
}
}
None
})
.flatten()
}
pub fn intersecting_ranges<'a, D, I>(
&'a self,
range: Range<(I, Bias)>,
snapshot: &'a MultiBufferSnapshot,
) -> impl Iterator<Item = (Range<D>, &'a T)> + 'a
where
D: TextDimension,
I: ToOffset,
{
let start_bias = range.start.1;
let end_bias = range.end.1;
let start_offset = range.start.0.to_offset(snapshot);
let end_offset = range.end.0.to_offset(snapshot);
let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>();
cursor.seek(&start_offset, start_bias, &());
let start_excerpt_id = &cursor.start().excerpt_id;
let start_ix = match self
.child_maps
.binary_search_by_key(&start_excerpt_id, |e| &e.0)
{
Ok(ix) | Err(ix) => ix,
};
let mut entry_ranges = None;
let mut entries = self.child_maps[start_ix..].iter();
std::iter::from_fn(move || loop {
match &mut entry_ranges {
None => {
let (excerpt_id, text_map) = entries.next()?;
cursor.seek(excerpt_id, Bias::Left, &());
if cursor.start().text.bytes >= end_offset {
return None;
}
if let Some(excerpt) = cursor.item() {
if excerpt.id == *excerpt_id {
let mut excerpt_start = D::from_text_summary(&cursor.start().text);
excerpt_start.add_summary(&excerpt.header_summary(), &());
let excerpt_start_offset = cursor.start().text.bytes;
let excerpt_end_offset = cursor.end(&()).text.bytes;
let excerpt_buffer_range = excerpt.range.to_offset(&excerpt.buffer);
let start;
if start_offset >= excerpt_start_offset {
start = (
excerpt_buffer_range.start + start_offset
- excerpt_start_offset,
start_bias,
);
} else {
start = (excerpt_buffer_range.start, Bias::Left);
}
let end;
if end_offset <= excerpt_end_offset {
end = (
excerpt_buffer_range.start + end_offset - excerpt_start_offset,
end_bias,
);
} else {
end = (excerpt_buffer_range.end, Bias::Right);
}
entry_ranges = Some(
text_map
.intersecting_ranges(start..end, &excerpt.buffer)
.map(move |(range, value)| {
let mut full_range =
excerpt_start.clone()..excerpt_start.clone();
full_range.start.add_assign(&range.start);
full_range.end.add_assign(&range.end);
(full_range, value)
}),
);
}
}
}
Some(ranges) => {
if let Some(item) = ranges.next() {
return Some(item);
} else {
entry_ranges.take();
}
}
}
})
}
pub fn min_by_key<'a, D, F, K>(
&self,
snapshot: &'a MultiBufferSnapshot,
extract_key: F,
) -> Option<(Range<D>, &T)>
where
D: TextDimension,
F: FnMut(&T) -> K,
K: Ord,
{
self.min_or_max_by_key(snapshot, Ordering::Less, extract_key)
}
pub fn max_by_key<'a, D, F, K>(
&self,
snapshot: &'a MultiBufferSnapshot,
extract_key: F,
) -> Option<(Range<D>, &T)>
where
D: TextDimension,
F: FnMut(&T) -> K,
K: Ord,
{
self.min_or_max_by_key(snapshot, Ordering::Greater, extract_key)
}
fn min_or_max_by_key<'a, D, F, K>(
&self,
snapshot: &'a MultiBufferSnapshot,
target_ordering: Ordering,
mut extract_key: F,
) -> Option<(Range<D>, &T)>
where
D: TextDimension,
F: FnMut(&T) -> K,
K: Ord,
{
let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>();
let mut max = None;
for (excerpt_id, text_map) in &self.child_maps {
cursor.seek(excerpt_id, Bias::Left, &());
if let Some(excerpt) = cursor.item() {
if excerpt.id == *excerpt_id {
if let Some((range, value)) =
text_map.max_by_key(&excerpt.buffer, &mut extract_key)
{
if max.as_ref().map_or(true, |(_, max_value)| {
extract_key(value).cmp(&extract_key(*max_value)) == target_ordering
}) {
let mut excerpt_start = D::from_text_summary(&cursor.start().text);
excerpt_start.add_summary(&excerpt.header_summary(), &());
let mut full_range = excerpt_start.clone()..excerpt_start.clone();
full_range.start.add_assign(&range.start);
full_range.end.add_assign(&range.end);
max = Some((full_range, value));
}
}
}
}
}
max
}
}
impl AnchorRangeSet {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn ranges<'a, D>(
&'a self,
content: &'a MultiBufferSnapshot,
) -> impl 'a + Iterator<Item = Range<Point>>
where
D: TextDimension,
{
self.0.ranges(content).map(|(range, _)| range)
} }
} }

View File

@ -1,76 +0,0 @@
use smallvec::{smallvec, SmallVec};
use std::iter;
pub type ExcerptId = Location;
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Location(SmallVec<[u8; 4]>);
impl Location {
pub fn min() -> Self {
Self(smallvec![u8::MIN])
}
pub fn max() -> Self {
Self(smallvec![u8::MAX])
}
pub fn between(lhs: &Self, rhs: &Self) -> Self {
let lhs = lhs.0.iter().copied().chain(iter::repeat(u8::MIN));
let rhs = rhs.0.iter().copied().chain(iter::repeat(u8::MAX));
let mut location = SmallVec::new();
for (lhs, rhs) in lhs.zip(rhs) {
let mid = lhs + (rhs.saturating_sub(lhs)) / 2;
location.push(mid);
if mid > lhs {
break;
}
}
Self(location)
}
}
impl Default for Location {
fn default() -> Self {
Self::min()
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::prelude::*;
use std::mem;
#[gpui::test(iterations = 100)]
fn test_location(mut rng: StdRng) {
let mut lhs = Default::default();
let mut rhs = Default::default();
while lhs == rhs {
lhs = Location(
(0..rng.gen_range(1..=5))
.map(|_| rng.gen_range(0..=100))
.collect(),
);
rhs = Location(
(0..rng.gen_range(1..=5))
.map(|_| rng.gen_range(0..=100))
.collect(),
);
}
if lhs > rhs {
mem::swap(&mut lhs, &mut rhs);
}
let middle = Location::between(&lhs, &rhs);
assert!(middle > lhs);
assert!(middle < rhs);
for ix in 0..middle.0.len() - 1 {
assert!(
middle.0[ix] == *lhs.0.get(ix).unwrap_or(&0)
|| middle.0[ix] == *rhs.0.get(ix).unwrap_or(&0)
);
}
}
}

View File

@ -1,13 +1,16 @@
use super::{anchor::AnchorRangeMap, MultiBufferSnapshot, ToOffset}; use super::{Anchor, MultiBufferSnapshot, ToOffset};
use std::{ops::Range, sync::Arc}; use std::{
ops::{Range, Sub},
sync::Arc,
};
use sum_tree::Bias; use sum_tree::Bias;
use text::{rope::TextDimension, Selection, SelectionSetId, SelectionState}; use text::{rope::TextDimension, Selection, SelectionSetId};
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct SelectionSet { pub struct SelectionSet {
pub id: SelectionSetId, pub id: SelectionSetId,
pub active: bool, pub active: bool,
pub selections: Arc<AnchorRangeMap<SelectionState>>, pub selections: Arc<[Selection<Anchor>]>,
} }
impl SelectionSet { impl SelectionSet {
@ -17,75 +20,102 @@ impl SelectionSet {
pub fn selections<'a, D>( pub fn selections<'a, D>(
&'a self, &'a self,
content: &'a MultiBufferSnapshot, snapshot: &'a MultiBufferSnapshot,
) -> impl 'a + Iterator<Item = Selection<D>> ) -> impl 'a + Iterator<Item = Selection<D>>
where where
D: TextDimension, D: TextDimension + Ord + Sub<D, Output = D>,
{ {
self.selections resolve_selections(&self.selections, snapshot)
.ranges(content)
.map(|(range, state)| Selection {
id: state.id,
start: range.start,
end: range.end,
reversed: state.reversed,
goal: state.goal,
})
} }
pub fn intersecting_selections<'a, D, I>( pub fn intersecting_selections<'a, D, I>(
&'a self, &'a self,
range: Range<(I, Bias)>, range: Range<(I, Bias)>,
content: &'a MultiBufferSnapshot, snapshot: &'a MultiBufferSnapshot,
) -> impl 'a + Iterator<Item = Selection<D>> ) -> impl 'a + Iterator<Item = Selection<D>>
where where
D: TextDimension, D: TextDimension + Ord + Sub<D, Output = D>,
I: 'a + ToOffset, I: 'a + ToOffset,
{ {
self.selections let start = snapshot.anchor_at(range.start.0, range.start.1);
.intersecting_ranges(range, content) let end = snapshot.anchor_at(range.end.0, range.end.1);
.map(|(range, state)| Selection { let start_ix = match self
id: state.id, .selections
start: range.start, .binary_search_by(|probe| probe.end.cmp(&start, snapshot).unwrap())
end: range.end, {
reversed: state.reversed, Ok(ix) | Err(ix) => ix,
goal: state.goal, };
}) let end_ix = match self
.selections
.binary_search_by(|probe| probe.start.cmp(&end, snapshot).unwrap())
{
Ok(ix) | Err(ix) => ix,
};
resolve_selections(&self.selections[start_ix..end_ix], snapshot)
} }
pub fn oldest_selection<'a, D>( pub fn oldest_selection<'a, D>(
&'a self, &'a self,
content: &'a MultiBufferSnapshot, snapshot: &'a MultiBufferSnapshot,
) -> Option<Selection<D>> ) -> Option<Selection<D>>
where where
D: TextDimension, D: TextDimension + Ord + Sub<D, Output = D>,
{ {
self.selections self.selections
.min_by_key(content, |selection| selection.id) .iter()
.map(|(range, state)| Selection { .min_by_key(|selection| selection.id)
id: state.id, .map(|selection| resolve_selection(selection, snapshot))
start: range.start,
end: range.end,
reversed: state.reversed,
goal: state.goal,
})
} }
pub fn newest_selection<'a, D>( pub fn newest_selection<'a, D>(
&'a self, &'a self,
content: &'a MultiBufferSnapshot, snapshot: &'a MultiBufferSnapshot,
) -> Option<Selection<D>> ) -> Option<Selection<D>>
where where
D: TextDimension, D: TextDimension + Ord + Sub<D, Output = D>,
{ {
self.selections self.selections
.max_by_key(content, |selection| selection.id) .iter()
.map(|(range, state)| Selection { .max_by_key(|selection| selection.id)
id: state.id, .map(|selection| resolve_selection(selection, snapshot))
start: range.start,
end: range.end,
reversed: state.reversed,
goal: state.goal,
})
} }
} }
fn resolve_selection<'a, D>(
selection: &'a Selection<Anchor>,
snapshot: &'a MultiBufferSnapshot,
) -> Selection<D>
where
D: TextDimension + Ord + Sub<D, Output = D>,
{
Selection {
id: selection.id,
start: selection.start.summary::<D>(snapshot),
end: selection.end.summary::<D>(snapshot),
reversed: selection.reversed,
goal: selection.goal,
}
}
fn resolve_selections<'a, D>(
selections: &'a [Selection<Anchor>],
snapshot: &'a MultiBufferSnapshot,
) -> impl 'a + Iterator<Item = Selection<D>>
where
D: TextDimension + Ord + Sub<D, Output = D>,
{
let mut summaries = snapshot
.summaries_for_anchors::<D, _>(
selections
.iter()
.flat_map(|selection| [&selection.start, &selection.end]),
)
.into_iter();
selections.iter().map(move |selection| Selection {
id: selection.id,
start: summaries.next().unwrap(),
end: summaries.next().unwrap(),
reversed: selection.reversed,
goal: selection.goal,
})
}

View File

@ -1,5 +1,5 @@
mod anchor; mod anchor;
mod locator; pub mod locator;
pub mod operation_queue; pub mod operation_queue;
mod patch; mod patch;
mod point; mod point;