Compare commits

...

7 Commits

Author SHA1 Message Date
Antonio Scandurra
5ec78700b6 Merge remote-tracking branch 'origin/main' into anchor-enum
# Conflicts:
#	crates/multi_buffer/src/multi_buffer.rs
2024-09-23 11:44:39 -06:00
Antonio Scandurra
250a27945c WIP 2024-09-19 09:10:34 -06:00
Antonio Scandurra
7a971e301c WIP 2024-09-18 10:40:19 -06:00
Antonio Scandurra
4cfe6469dc Merge remote-tracking branch 'origin/main' into anchor-enum
# Conflicts:
#	crates/text/src/anchor.rs
#	crates/text/src/text.rs
2024-09-18 09:26:53 -06:00
Antonio Scandurra
adcdc9cd89 WIP 2024-09-17 14:58:32 -06:00
Antonio Scandurra
fcd27b0019 WIP 2024-09-17 14:10:23 -06:00
Antonio Scandurra
013e12d3bc WIP: Make buffer_id not optional in text::Anchor 2024-09-17 13:49:28 -06:00
23 changed files with 572 additions and 394 deletions

View File

@@ -2794,7 +2794,7 @@ impl ContextEditor {
let multibuffer = editor.buffer().read(cx).snapshot(cx); let multibuffer = editor.buffer().read(cx).snapshot(cx);
let (&excerpt_id, _, buffer) = multibuffer.as_singleton().unwrap(); let (&excerpt_id, _, buffer) = multibuffer.as_singleton().unwrap();
let anchor = if group.context_range.start.to_offset(buffer) == 0 { let anchor = if group.context_range.start.to_offset(buffer) == 0 {
Anchor::min() Anchor::Start
} else { } else {
multibuffer multibuffer
.anchor_in_excerpt(excerpt_id, group.context_range.start) .anchor_in_excerpt(excerpt_id, group.context_range.start)

View File

@@ -1208,7 +1208,7 @@ impl InlineAssistant {
editor.set_read_only(true); editor.set_read_only(true);
editor.set_show_inline_completions(Some(false), cx); editor.set_show_inline_completions(Some(false), cx);
editor.highlight_rows::<DeletedLines>( editor.highlight_rows::<DeletedLines>(
Anchor::min()..=Anchor::max(), Anchor::Start..=Anchor::End,
Some(cx.theme().status().deleted_background), Some(cx.theme().status().deleted_background),
false, false,
cx, cx,

View File

@@ -138,7 +138,7 @@ impl WorkflowSuggestion {
} }
Self::CreateFile { description } => { Self::CreateFile { description } => {
initial_prompt = description.clone(); initial_prompt = description.clone();
suggestion_range = editor::Anchor::min()..editor::Anchor::min(); suggestion_range = Anchor::Start..Anchor::Start;
} }
Self::InsertBefore { Self::InsertBefore {
position, position,

View File

@@ -297,7 +297,7 @@ fn assert_remote_selections(
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) { ) {
let snapshot = editor.snapshot(cx); let snapshot = editor.snapshot(cx);
let range = Anchor::min()..Anchor::max(); let range = Anchor::Start..Anchor::End;
let remote_selections = snapshot let remote_selections = snapshot
.remote_selections_in_range(&range, editor.collaboration_hub().unwrap(), cx) .remote_selections_in_range(&range, editor.collaboration_hub().unwrap(), cx)
.map(|s| { .map(|s| {

View File

@@ -271,7 +271,7 @@ pub struct ItemSummary {
impl Default for ItemSummary { impl Default for ItemSummary {
fn default() -> Self { fn default() -> Self {
Self { Self {
range: Anchor::min()..Anchor::min(), range: Anchor::Start..Anchor::Start,
} }
} }
} }

View File

@@ -376,7 +376,7 @@ impl FoldMap {
.folds .folds
.cursor::<FoldRange>(&inlay_snapshot.buffer); .cursor::<FoldRange>(&inlay_snapshot.buffer);
folds_cursor.seek( folds_cursor.seek(
&FoldRange(anchor..Anchor::max()), &FoldRange(anchor..Anchor::End),
Bias::Left, Bias::Left,
&inlay_snapshot.buffer, &inlay_snapshot.buffer,
); );
@@ -997,7 +997,7 @@ impl DerefMut for FoldRange {
impl Default for FoldRange { impl Default for FoldRange {
fn default() -> Self { fn default() -> Self {
Self(Anchor::min()..Anchor::max()) Self(Anchor::Start..Anchor::End)
} }
} }
@@ -1027,10 +1027,10 @@ pub struct FoldSummary {
impl Default for FoldSummary { impl Default for FoldSummary {
fn default() -> Self { fn default() -> Self {
Self { Self {
start: Anchor::min(), start: Anchor::Start,
end: Anchor::max(), end: Anchor::End,
min_start: Anchor::max(), min_start: Anchor::End,
max_end: Anchor::min(), max_end: Anchor::Start,
count: 0, count: 0,
} }
} }

View File

@@ -3101,9 +3101,19 @@ impl Editor {
if self.linked_edit_ranges.is_empty() { if self.linked_edit_ranges.is_empty() {
return None; return None;
} }
let ((base_range, linked_ranges), buffer_snapshot, buffer) =
selection.end.buffer_id.and_then(|end_buffer_id| { let selection_start_buffer_id = match selection.start {
if selection.start.buffer_id != Some(end_buffer_id) { text::Anchor::Start | text::Anchor::End => None,
text::Anchor::Character { buffer_id, .. } => Some(buffer_id),
};
let selection_end_buffer_id = match selection.end {
text::Anchor::Start | text::Anchor::End => None,
text::Anchor::Character { buffer_id, .. } => Some(buffer_id),
};
let ((base_range, linked_ranges), buffer_snapshot, buffer) = selection_end_buffer_id
.and_then(|end_buffer_id| {
if selection_start_buffer_id != Some(end_buffer_id) {
return None; return None;
} }
let buffer = self.buffer.read(cx).buffer(end_buffer_id)?; let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
@@ -3130,8 +3140,8 @@ impl Editor {
continue; continue;
} }
if self.selections.disjoint_anchor_ranges().iter().any(|s| { if self.selections.disjoint_anchor_ranges().iter().any(|s| {
if s.start.buffer_id != selection.start.buffer_id if s.start.buffer_id != selection_start_buffer_id
|| s.end.buffer_id != selection.end.buffer_id || s.end.buffer_id != selection_end_buffer_id
{ {
return false; return false;
} }
@@ -5014,12 +5024,10 @@ impl Editor {
continue; continue;
} }
let range = Anchor { let range = Anchor::Text {
buffer_id,
excerpt_id, excerpt_id,
text_anchor: start, text_anchor: start,
}..Anchor { }..Anchor::Text {
buffer_id,
excerpt_id, excerpt_id,
text_anchor: end, text_anchor: end,
}; };
@@ -5611,7 +5619,15 @@ impl Editor {
for selection in selections.iter() { for selection in selections.iter() {
let selection_start = snapshot.anchor_before(selection.start).text_anchor; let selection_start = snapshot.anchor_before(selection.start).text_anchor;
let selection_end = snapshot.anchor_after(selection.end).text_anchor; let selection_end = snapshot.anchor_after(selection.end).text_anchor;
if selection_start.buffer_id != selection_end.buffer_id { let selection_start_buffer_id = match selection_start {
text::Anchor::Start | text::Anchor::End => None,
text::Anchor::Character { buffer_id, .. } => Some(buffer_id),
};
let selection_end_buffer_id = match selection_end {
text::Anchor::Start | text::Anchor::End => None,
text::Anchor::Character { buffer_id, .. } => Some(buffer_id),
};
if selection_start_buffer_id != selection_end_buffer_id {
continue; continue;
} }
if let Some(ranges) = if let Some(ranges) =
@@ -8974,7 +8990,7 @@ impl Editor {
.spawn({ .spawn({
let snapshot = display_snapshot.clone(); let snapshot = display_snapshot.clone();
async move { async move {
Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max()) Self::fetch_runnable_ranges(&snapshot, Anchor::Start..Anchor::End)
} }
}) })
.await; .await;
@@ -12686,7 +12702,7 @@ fn snippet_completions(
return vec![]; return vec![];
} }
let snapshot = buffer.read(cx).text_snapshot(); let snapshot = buffer.read(cx).text_snapshot();
let chunks = snapshot.reversed_chunks_in_range(text::Anchor::MIN..buffer_position); let chunks = snapshot.reversed_chunks_in_range(text::Anchor::Start..buffer_position);
let mut lines = chunks.lines(); let mut lines = chunks.lines();
let Some(line_at) = lines.next().filter(|line| !line.is_empty()) else { let Some(line_at) = lines.next().filter(|line| !line.is_empty()) else {

View File

@@ -739,7 +739,9 @@ async fn test_navigation_history(cx: &mut TestAppContext) {
// Ensure we don't panic when navigation data contains invalid anchors *and* points. // Ensure we don't panic when navigation data contains invalid anchors *and* points.
let mut invalid_anchor = editor.scroll_manager.anchor().anchor; let mut invalid_anchor = editor.scroll_manager.anchor().anchor;
invalid_anchor.text_anchor.buffer_id = BufferId::new(999).ok(); invalid_anchor.text_anchor = text::Anchor::Start {
buffer_id: BufferId::new(999).unwrap(),
};
let invalid_point = Point::new(9999, 0); let invalid_point = Point::new(9999, 0);
editor.navigate( editor.navigate(
Box::new(NavigationData { Box::new(NavigationData {

View File

@@ -950,7 +950,7 @@ impl EditorElement {
// Remote cursors // Remote cursors
if let Some(collaboration_hub) = &editor.collaboration_hub { if let Some(collaboration_hub) = &editor.collaboration_hub {
for remote_selection in snapshot.remote_selections_in_range( for remote_selection in snapshot.remote_selections_in_range(
&(Anchor::min()..Anchor::max()), &(Anchor::Start..Anchor::End),
collaboration_hub.deref(), collaboration_hub.deref(),
cx, cx,
) { ) {
@@ -5087,14 +5087,14 @@ impl Element for EditorElement {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let start_anchor = if start_row == Default::default() { let start_anchor = if start_row == Default::default() {
Anchor::min() Anchor::Start
} else { } else {
snapshot.buffer_snapshot.anchor_before( snapshot.buffer_snapshot.anchor_before(
DisplayPoint::new(start_row, 0).to_offset(&snapshot, Bias::Left), DisplayPoint::new(start_row, 0).to_offset(&snapshot, Bias::Left),
) )
}; };
let end_anchor = if end_row > max_row { let end_anchor = if end_row > max_row {
Anchor::max() Anchor::End
} else { } else {
snapshot.buffer_snapshot.anchor_before( snapshot.buffer_snapshot.anchor_before(
DisplayPoint::new(end_row, 0).to_offset(&snapshot, Bias::Right), DisplayPoint::new(end_row, 0).to_offset(&snapshot, Bias::Right),

View File

@@ -784,7 +784,7 @@ fn editor_with_deleted_text(
editor.set_read_only(true); editor.set_read_only(true);
editor.set_show_inline_completions(Some(false), cx); editor.set_show_inline_completions(Some(false), cx);
editor.highlight_rows::<DiffRowHighlight>( editor.highlight_rows::<DiffRowHighlight>(
Anchor::min()..=Anchor::max(), Anchor::Start..=Anchor::End,
Some(deleted_color), Some(deleted_color),
false, false,
cx, cx,

View File

@@ -40,13 +40,13 @@ impl ScrollAnchor {
fn new() -> Self { fn new() -> Self {
Self { Self {
offset: gpui::Point::default(), offset: gpui::Point::default(),
anchor: Anchor::min(), anchor: Anchor::Start,
} }
} }
pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point<f32> { pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point<f32> {
let mut scroll_position = self.offset; let mut scroll_position = self.offset;
if self.anchor == Anchor::min() { if self.anchor == Anchor::Start {
scroll_position.y = 0.; scroll_position.y = 0.;
} else { } else {
let scroll_top = self.anchor.to_display_point(snapshot).row().as_f32(); let scroll_top = self.anchor.to_display_point(snapshot).row().as_f32();
@@ -194,7 +194,7 @@ impl ScrollManager {
let (new_anchor, top_row) = if scroll_position.y <= 0. { let (new_anchor, top_row) = if scroll_position.y <= 0. {
( (
ScrollAnchor { ScrollAnchor {
anchor: Anchor::min(), anchor: Anchor::Start,
offset: scroll_position.max(&gpui::Point::default()), offset: scroll_position.max(&gpui::Point::default()),
}, },
0, 0,

View File

@@ -48,8 +48,8 @@ impl SelectionsCollection {
pending: Some(PendingSelection { pending: Some(PendingSelection {
selection: Selection { selection: Selection {
id: 0, id: 0,
start: Anchor::min(), start: Anchor::Start,
end: Anchor::min(), end: Anchor::Start,
reversed: false, reversed: false,
goal: SelectionGoal::None, goal: SelectionGoal::None,
}, },

View File

@@ -41,7 +41,7 @@ impl sum_tree::Item for InternalDiffHunk {
} }
} }
#[derive(Debug, Default, Clone)] #[derive(Debug, Clone)]
pub struct DiffHunkSummary { pub struct DiffHunkSummary {
buffer_range: Range<Anchor>, buffer_range: Range<Anchor>,
} }
@@ -49,8 +49,10 @@ pub struct DiffHunkSummary {
impl sum_tree::Summary for DiffHunkSummary { impl sum_tree::Summary for DiffHunkSummary {
type Context = text::BufferSnapshot; type Context = text::BufferSnapshot;
fn zero(_cx: &Self::Context) -> Self { fn zero(buffer: &Self::Context) -> Self {
Default::default() Self {
buffer_range: buffer.min_anchor()..buffer.min_anchor(),
}
} }
fn add_summary(&mut self, other: &Self, buffer: &Self::Context) { fn add_summary(&mut self, other: &Self, buffer: &Self::Context) {

View File

@@ -2768,7 +2768,7 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
for buffer in &buffers { for buffer in &buffers {
let buffer = buffer.read(cx).snapshot(); let buffer = buffer.read(cx).snapshot();
let actual_remote_selections = buffer let actual_remote_selections = buffer
.selections_in_range(Anchor::MIN..Anchor::MAX, false) .selections_in_range(buffer.min_anchor()..buffer.max_anchor(), false)
.map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>())) .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let expected_remote_selections = active_selections let expected_remote_selections = active_selections

View File

@@ -246,23 +246,17 @@ impl DiagnosticEntry<Anchor> {
} }
} }
impl Default for Summary {
fn default() -> Self {
Self {
start: Anchor::MIN,
end: Anchor::MAX,
min_start: Anchor::MAX,
max_end: Anchor::MIN,
count: 0,
}
}
}
impl sum_tree::Summary for Summary { impl sum_tree::Summary for Summary {
type Context = text::BufferSnapshot; type Context = text::BufferSnapshot;
fn zero(_cx: &Self::Context) -> Self { fn zero(buffer: &Self::Context) -> Self {
Default::default() Self {
start: buffer.min_anchor(),
end: buffer.max_anchor(),
min_start: buffer.max_anchor(),
max_end: buffer.min_anchor(),
count: 0,
}
} }
fn add_summary(&mut self, other: &Self, buffer: &Self::Context) { fn add_summary(&mut self, other: &Self, buffer: &Self::Context) {

View File

@@ -6,7 +6,7 @@ use clock::ReplicaId;
use lsp::{DiagnosticSeverity, LanguageServerId}; use lsp::{DiagnosticSeverity, LanguageServerId};
use rpc::proto; use rpc::proto;
use serde_json::Value; use serde_json::Value;
use std::{ops::Range, str::FromStr, sync::Arc}; use std::{ops::Range, str::FromStr, sync::Arc, u32};
use text::*; use text::*;
pub use proto::{BufferState, Operation}; pub use proto::{BufferState, Operation};
@@ -221,15 +221,36 @@ pub fn serialize_diagnostics<'a>(
/// Serializes an [`Anchor`] to be sent over RPC. /// Serializes an [`Anchor`] to be sent over RPC.
pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor { pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
proto::Anchor { match *anchor {
replica_id: anchor.timestamp.replica_id as u32, Anchor::Start { buffer_id } => proto::Anchor {
timestamp: anchor.timestamp.value, replica_id: 0,
offset: anchor.offset as u64, timestamp: 0,
bias: match anchor.bias { offset: 0,
Bias::Left => proto::Bias::Left as i32, bias: proto::Bias::Left as i32,
Bias::Right => proto::Bias::Right as i32, buffer_id: Some(buffer_id.into()),
},
Anchor::End { buffer_id } => proto::Anchor {
replica_id: u32::MAX,
timestamp: u32::MAX,
offset: u64::MAX,
bias: proto::Bias::Right as i32,
buffer_id: Some(buffer_id.into()),
},
Anchor::Character {
buffer_id,
insertion_id,
offset,
bias,
} => proto::Anchor {
replica_id: insertion_id.replica_id as u32,
timestamp: insertion_id.value,
offset: offset as u64,
bias: match bias {
Bias::Left => proto::Bias::Left as i32,
Bias::Right => proto::Bias::Right as i32,
},
buffer_id: Some(buffer_id.into()),
}, },
buffer_id: anchor.buffer_id.map(Into::into),
} }
} }
@@ -429,23 +450,33 @@ pub fn deserialize_diagnostics(
/// Deserializes an [`Anchor`] from the RPC representation. /// Deserializes an [`Anchor`] from the RPC representation.
pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> { pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
let buffer_id = if let Some(id) = anchor.buffer_id { let buffer_id = BufferId::new(anchor.buffer_id?).ok()?;
Some(BufferId::new(id).ok()?) if anchor.replica_id == 0
&& anchor.timestamp == 0
&& anchor.offset == 0
&& anchor.bias == proto::Bias::Left as i32
{
Some(Anchor::Start { buffer_id })
} else if anchor.replica_id == u32::MAX
&& anchor.timestamp == u32::MAX
&& anchor.offset == u64::MAX
&& anchor.bias == proto::Bias::Right as i32
{
Some(Anchor::End { buffer_id })
} else { } else {
None Some(Anchor::Character {
}; insertion_id: clock::Lamport {
Some(Anchor { replica_id: anchor.replica_id as ReplicaId,
timestamp: clock::Lamport { value: anchor.timestamp,
replica_id: anchor.replica_id as ReplicaId, },
value: anchor.timestamp, offset: anchor.offset as usize,
}, bias: match proto::Bias::from_i32(anchor.bias)? {
offset: anchor.offset as usize, proto::Bias::Left => Bias::Left,
bias: match proto::Bias::from_i32(anchor.bias)? { proto::Bias::Right => Bias::Right,
proto::Bias::Left => Bias::Left, },
proto::Bias::Right => Bias::Right, buffer_id,
}, })
buffer_id, }
})
} }
/// Returns a `[clock::Lamport`] timestamp for the given [`proto::Operation`]. /// Returns a `[clock::Lamport`] timestamp for the given [`proto::Operation`].

View File

@@ -303,7 +303,7 @@ impl SyntaxSnapshot {
let slice = cursor.slice( let slice = cursor.slice(
&SyntaxLayerPosition { &SyntaxLayerPosition {
depth: depth + 1, depth: depth + 1,
range: Anchor::MIN..Anchor::MAX, range: text.min_anchor()..text.max_anchor(),
language: None, language: None,
}, },
Bias::Left, Bias::Left,
@@ -459,7 +459,7 @@ impl SyntaxSnapshot {
start_point: Point::zero().to_ts_point(), start_point: Point::zero().to_ts_point(),
end_point: text.max_point().to_ts_point(), end_point: text.max_point().to_ts_point(),
}], }],
range: Anchor::MIN..Anchor::MAX, range: text.min_anchor()..text.max_anchor(),
mode: ParseMode::Single, mode: ParseMode::Single,
}); });
@@ -474,7 +474,7 @@ impl SyntaxSnapshot {
} else { } else {
SyntaxLayerPosition { SyntaxLayerPosition {
depth: max_depth + 1, depth: max_depth + 1,
range: Anchor::MAX..Anchor::MAX, range: text.max_anchor()..text.max_anchor(),
language: None, language: None,
} }
}; };
@@ -485,7 +485,7 @@ impl SyntaxSnapshot {
let bounded_position = SyntaxLayerPositionBeforeChange { let bounded_position = SyntaxLayerPositionBeforeChange {
position: position.clone(), position: position.clone(),
change: changed_regions.start_position(), change: changed_regions.start_position(text),
}; };
if bounded_position.cmp(cursor.start(), text).is_gt() { if bounded_position.cmp(cursor.start(), text).is_gt() {
let slice = cursor.slice(&bounded_position, Bias::Left, text); let slice = cursor.slice(&bounded_position, Bias::Left, text);
@@ -1608,11 +1608,11 @@ impl ChangedRegion {
} }
impl ChangeRegionSet { impl ChangeRegionSet {
fn start_position(&self) -> ChangeStartPosition { fn start_position(&self, text: &BufferSnapshot) -> ChangeStartPosition {
self.0.first().map_or( self.0.first().map_or(
ChangeStartPosition { ChangeStartPosition {
depth: usize::MAX, depth: usize::MAX,
position: Anchor::MAX, position: text.max_anchor(),
}, },
|region| ChangeStartPosition { |region| ChangeStartPosition {
depth: region.depth, depth: region.depth,
@@ -1661,24 +1661,18 @@ impl ChangeRegionSet {
} }
} }
impl Default for SyntaxLayerSummary {
fn default() -> Self {
Self {
max_depth: 0,
min_depth: 0,
range: Anchor::MAX..Anchor::MIN,
last_layer_range: Anchor::MIN..Anchor::MAX,
last_layer_language: None,
contains_unknown_injections: false,
}
}
}
impl sum_tree::Summary for SyntaxLayerSummary { impl sum_tree::Summary for SyntaxLayerSummary {
type Context = BufferSnapshot; type Context = BufferSnapshot;
fn zero(_cx: &BufferSnapshot) -> Self { fn zero(buffer: &BufferSnapshot) -> Self {
Default::default() Self {
max_depth: 0,
min_depth: 0,
range: buffer.max_anchor()..buffer.min_anchor(),
last_layer_range: buffer.min_anchor()..buffer.max_anchor(),
last_layer_language: None,
contains_unknown_injections: false,
}
} }
fn add_summary(&mut self, other: &Self, buffer: &Self::Context) { fn add_summary(&mut self, other: &Self, buffer: &Self::Context) {
@@ -1686,7 +1680,7 @@ impl sum_tree::Summary for SyntaxLayerSummary {
self.max_depth = other.max_depth; self.max_depth = other.max_depth;
self.range = other.range.clone(); self.range = other.range.clone();
} else { } else {
if self.range == (Anchor::MAX..Anchor::MAX) { if self.range == (buffer.max_anchor()..buffer.max_anchor()) {
self.range.start = other.range.start; self.range.start = other.range.start;
} }
if other.range.end.cmp(&self.range.end, buffer).is_gt() { if other.range.end.cmp(&self.range.end, buffer).is_gt() {

View File

@@ -5,75 +5,105 @@ use std::{
ops::{Range, Sub}, ops::{Range, Sub},
}; };
use sum_tree::Bias; use sum_tree::Bias;
use text::BufferId;
#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)] #[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
pub struct Anchor { pub enum Anchor {
pub buffer_id: Option<BufferId>, Start,
pub excerpt_id: ExcerptId, End,
pub text_anchor: text::Anchor, Text {
excerpt_id: ExcerptId,
text_anchor: text::Anchor,
},
} }
impl Anchor { impl Anchor {
pub fn min() -> Self { pub fn excerpt_id(&self) -> ExcerptId {
Self { match self {
buffer_id: None, Anchor::Start => ExcerptId::min(),
excerpt_id: ExcerptId::min(), Anchor::End => ExcerptId::max(),
text_anchor: text::Anchor::MIN, Anchor::Text { excerpt_id, .. } => *excerpt_id,
}
}
pub fn max() -> Self {
Self {
buffer_id: None,
excerpt_id: ExcerptId::max(),
text_anchor: text::Anchor::MAX,
} }
} }
pub fn cmp(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering { pub fn cmp(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering {
let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id, snapshot); match (self, other) {
if excerpt_id_cmp.is_eq() { (Anchor::Start, Anchor::Start) | (Anchor::End, Anchor::End) => Ordering::Equal,
if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() { (_, Anchor::Start) | (Anchor::End, _) => Ordering::Greater,
Ordering::Equal (Anchor::Start, _) | (_, Anchor::End) => Ordering::Less,
} else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) { (
self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer) Anchor::Text {
} else { excerpt_id: id1,
Ordering::Equal text_anchor: anchor1,
},
Anchor::Text {
excerpt_id: id2,
text_anchor: anchor2,
},
) => {
let excerpt_id_cmp = id1.cmp(id2, snapshot);
if excerpt_id_cmp.is_eq() {
if let Some(excerpt) = snapshot.excerpt(*id1) {
anchor1.cmp(anchor2, &excerpt.buffer)
} else {
Ordering::Equal
}
} else {
excerpt_id_cmp
}
} }
} else {
excerpt_id_cmp
} }
} }
pub fn bias(&self) -> Bias { pub fn bias(&self) -> Bias {
self.text_anchor.bias match self {
Anchor::Start => Bias::Left,
Anchor::End => Bias::Right,
Anchor::Text { text_anchor, .. } => match text_anchor {
text::Anchor::Start { .. } => Bias::Left,
text::Anchor::End { .. } => Bias::Right,
text::Anchor::Character { bias, .. } => *bias,
},
}
} }
pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor { pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
if self.text_anchor.bias != Bias::Left { match self {
if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) { Anchor::Start => *self,
return Self { Anchor::End => snapshot.anchor_before(snapshot.len()),
buffer_id: self.buffer_id, Anchor::Text {
excerpt_id: self.excerpt_id, excerpt_id,
text_anchor: self.text_anchor.bias_left(&excerpt.buffer), text_anchor,
}; } => {
if let Some(excerpt) = snapshot.excerpt(*excerpt_id) {
Anchor::Text {
excerpt_id: *excerpt_id,
text_anchor: text_anchor.bias_left(&excerpt.buffer),
}
} else {
*self
}
} }
} }
*self
} }
pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor { pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
if self.text_anchor.bias != Bias::Right { match self {
if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) { Anchor::Start => snapshot.anchor_after(0),
return Self { Anchor::End => *self,
buffer_id: self.buffer_id, Anchor::Text {
excerpt_id: self.excerpt_id, excerpt_id,
text_anchor: self.text_anchor.bias_right(&excerpt.buffer), text_anchor,
}; } => {
if let Some(excerpt) = snapshot.excerpt(*excerpt_id) {
Anchor::Text {
excerpt_id: *excerpt_id,
text_anchor: text_anchor.bias_right(&excerpt.buffer),
}
} else {
*self
}
} }
} }
*self
} }
pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
@@ -84,15 +114,18 @@ impl Anchor {
} }
pub fn is_valid(&self, snapshot: &MultiBufferSnapshot) -> bool { pub fn is_valid(&self, snapshot: &MultiBufferSnapshot) -> bool {
if *self == Anchor::min() || *self == Anchor::max() { match self {
true Self::Start | Anchor::End => true,
} else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) { Anchor::Text {
excerpt.contains(self) excerpt_id,
&& (self.text_anchor == excerpt.range.context.start text_anchor,
|| self.text_anchor == excerpt.range.context.end } => {
|| self.text_anchor.is_valid(&excerpt.buffer)) if let Some(excerpt) = snapshot.excerpt(*excerpt_id) {
} else { excerpt.contains(self) && text_anchor.is_valid(&excerpt.buffer)
false } else {
false
}
}
} }
} }
} }

View File

@@ -437,13 +437,14 @@ impl MultiBuffer {
self.capability == Capability::ReadOnly self.capability == Capability::ReadOnly
} }
pub fn singleton(buffer: Model<Buffer>, cx: &mut ModelContext<Self>) -> Self { pub fn singleton(buffer_model: Model<Buffer>, cx: &mut ModelContext<Self>) -> Self {
let mut this = Self::new(buffer.read(cx).capability()); let buffer = buffer_model.read(cx);
let mut this = Self::new(buffer.capability());
this.singleton = true; this.singleton = true;
this.push_excerpts( this.push_excerpts(
buffer, buffer_model,
[ExcerptRange { [ExcerptRange {
context: text::Anchor::MIN..text::Anchor::MAX, context: buffer.min_anchor()..buffer.max_anchor(),
primary: None, primary: None,
}], }],
cx, cx,
@@ -962,9 +963,27 @@ impl MultiBuffer {
Default::default(); Default::default();
let snapshot = self.read(cx); let snapshot = self.read(cx);
let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>(&()); let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>(&());
for selection in selections { for mut selection in selections {
let start_locator = snapshot.excerpt_locator_for_id(selection.start.excerpt_id); if selection.start == Anchor::Start {
let end_locator = snapshot.excerpt_locator_for_id(selection.end.excerpt_id); if let Some(first_excerpt) = snapshot.excerpts.first() {
selection.start = Anchor::Text {
excerpt_id: first_excerpt.id,
text_anchor: first_excerpt.range.context.start,
};
}
}
if selection.end == Anchor::End {
if let Some(last_excerpt) = snapshot.excerpts.last() {
selection.end = Anchor::Text {
excerpt_id: last_excerpt.id,
text_anchor: last_excerpt.range.context.end,
};
}
}
let start_locator = snapshot.excerpt_locator_for_id(selection.start.excerpt_id());
let end_locator = snapshot.excerpt_locator_for_id(selection.end.excerpt_id());
cursor.seek(&Some(start_locator), Bias::Left, &()); cursor.seek(&Some(start_locator), Bias::Left, &());
while let Some(excerpt) = cursor.item() { while let Some(excerpt) = cursor.item() {
@@ -974,11 +993,15 @@ impl MultiBuffer {
let mut start = excerpt.range.context.start; let mut start = excerpt.range.context.start;
let mut end = excerpt.range.context.end; let mut end = excerpt.range.context.end;
if excerpt.id == selection.start.excerpt_id { if excerpt.id == selection.start.excerpt_id() {
start = selection.start.text_anchor; if let Anchor::Text { text_anchor, .. } = selection.start {
start = text_anchor;
}
} }
if excerpt.id == selection.end.excerpt_id { if excerpt.id == selection.end.excerpt_id() {
end = selection.end.text_anchor; if let Anchor::Text { text_anchor, .. } = selection.end {
end = text_anchor;
}
} }
selections_by_buffer selections_by_buffer
.entry(excerpt.buffer_id) .entry(excerpt.buffer_id)
@@ -1168,13 +1191,11 @@ impl MultiBuffer {
for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.by_ref()) for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.by_ref())
{ {
for range in ranges.by_ref().take(range_count) { for range in ranges.by_ref().take(range_count) {
let start = Anchor { let start = Anchor::Text {
buffer_id: Some(buffer_id),
excerpt_id, excerpt_id,
text_anchor: range.start, text_anchor: range.start,
}; };
let end = Anchor { let end = Anchor::Text {
buffer_id: Some(buffer_id),
excerpt_id, excerpt_id,
text_anchor: range.end, text_anchor: range.end,
}; };
@@ -1223,13 +1244,11 @@ impl MultiBuffer {
let mut ranges = ranges.into_iter(); let mut ranges = ranges.into_iter();
for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.into_iter()) { for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.into_iter()) {
anchor_ranges.extend(ranges.by_ref().take(range_count).map(|range| { anchor_ranges.extend(ranges.by_ref().take(range_count).map(|range| {
let start = Anchor { let start = Anchor::Text {
buffer_id: Some(buffer_id),
excerpt_id, excerpt_id,
text_anchor: buffer_snapshot.anchor_after(range.start), text_anchor: buffer_snapshot.anchor_after(range.start),
}; };
let end = Anchor { let end = Anchor::Text {
buffer_id: Some(buffer_id),
excerpt_id, excerpt_id,
text_anchor: buffer_snapshot.anchor_after(range.end), text_anchor: buffer_snapshot.anchor_after(range.end),
}; };
@@ -1654,14 +1673,15 @@ impl MultiBuffer {
let mut error = None; let mut error = None;
let mut futures = Vec::new(); let mut futures = Vec::new();
for anchor in anchors { for anchor in anchors {
if let Some(buffer_id) = anchor.buffer_id { if let Anchor::Text { text_anchor, .. } = anchor {
if let Some(buffer) = borrow.get(&buffer_id) { if let Some(buffer) = borrow.get(&text_anchor.buffer_id()) {
buffer.buffer.update(cx, |buffer, _| { buffer.buffer.update(cx, |buffer, _| {
futures.push(buffer.wait_for_anchors([anchor.text_anchor])) futures.push(buffer.wait_for_anchors([text_anchor]))
}); });
} else { } else {
error = Some(anyhow!( error = Some(anyhow!(
"buffer {buffer_id} is not part of this multi-buffer" "buffer {:?} is not part of this multi-buffer",
text_anchor.buffer_id()
)); ));
break; break;
} }
@@ -1684,14 +1704,43 @@ impl MultiBuffer {
cx: &AppContext, cx: &AppContext,
) -> Option<(Model<Buffer>, language::Anchor)> { ) -> Option<(Model<Buffer>, language::Anchor)> {
let snapshot = self.read(cx); let snapshot = self.read(cx);
let anchor = snapshot.anchor_before(position); match snapshot.anchor_before(position) {
let buffer = self Anchor::Start => {
.buffers if let Some(first_excerpt) = snapshot.excerpts.first() {
.borrow() let buffer = self
.get(&anchor.buffer_id?)? .buffers
.buffer .borrow()
.clone(); .get(&first_excerpt.buffer_id)?
Some((buffer, anchor.text_anchor)) .buffer
.clone();
Some((buffer, first_excerpt.range.context.start))
} else {
None
}
}
Anchor::End => {
if let Some(last_excerpt) = snapshot.excerpts.last() {
let buffer = self
.buffers
.borrow()
.get(&last_excerpt.buffer_id)?
.buffer
.clone();
Some((buffer, last_excerpt.range.context.end))
} else {
None
}
}
Anchor::Text { text_anchor, .. } => {
let buffer = self
.buffers
.borrow()
.get(&text_anchor.buffer_id())?
.buffer
.clone();
Some((buffer, text_anchor))
}
}
} }
fn on_buffer_event( fn on_buffer_event(
@@ -2944,7 +2993,7 @@ impl MultiBufferSnapshot {
D: TextDimension + Ord + Sub<D, Output = D>, D: TextDimension + Ord + Sub<D, Output = D>,
{ {
let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&()); let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&());
let locator = self.excerpt_locator_for_id(anchor.excerpt_id); let locator = self.excerpt_locator_for_id(anchor.excerpt_id());
cursor.seek(locator, Bias::Left, &()); cursor.seek(locator, Bias::Left, &());
if cursor.item().is_none() { if cursor.item().is_none() {
@@ -2953,7 +3002,7 @@ impl MultiBufferSnapshot {
let mut position = D::from_text_summary(&cursor.start().text); let mut position = D::from_text_summary(&cursor.start().text);
if let Some(excerpt) = cursor.item() { if let Some(excerpt) = cursor.item() {
if excerpt.id == anchor.excerpt_id { if excerpt.id == anchor.excerpt_id() {
let excerpt_buffer_start = let excerpt_buffer_start =
excerpt.range.context.start.summary::<D>(&excerpt.buffer); excerpt.range.context.start.summary::<D>(&excerpt.buffer);
let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer); let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer);
@@ -3085,12 +3134,11 @@ impl MultiBufferSnapshot {
// If there's no adjacent excerpt that contains the anchor's position, // If there's no adjacent excerpt that contains the anchor's position,
// then report that the anchor has lost its position. // then report that the anchor has lost its position.
if !kept_position { if !kept_position {
let bias = anchor.bias();
anchor = if let Some(excerpt) = next_excerpt { anchor = if let Some(excerpt) = next_excerpt {
let mut text_anchor = excerpt let mut text_anchor =
.range excerpt.range.context.start.bias(bias, &excerpt.buffer);
.context
.start
.bias(anchor.text_anchor.bias, &excerpt.buffer);
if text_anchor if text_anchor
.cmp(&excerpt.range.context.end, &excerpt.buffer) .cmp(&excerpt.range.context.end, &excerpt.buffer)
.is_gt() .is_gt()
@@ -3103,11 +3151,7 @@ impl MultiBufferSnapshot {
text_anchor, text_anchor,
} }
} else if let Some(excerpt) = prev_excerpt { } else if let Some(excerpt) = prev_excerpt {
let mut text_anchor = excerpt let mut text_anchor = excerpt.range.context.end.bias(bias, &excerpt.buffer);
.range
.context
.end
.bias(anchor.text_anchor.bias, &excerpt.buffer);
if text_anchor if text_anchor
.cmp(&excerpt.range.context.start, &excerpt.buffer) .cmp(&excerpt.range.context.start, &excerpt.buffer)
.is_lt() .is_lt()
@@ -3119,10 +3163,10 @@ impl MultiBufferSnapshot {
excerpt_id: excerpt.id, excerpt_id: excerpt.id,
text_anchor, text_anchor,
} }
} else if anchor.text_anchor.bias == Bias::Left { } else if bias == Bias::Left {
Anchor::min() Anchor::Start
} else { } else {
Anchor::max() Anchor::End
}; };
} }
@@ -3172,9 +3216,9 @@ impl MultiBufferSnapshot {
text_anchor, text_anchor,
} }
} else if offset == 0 && bias == Bias::Left { } else if offset == 0 && bias == Bias::Left {
Anchor::min() Anchor::Start
} else { } else {
Anchor::max() Anchor::End
} }
} }

View File

@@ -999,7 +999,7 @@ impl LspStore {
let actions = this let actions = this
.update(cx, move |this, cx| { .update(cx, move |this, cx| {
let request = GetCodeActions { let request = GetCodeActions {
range: text::Anchor::MIN..text::Anchor::MAX, range: buffer.read(cx).min_anchor()..buffer.read(cx).max_anchor(),
kinds: Some(code_actions), kinds: Some(code_actions),
}; };
let server = LanguageServerToQuery::Other(language_server.server_id()); let server = LanguageServerToQuery::Other(language_server.server_id());
@@ -1323,9 +1323,7 @@ impl LspStore {
}); });
buffer buffer
.update(&mut cx, |buffer, _| { .update(&mut cx, |buffer, _| buffer.wait_for_anchors(Some(position)))?
buffer.wait_for_edits(Some(position.timestamp))
})?
.await?; .await?;
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
let position = position.to_point_utf16(buffer.read(cx)); let position = position.to_point_utf16(buffer.read(cx));
@@ -1969,7 +1967,7 @@ impl LspStore {
cx.spawn(move |_, mut cx| async move { cx.spawn(move |_, mut cx| async move {
buffer_handle buffer_handle
.update(&mut cx, |buffer, _| { .update(&mut cx, |buffer, _| {
buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp]) buffer.wait_for_anchors([range_start, range_end])
})? })?
.await .await
.context("waiting for inlay hint request range edits")?; .context("waiting for inlay hint request range edits")?;

View File

@@ -537,7 +537,7 @@ async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) {
DiagnosticSet::from_sorted_entries( DiagnosticSet::from_sorted_entries(
vec![DiagnosticEntry { vec![DiagnosticEntry {
diagnostic: Default::default(), diagnostic: Default::default(),
range: Anchor::MIN..Anchor::MAX, range: buffer.min_anchor()..buffer.max_anchor(),
}], }],
&buffer.snapshot(), &buffer.snapshot(),
), ),

View File

@@ -6,43 +6,68 @@ use std::{cmp::Ordering, fmt::Debug, ops::Range};
use sum_tree::Bias; use sum_tree::Bias;
/// A timestamped position in a buffer /// A timestamped position in a buffer
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Default)] #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
pub struct Anchor { pub enum Anchor {
pub timestamp: clock::Lamport, Start {
/// The byte offset in the buffer buffer_id: BufferId,
pub offset: usize, },
/// Describes which character the anchor is biased towards End {
pub bias: Bias, buffer_id: BufferId,
pub buffer_id: Option<BufferId>, },
Character {
buffer_id: BufferId,
insertion_id: clock::Lamport,
offset: usize,
bias: Bias,
},
} }
impl Anchor { impl Anchor {
pub const MIN: Self = Self { pub fn buffer_id(&self) -> BufferId {
timestamp: clock::Lamport::MIN, match self {
offset: usize::MIN, Anchor::Start { buffer_id } => *buffer_id,
bias: Bias::Left, Anchor::End { buffer_id } => *buffer_id,
buffer_id: None, Anchor::Character { buffer_id, .. } => *buffer_id,
}; }
}
pub const MAX: Self = Self {
timestamp: clock::Lamport::MAX,
offset: usize::MAX,
bias: Bias::Right,
buffer_id: None,
};
pub fn cmp(&self, other: &Anchor, buffer: &BufferSnapshot) -> Ordering { pub fn cmp(&self, other: &Anchor, buffer: &BufferSnapshot) -> Ordering {
let fragment_id_comparison = if self.timestamp == other.timestamp { debug_assert_eq!(
Ordering::Equal self.buffer_id(),
} else { other.buffer_id(),
buffer "anchors belong to different buffers"
.fragment_id_for_anchor(self) );
.cmp(buffer.fragment_id_for_anchor(other))
};
fragment_id_comparison match (self, other) {
.then_with(|| self.offset.cmp(&other.offset)) (Anchor::Start { .. }, Anchor::Start { .. }) => Ordering::Equal,
.then_with(|| self.bias.cmp(&other.bias)) (Anchor::End { .. }, Anchor::End { .. }) => Ordering::Equal,
(Anchor::Start { .. }, _) | (_, Anchor::End { .. }) => Ordering::Less,
(_, Anchor::Start { .. }) | (Anchor::End { .. }, _) => Ordering::Greater,
(
Anchor::Character {
insertion_id,
offset,
bias,
..
},
Anchor::Character {
insertion_id: other_insertion_id,
offset: other_offset,
bias: other_bias,
..
},
) => {
if insertion_id == other_insertion_id {
offset
.cmp(&other_offset)
.then_with(|| bias.cmp(&other_bias))
} else {
buffer
.fragment_id_for_anchor(self)
.cmp(buffer.fragment_id_for_anchor(other))
}
}
}
} }
pub fn min(&self, other: &Self, buffer: &BufferSnapshot) -> Self { pub fn min(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
@@ -70,18 +95,42 @@ impl Anchor {
} }
pub fn bias_left(&self, buffer: &BufferSnapshot) -> Anchor { pub fn bias_left(&self, buffer: &BufferSnapshot) -> Anchor {
if self.bias == Bias::Left { match self {
*self Anchor::Start { buffer_id } => Anchor::Start {
} else { buffer_id: *buffer_id,
buffer.anchor_before(self) },
Anchor::End { .. } => buffer.anchor_before(buffer.len()),
Anchor::Character {
buffer_id,
insertion_id,
offset,
..
} => Anchor::Character {
buffer_id: *buffer_id,
insertion_id: *insertion_id,
offset: *offset,
bias: Bias::Left,
},
} }
} }
pub fn bias_right(&self, buffer: &BufferSnapshot) -> Anchor { pub fn bias_right(&self, buffer: &BufferSnapshot) -> Anchor {
if self.bias == Bias::Right { match self {
*self Anchor::Start { .. } => buffer.anchor_after(0),
} else { Anchor::End { buffer_id } => Anchor::End {
buffer.anchor_after(self) buffer_id: *buffer_id,
},
Anchor::Character {
buffer_id,
insertion_id,
offset,
..
} => Anchor::Character {
buffer_id: *buffer_id,
insertion_id: *insertion_id,
offset: *offset,
bias: Bias::Right,
},
} }
} }
@@ -94,17 +143,23 @@ impl Anchor {
/// Returns true when the [`Anchor`] is located inside a visible fragment. /// Returns true when the [`Anchor`] is located inside a visible fragment.
pub fn is_valid(&self, buffer: &BufferSnapshot) -> bool { pub fn is_valid(&self, buffer: &BufferSnapshot) -> bool {
if *self == Anchor::MIN || *self == Anchor::MAX { match self {
true Anchor::Start { buffer_id } | Anchor::End { buffer_id } => {
} else if self.buffer_id != Some(buffer.remote_id) { *buffer_id == buffer.remote_id
false }
} else { Anchor::Character { buffer_id, .. } => {
let fragment_id = buffer.fragment_id_for_anchor(self); if *buffer_id == buffer.remote_id {
let mut fragment_cursor = buffer.fragments.cursor::<(Option<&Locator>, usize)>(&None); let fragment_id = buffer.fragment_id_for_anchor(self);
fragment_cursor.seek(&Some(fragment_id), Bias::Left, &None); let mut fragment_cursor =
fragment_cursor buffer.fragments.cursor::<(Option<&Locator>, usize)>(&None);
.item() fragment_cursor.seek(&Some(fragment_id), Bias::Left, &None);
.map_or(false, |fragment| fragment.visible) fragment_cursor
.item()
.map_or(false, |fragment| fragment.visible)
} else {
false
}
}
} }
} }
} }

View File

@@ -1542,16 +1542,15 @@ impl Buffer {
) -> impl 'static + Future<Output = Result<()>> { ) -> impl 'static + Future<Output = Result<()>> {
let mut futures = Vec::new(); let mut futures = Vec::new();
for anchor in anchors { for anchor in anchors {
if !self.version.observed(anchor.timestamp) if let Anchor::Character { insertion_id, .. } = anchor {
&& anchor != Anchor::MAX if !self.version.observed(insertion_id) {
&& anchor != Anchor::MIN let (tx, rx) = oneshot::channel();
{ self.edit_id_resolvers
let (tx, rx) = oneshot::channel(); .entry(insertion_id)
self.edit_id_resolvers .or_default()
.entry(anchor.timestamp) .push(tx);
.or_default() futures.push(rx);
.push(tx); }
futures.push(rx);
} }
} }
@@ -1928,6 +1927,18 @@ impl BufferSnapshot {
self.visible_text.summary() self.visible_text.summary()
} }
pub fn min_anchor(&self) -> Anchor {
Anchor::Start {
buffer_id: self.remote_id,
}
}
pub fn max_anchor(&self) -> Anchor {
Anchor::End {
buffer_id: self.remote_id,
}
}
pub fn max_point(&self) -> Point { pub fn max_point(&self) -> Point {
self.visible_text.max_point() self.visible_text.max_point()
} }
@@ -2129,41 +2140,50 @@ impl BufferSnapshot {
let mut position = D::zero(&()); let mut position = D::zero(&());
anchors.map(move |(anchor, payload)| { anchors.map(move |(anchor, payload)| {
if *anchor == Anchor::MIN { debug_assert_eq!(
return (D::zero(&()), payload); anchor.buffer_id(),
} else if *anchor == Anchor::MAX { self.remote_id,
return (D::from_text_summary(&self.visible_text.summary()), payload); "anchor belongs to a different buffer"
} );
let anchor_key = InsertionFragmentKey { match *anchor {
timestamp: anchor.timestamp, Anchor::Start { .. } => (D::zero(&()), payload),
split_offset: anchor.offset, Anchor::End { .. } => (D::from_text_summary(&self.visible_text.summary()), payload),
}; Anchor::Character {
insertion_cursor.seek(&anchor_key, anchor.bias, &()); insertion_id,
if let Some(insertion) = insertion_cursor.item() { offset,
let comparison = sum_tree::KeyedItem::key(insertion).cmp(&anchor_key); bias,
if comparison == Ordering::Greater ..
|| (anchor.bias == Bias::Left } => {
&& comparison == Ordering::Equal let anchor_key = InsertionFragmentKey {
&& anchor.offset > 0) timestamp: insertion_id,
{ split_offset: offset,
insertion_cursor.prev(&()); };
insertion_cursor.seek(&anchor_key, bias, &());
if let Some(insertion) = insertion_cursor.item() {
let comparison = sum_tree::KeyedItem::key(insertion).cmp(&anchor_key);
if comparison == Ordering::Greater
|| (bias == Bias::Left && comparison == Ordering::Equal && offset > 0)
{
insertion_cursor.prev(&());
}
} else {
insertion_cursor.prev(&());
}
let insertion = insertion_cursor.item().expect("invalid insertion");
assert_eq!(insertion.timestamp, insertion_id, "invalid insertion");
fragment_cursor.seek_forward(&Some(&insertion.fragment_id), Bias::Left, &None);
let fragment = fragment_cursor.item().unwrap();
let mut fragment_offset = fragment_cursor.start().1;
if fragment.visible {
fragment_offset += offset - insertion.split_offset;
}
position.add_assign(&text_cursor.summary(fragment_offset));
(position.clone(), payload)
} }
} else {
insertion_cursor.prev(&());
} }
let insertion = insertion_cursor.item().expect("invalid insertion");
assert_eq!(insertion.timestamp, anchor.timestamp, "invalid insertion");
fragment_cursor.seek_forward(&Some(&insertion.fragment_id), Bias::Left, &None);
let fragment = fragment_cursor.item().unwrap();
let mut fragment_offset = fragment_cursor.start().1;
if fragment.visible {
fragment_offset += anchor.offset - insertion.split_offset;
}
position.add_assign(&text_cursor.summary(fragment_offset));
(position.clone(), payload)
}) })
} }
@@ -2171,90 +2191,57 @@ impl BufferSnapshot {
where where
D: TextDimension, D: TextDimension,
{ {
if *anchor == Anchor::MIN { self.summaries_for_anchors([anchor]).next().unwrap()
D::zero(&())
} else if *anchor == Anchor::MAX {
D::from_text_summary(&self.visible_text.summary())
} else {
let anchor_key = InsertionFragmentKey {
timestamp: anchor.timestamp,
split_offset: anchor.offset,
};
let mut insertion_cursor = self.insertions.cursor::<InsertionFragmentKey>(&());
insertion_cursor.seek(&anchor_key, anchor.bias, &());
if let Some(insertion) = insertion_cursor.item() {
let comparison = sum_tree::KeyedItem::key(insertion).cmp(&anchor_key);
if comparison == Ordering::Greater
|| (anchor.bias == Bias::Left
&& comparison == Ordering::Equal
&& anchor.offset > 0)
{
insertion_cursor.prev(&());
}
} else {
insertion_cursor.prev(&());
}
let Some(insertion) = insertion_cursor
.item()
.filter(|insertion| insertion.timestamp == anchor.timestamp)
else {
panic!(
"invalid anchor {:?}. buffer id: {}, version: {:?}",
anchor, self.remote_id, self.version
);
};
let mut fragment_cursor = self.fragments.cursor::<(Option<&Locator>, usize)>(&None);
fragment_cursor.seek(&Some(&insertion.fragment_id), Bias::Left, &None);
let fragment = fragment_cursor.item().unwrap();
let mut fragment_offset = fragment_cursor.start().1;
if fragment.visible {
fragment_offset += anchor.offset - insertion.split_offset;
}
self.text_summary_for_range(0..fragment_offset)
}
} }
fn fragment_id_for_anchor(&self, anchor: &Anchor) -> &Locator { fn fragment_id_for_anchor(&self, anchor: &Anchor) -> &Locator {
if *anchor == Anchor::MIN { debug_assert_eq!(
Locator::min_ref() anchor.buffer_id(),
} else if *anchor == Anchor::MAX { self.remote_id,
Locator::max_ref() "anchor belongs to a different buffer"
} else { );
let anchor_key = InsertionFragmentKey {
timestamp: anchor.timestamp, match *anchor {
split_offset: anchor.offset, Anchor::Start { .. } => Locator::min_ref(),
}; Anchor::End { .. } => Locator::max_ref(),
let mut insertion_cursor = self.insertions.cursor::<InsertionFragmentKey>(&()); Anchor::Character {
insertion_cursor.seek(&anchor_key, anchor.bias, &()); insertion_id,
if let Some(insertion) = insertion_cursor.item() { offset,
let comparison = sum_tree::KeyedItem::key(insertion).cmp(&anchor_key); bias,
if comparison == Ordering::Greater ..
|| (anchor.bias == Bias::Left } => {
&& comparison == Ordering::Equal let anchor_key = InsertionFragmentKey {
&& anchor.offset > 0) timestamp: insertion_id,
{ split_offset: offset,
};
let mut insertion_cursor = self.insertions.cursor::<InsertionFragmentKey>(&());
insertion_cursor.seek(&anchor_key, bias, &());
if let Some(insertion) = insertion_cursor.item() {
let comparison = sum_tree::KeyedItem::key(insertion).cmp(&anchor_key);
if comparison == Ordering::Greater
|| (bias == Bias::Left && comparison == Ordering::Equal && offset > 0)
{
insertion_cursor.prev(&());
}
} else {
insertion_cursor.prev(&()); insertion_cursor.prev(&());
} }
} else {
insertion_cursor.prev(&()); let Some(insertion) = insertion_cursor.item().filter(|insertion| {
if cfg!(debug_assertions) {
insertion.timestamp == insertion_id
} else {
true
}
}) else {
panic!(
"invalid anchor {:?}. buffer id: {}, version: {:?}",
anchor, self.remote_id, self.version
);
};
&insertion.fragment_id
} }
let Some(insertion) = insertion_cursor.item().filter(|insertion| {
if cfg!(debug_assertions) {
insertion.timestamp == anchor.timestamp
} else {
true
}
}) else {
panic!(
"invalid anchor {:?}. buffer id: {}, version: {:?}",
anchor, self.remote_id, self.version
);
};
&insertion.fragment_id
} }
} }
@@ -2272,27 +2259,33 @@ impl BufferSnapshot {
fn anchor_at_offset(&self, offset: usize, bias: Bias) -> Anchor { fn anchor_at_offset(&self, offset: usize, bias: Bias) -> Anchor {
if bias == Bias::Left && offset == 0 { if bias == Bias::Left && offset == 0 {
Anchor::MIN self.min_anchor()
} else if bias == Bias::Right && offset == self.len() { } else if bias == Bias::Right && offset == self.len() {
Anchor::MAX self.max_anchor()
} else { } else {
let mut fragment_cursor = self.fragments.cursor::<usize>(&None); let mut fragment_cursor = self.fragments.cursor::<usize>(&None);
fragment_cursor.seek(&offset, bias, &None); fragment_cursor.seek(&offset, bias, &None);
let fragment = fragment_cursor.item().unwrap(); let fragment = fragment_cursor.item().unwrap();
let overshoot = offset - *fragment_cursor.start(); let overshoot = offset - *fragment_cursor.start();
Anchor { Anchor::Character {
timestamp: fragment.timestamp, insertion_id: fragment.timestamp,
offset: fragment.insertion_offset + overshoot, offset: fragment.insertion_offset + overshoot,
bias, bias,
buffer_id: Some(self.remote_id), buffer_id: self.remote_id,
} }
} }
} }
pub fn can_resolve(&self, anchor: &Anchor) -> bool { pub fn can_resolve(&self, anchor: &Anchor) -> bool {
*anchor == Anchor::MIN match *anchor {
|| *anchor == Anchor::MAX Anchor::Start { buffer_id } => self.remote_id == buffer_id,
|| (Some(self.remote_id) == anchor.buffer_id && self.version.observed(anchor.timestamp)) Anchor::End { buffer_id } => self.remote_id == buffer_id,
Anchor::Character {
buffer_id,
insertion_id,
..
} => self.remote_id == buffer_id && self.version.observed(insertion_id),
}
} }
pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize { pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
@@ -2318,7 +2311,7 @@ impl BufferSnapshot {
where where
D: TextDimension + Ord, D: TextDimension + Ord,
{ {
self.edits_since_in_range(since, Anchor::MIN..Anchor::MAX) self.edits_since_in_range(since, self.min_anchor()..self.max_anchor())
} }
pub fn anchored_edits_since<'a, D>( pub fn anchored_edits_since<'a, D>(
@@ -2328,7 +2321,7 @@ impl BufferSnapshot {
where where
D: TextDimension + Ord, D: TextDimension + Ord,
{ {
self.anchored_edits_since_in_range(since, Anchor::MIN..Anchor::MAX) self.anchored_edits_since_in_range(since, self.min_anchor()..self.max_anchor())
} }
pub fn edits_since_in_range<'a, D>( pub fn edits_since_in_range<'a, D>(
@@ -2366,10 +2359,20 @@ impl BufferSnapshot {
let start_fragment_id = self.fragment_id_for_anchor(&range.start); let start_fragment_id = self.fragment_id_for_anchor(&range.start);
cursor.seek(&Some(start_fragment_id), Bias::Left, &None); cursor.seek(&Some(start_fragment_id), Bias::Left, &None);
let start_fragment_offset = if let Anchor::Character { offset, .. } = range.start {
offset
} else {
0
};
let mut visible_start = cursor.start().1.visible; let mut visible_start = cursor.start().1.visible;
let mut deleted_start = cursor.start().1.deleted; let mut deleted_start = cursor.start().1.deleted;
if let Some(fragment) = cursor.item() { if let Some(fragment) = cursor.item() {
let overshoot = range.start.offset - fragment.insertion_offset; let overshoot = if let Anchor::Character { offset, .. } = range.start {
offset - fragment.insertion_offset
} else {
0
};
if fragment.visible { if fragment.visible {
visible_start += overshoot; visible_start += overshoot;
} else { } else {
@@ -2377,6 +2380,11 @@ impl BufferSnapshot {
} }
} }
let end_fragment_id = self.fragment_id_for_anchor(&range.end); let end_fragment_id = self.fragment_id_for_anchor(&range.end);
let end_fragment_offset = if let Anchor::Character { offset, .. } = range.end {
offset
} else {
0
};
Edits { Edits {
visible_cursor: self.visible_text.cursor(visible_start), visible_cursor: self.visible_text.cursor(visible_start),
@@ -2386,7 +2394,8 @@ impl BufferSnapshot {
since, since,
old_end: D::zero(&()), old_end: D::zero(&()),
new_end: D::zero(&()), new_end: D::zero(&()),
range: (start_fragment_id, range.start.offset)..(end_fragment_id, range.end.offset), range: (start_fragment_id, start_fragment_offset)
..(end_fragment_id, end_fragment_offset),
buffer_id: self.remote_id, buffer_id: self.remote_id,
} }
} }
@@ -2516,17 +2525,17 @@ impl<'a, D: TextDimension + Ord, F: FnMut(&FragmentSummary) -> bool> Iterator fo
break; break;
} }
let start_anchor = Anchor { let start_anchor = Anchor::Character {
timestamp: fragment.timestamp, insertion_id: fragment.timestamp,
offset: fragment.insertion_offset, offset: fragment.insertion_offset,
bias: Bias::Right, bias: Bias::Right,
buffer_id: Some(self.buffer_id), buffer_id: self.buffer_id,
}; };
let end_anchor = Anchor { let end_anchor = Anchor::Character {
timestamp: fragment.timestamp, insertion_id: fragment.timestamp,
offset: fragment.insertion_offset + fragment.len, offset: fragment.insertion_offset + fragment.len,
bias: Bias::Left, bias: Bias::Left,
buffer_id: Some(self.buffer_id), buffer_id: self.buffer_id,
}; };
if !fragment.was_visible(self.since, self.undos) && fragment.visible { if !fragment.was_visible(self.since, self.undos) && fragment.visible {