mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 20:25:44 +03:00
Finish removing anchor collections from MultiBuffer
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
d9da8effd4
commit
9c74deb9ec
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user