Detailed changes
@@ -28,7 +28,7 @@ pub struct Summary {
}
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
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
I: IntoIterator<Item = DiagnosticEntry<PointUtf16>>,
{
@@ -62,7 +62,7 @@ impl DiagnosticSet {
pub fn range<'a, T, O>(
&'a self,
range: Range<T>,
- buffer: &'a text::Snapshot,
+ buffer: &'a text::BufferSnapshot,
inclusive: bool,
) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
where
@@ -101,7 +101,7 @@ impl DiagnosticSet {
pub fn group<'a, O: FromAnchor>(
&'a self,
group_id: usize,
- buffer: &'a text::Snapshot,
+ buffer: &'a text::BufferSnapshot,
) -> impl 'a + Iterator<Item = DiagnosticEntry<O>> {
self.iter()
.filter(move |entry| entry.diagnostic.group_id == group_id)
@@ -124,7 +124,7 @@ impl sum_tree::Item for 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 {
range: O::from_anchor(&self.range.start, buffer)
..O::from_anchor(&self.range.end, buffer),
@@ -146,7 +146,7 @@ impl Default 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) {
if other
@@ -1,32 +1,36 @@
mod anchor;
-mod location;
mod selection;
-use self::location::*;
use crate::{
buffer::{self, Buffer, Chunk, ToOffset as _, ToPoint as _},
BufferSnapshot, Diagnostic, File, Language,
};
+pub use anchor::{Anchor, AnchorRangeExt};
use anyhow::Result;
use clock::ReplicaId;
use collections::HashMap;
use gpui::{AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task};
use parking_lot::{Mutex, MutexGuard};
-use smallvec::SmallVec;
-use std::{cmp, io, ops::Range, sync::Arc, time::SystemTime};
+pub use selection::SelectionSet;
+use std::{
+ cmp, io,
+ ops::{Range, Sub},
+ sync::Arc,
+ time::SystemTime,
+};
use sum_tree::{Bias, Cursor, SumTree};
use text::{
+ locator::Locator,
rope::TextDimension,
subscription::{Subscription, Topic},
AnchorRangeExt as _, Edit, Point, PointUtf16, Selection, SelectionSetId, TextSummary,
};
use theme::SyntaxTheme;
-pub use anchor::{Anchor, AnchorRangeExt, AnchorRangeMap, AnchorRangeSet};
-pub use selection::SelectionSet;
-
const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize];
+pub type ExcerptId = Locator;
+
#[derive(Default)]
pub struct MultiBuffer {
snapshot: Mutex<MultiBufferSnapshot>,
@@ -314,10 +318,10 @@ impl MultiBuffer {
let mut edits = Vec::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 {
- 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 buffer = buffer_state.buffer.read(cx);
@@ -411,36 +415,6 @@ impl MultiBuffer {
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 {
self.snapshot.lock().clip_offset(offset, bias)
}
@@ -863,6 +837,77 @@ impl MultiBufferSnapshot {
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 {
self.anchor_at(position, Bias::Left)
}
@@ -923,12 +968,12 @@ impl MultiBufferSnapshot {
fn buffer_snapshot_for_excerpt<'a>(
&'a self,
- excerpt_id: &ExcerptId,
+ excerpt_id: &'a ExcerptId,
) -> Option<&'a BufferSnapshot> {
- let mut cursor = self.excerpts.cursor::<ExcerptId>();
- cursor.seek(excerpt_id, Bias::Left, &());
+ let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
+ cursor.seek(&Some(excerpt_id), Bias::Left, &());
if let Some(excerpt) = cursor.item() {
- if cursor.start() == excerpt_id {
+ if *cursor.start() == Some(excerpt_id) {
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 {
- 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, _: &()) {
- debug_assert!(summary.excerpt_id > *self);
- *self = summary.excerpt_id.clone();
+ *self = Some(&summary.excerpt_id);
}
}
@@ -1,27 +1,18 @@
-use super::{location::*, ExcerptSummary, MultiBufferSnapshot, ToOffset, ToPoint};
+use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToPoint};
use anyhow::{anyhow, Result};
-use smallvec::SmallVec;
use std::{
cmp::Ordering,
ops::{Range, Sub},
};
use sum_tree::Bias;
-use text::{rope::TextDimension, AnchorRangeExt as _, Point};
+use text::{rope::TextDimension, Point};
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub struct Anchor {
- excerpt_id: ExcerptId,
- text_anchor: text::Anchor,
+ pub(crate) excerpt_id: ExcerptId,
+ 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 {
pub fn min() -> Self {
Self {
@@ -75,234 +66,11 @@ impl Anchor {
self.clone()
}
- pub fn summary<'a, D>(&self, snapshot: &'a MultiBufferSnapshot) -> D
+ pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
where
D: TextDimension + Ord + Sub<D, Output = D>,
{
- let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>();
- 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)
+ snapshot.summary_for_anchor(self)
}
}
@@ -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)
- );
- }
- }
-}
@@ -1,13 +1,16 @@
-use super::{anchor::AnchorRangeMap, MultiBufferSnapshot, ToOffset};
-use std::{ops::Range, sync::Arc};
+use super::{Anchor, MultiBufferSnapshot, ToOffset};
+use std::{
+ ops::{Range, Sub},
+ sync::Arc,
+};
use sum_tree::Bias;
-use text::{rope::TextDimension, Selection, SelectionSetId, SelectionState};
+use text::{rope::TextDimension, Selection, SelectionSetId};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SelectionSet {
pub id: SelectionSetId,
pub active: bool,
- pub selections: Arc<AnchorRangeMap<SelectionState>>,
+ pub selections: Arc<[Selection<Anchor>]>,
}
impl SelectionSet {
@@ -17,75 +20,102 @@ impl SelectionSet {
pub fn selections<'a, D>(
&'a self,
- content: &'a MultiBufferSnapshot,
+ snapshot: &'a MultiBufferSnapshot,
) -> impl 'a + Iterator<Item = Selection<D>>
where
- D: TextDimension,
+ D: TextDimension + Ord + Sub<D, Output = D>,
{
- self.selections
- .ranges(content)
- .map(|(range, state)| Selection {
- id: state.id,
- start: range.start,
- end: range.end,
- reversed: state.reversed,
- goal: state.goal,
- })
+ resolve_selections(&self.selections, snapshot)
}
pub fn intersecting_selections<'a, D, I>(
&'a self,
range: Range<(I, Bias)>,
- content: &'a MultiBufferSnapshot,
+ snapshot: &'a MultiBufferSnapshot,
) -> impl 'a + Iterator<Item = Selection<D>>
where
- D: TextDimension,
+ D: TextDimension + Ord + Sub<D, Output = D>,
I: 'a + ToOffset,
{
- self.selections
- .intersecting_ranges(range, content)
- .map(|(range, state)| Selection {
- id: state.id,
- start: range.start,
- end: range.end,
- reversed: state.reversed,
- goal: state.goal,
- })
+ let start = snapshot.anchor_at(range.start.0, range.start.1);
+ let end = snapshot.anchor_at(range.end.0, range.end.1);
+ let start_ix = match self
+ .selections
+ .binary_search_by(|probe| probe.end.cmp(&start, snapshot).unwrap())
+ {
+ Ok(ix) | Err(ix) => ix,
+ };
+ 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>(
&'a self,
- content: &'a MultiBufferSnapshot,
+ snapshot: &'a MultiBufferSnapshot,
) -> Option<Selection<D>>
where
- D: TextDimension,
+ D: TextDimension + Ord + Sub<D, Output = D>,
{
self.selections
- .min_by_key(content, |selection| selection.id)
- .map(|(range, state)| Selection {
- id: state.id,
- start: range.start,
- end: range.end,
- reversed: state.reversed,
- goal: state.goal,
- })
+ .iter()
+ .min_by_key(|selection| selection.id)
+ .map(|selection| resolve_selection(selection, snapshot))
}
pub fn newest_selection<'a, D>(
&'a self,
- content: &'a MultiBufferSnapshot,
+ snapshot: &'a MultiBufferSnapshot,
) -> Option<Selection<D>>
where
- D: TextDimension,
+ D: TextDimension + Ord + Sub<D, Output = D>,
{
self.selections
- .max_by_key(content, |selection| selection.id)
- .map(|(range, state)| Selection {
- id: state.id,
- start: range.start,
- end: range.end,
- reversed: state.reversed,
- goal: state.goal,
- })
+ .iter()
+ .max_by_key(|selection| selection.id)
+ .map(|selection| resolve_selection(selection, snapshot))
}
}
+
+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,
+ })
+}
@@ -1,5 +1,5 @@
mod anchor;
-mod locator;
+pub mod locator;
pub mod operation_queue;
mod patch;
mod point;