mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 10:29:35 +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 {
|
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
|
||||||
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user