Compare commits
43 Commits
telemetry-
...
overhaul-m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15abdc0e61 | ||
|
|
45b806f236 | ||
|
|
7c988d0e66 | ||
|
|
3d61cee893 | ||
|
|
0bb7477aa1 | ||
|
|
5e1395cdc5 | ||
|
|
9b069903a7 | ||
|
|
b53c812da4 | ||
|
|
03ece03628 | ||
|
|
784b5ea8bb | ||
|
|
429f1b7f72 | ||
|
|
088380b9b2 | ||
|
|
c12b1ff3e6 | ||
|
|
2de9a2fc1d | ||
|
|
51c1710f80 | ||
|
|
c49a8df756 | ||
|
|
da325c70c2 | ||
|
|
55cc715637 | ||
|
|
f5db7a4ee5 | ||
|
|
4b31d1b47e | ||
|
|
cc4ba8d035 | ||
|
|
6da51e2443 | ||
|
|
957010d068 | ||
|
|
24829054c5 | ||
|
|
b90f23b10c | ||
|
|
9dedaba067 | ||
|
|
e6e2f45b21 | ||
|
|
12744f84f9 | ||
|
|
a787fedac0 | ||
|
|
1e1b36537a | ||
|
|
e0e9656b2b | ||
|
|
14815d0e80 | ||
|
|
cb5720f252 | ||
|
|
014d792be2 | ||
|
|
a67789d6d7 | ||
|
|
fb0cebd3d1 | ||
|
|
e0e39bf2c7 | ||
|
|
32d3074bbb | ||
|
|
d55b61a10c | ||
|
|
e192aefed3 | ||
|
|
479ff87909 | ||
|
|
10b452fc25 | ||
|
|
bcce7b7f62 |
26
Cargo.lock
generated
26
Cargo.lock
generated
@@ -7065,6 +7065,32 @@ dependencies = [
|
||||
"util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multi_buffer2"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clock",
|
||||
"collections",
|
||||
"ctor",
|
||||
"env_logger",
|
||||
"futures 0.3.30",
|
||||
"gpui",
|
||||
"itertools 0.13.0",
|
||||
"language",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"rand 0.8.5",
|
||||
"rpc",
|
||||
"serde",
|
||||
"settings",
|
||||
"smallvec",
|
||||
"sum_tree",
|
||||
"text",
|
||||
"theme",
|
||||
"util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.8.3"
|
||||
|
||||
@@ -67,6 +67,7 @@ members = [
|
||||
"crates/media",
|
||||
"crates/menu",
|
||||
"crates/multi_buffer",
|
||||
"crates/multi_buffer2",
|
||||
"crates/node_runtime",
|
||||
"crates/notifications",
|
||||
"crates/ollama",
|
||||
|
||||
@@ -599,7 +599,7 @@ impl Context {
|
||||
});
|
||||
let message = MessageAnchor {
|
||||
id: first_message_id,
|
||||
start: language::Anchor::MIN,
|
||||
start: this.buffer.read(cx).min_anchor(),
|
||||
};
|
||||
this.messages_metadata.insert(
|
||||
first_message_id,
|
||||
@@ -862,11 +862,9 @@ impl Context {
|
||||
}
|
||||
|
||||
match op {
|
||||
ContextOperation::InsertMessage { anchor, .. } => self
|
||||
.buffer
|
||||
.read(cx)
|
||||
.version
|
||||
.observed(anchor.start.timestamp),
|
||||
ContextOperation::InsertMessage { anchor, .. } => {
|
||||
self.buffer.read(cx).can_resolve(&anchor.start)
|
||||
}
|
||||
ContextOperation::UpdateMessage { message_id, .. } => {
|
||||
self.messages_metadata.contains_key(message_id)
|
||||
}
|
||||
@@ -876,20 +874,12 @@ impl Context {
|
||||
sections,
|
||||
..
|
||||
} => {
|
||||
let version = &self.buffer.read(cx).version;
|
||||
let buffer = self.buffer.read(cx);
|
||||
sections
|
||||
.iter()
|
||||
.map(|section| §ion.range)
|
||||
.chain([output_range])
|
||||
.all(|range| {
|
||||
let observed_start = range.start == language::Anchor::MIN
|
||||
|| range.start == language::Anchor::MAX
|
||||
|| version.observed(range.start.timestamp);
|
||||
let observed_end = range.end == language::Anchor::MIN
|
||||
|| range.end == language::Anchor::MAX
|
||||
|| version.observed(range.end.timestamp);
|
||||
observed_start && observed_end
|
||||
})
|
||||
.all(|range| buffer.can_resolve(&range.start) && buffer.can_resolve(&range.end))
|
||||
}
|
||||
ContextOperation::BufferOperation(_) => {
|
||||
panic!("buffer operations should always be applied")
|
||||
@@ -1563,7 +1553,7 @@ impl Context {
|
||||
}
|
||||
|
||||
if let Some(mut pending_step) = pending_step {
|
||||
pending_step.range.end = text::Anchor::MAX;
|
||||
pending_step.range.end = buffer.max_anchor();
|
||||
new_steps.push(pending_step);
|
||||
}
|
||||
|
||||
@@ -2707,7 +2697,7 @@ impl Context {
|
||||
messages.next();
|
||||
}
|
||||
}
|
||||
let message_end_anchor = message_end.unwrap_or(language::Anchor::MAX);
|
||||
let message_end_anchor = message_end.unwrap_or(buffer.max_anchor());
|
||||
let message_end = message_end_anchor.to_offset(buffer);
|
||||
|
||||
return Some(Message {
|
||||
@@ -2932,6 +2922,7 @@ impl SavedContext {
|
||||
buffer: &Model<Buffer>,
|
||||
cx: &mut ModelContext<Context>,
|
||||
) -> Vec<ContextOperation> {
|
||||
let buffer = buffer.read(cx);
|
||||
let mut operations = Vec::new();
|
||||
let mut version = clock::Global::new();
|
||||
let mut next_timestamp = clock::Lamport::new(ReplicaId::default());
|
||||
@@ -2944,7 +2935,7 @@ impl SavedContext {
|
||||
operations.push(ContextOperation::InsertMessage {
|
||||
anchor: MessageAnchor {
|
||||
id: message.id,
|
||||
start: buffer.read(cx).anchor_before(message.start),
|
||||
start: buffer.anchor_before(message.start),
|
||||
},
|
||||
metadata: MessageMetadata {
|
||||
role: message.metadata.role,
|
||||
@@ -2977,19 +2968,16 @@ impl SavedContext {
|
||||
let timestamp = next_timestamp.tick();
|
||||
operations.push(ContextOperation::SlashCommandFinished {
|
||||
id: SlashCommandId(timestamp),
|
||||
output_range: language::Anchor::MIN..language::Anchor::MAX,
|
||||
output_range: buffer.min_anchor()..buffer.max_anchor(),
|
||||
sections: self
|
||||
.slash_command_output_sections
|
||||
.into_iter()
|
||||
.map(|section| {
|
||||
let buffer = buffer.read(cx);
|
||||
SlashCommandOutputSection {
|
||||
range: buffer.anchor_after(section.range.start)
|
||||
..buffer.anchor_before(section.range.end),
|
||||
icon: section.icon,
|
||||
label: section.label,
|
||||
metadata: section.metadata,
|
||||
}
|
||||
.map(|section| SlashCommandOutputSection {
|
||||
range: buffer.anchor_after(section.range.start)
|
||||
..buffer.anchor_before(section.range.end),
|
||||
icon: section.icon,
|
||||
label: section.label,
|
||||
metadata: section.metadata,
|
||||
})
|
||||
.collect(),
|
||||
version: version.clone(),
|
||||
|
||||
@@ -64,14 +64,15 @@ pub enum WorkflowSuggestion {
|
||||
|
||||
impl WorkflowSuggestion {
|
||||
pub fn range(&self) -> Range<language::Anchor> {
|
||||
match self {
|
||||
Self::Update { range, .. } => range.clone(),
|
||||
Self::CreateFile { .. } => language::Anchor::MIN..language::Anchor::MAX,
|
||||
Self::InsertBefore { position, .. } | Self::InsertAfter { position, .. } => {
|
||||
*position..*position
|
||||
}
|
||||
Self::Delete { range, .. } => range.clone(),
|
||||
}
|
||||
todo!()
|
||||
// match self {
|
||||
// Self::Update { range, .. } => range.clone(),
|
||||
// Self::CreateFile { .. } => language::Anchor::MIN..language::Anchor::MAX,
|
||||
// Self::InsertBefore { position, .. } | Self::InsertAfter { position, .. } => {
|
||||
// *position..*position
|
||||
// }
|
||||
// Self::Delete { range, .. } => range.clone(),
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn description(&self) -> Option<&str> {
|
||||
|
||||
@@ -1198,7 +1198,7 @@ async fn test_share_project(
|
||||
buffer_a.read_with(cx_a, |buffer, _| {
|
||||
buffer
|
||||
.snapshot()
|
||||
.selections_in_range(text::Anchor::MIN..text::Anchor::MAX, false)
|
||||
.selections_in_range(buffer.min_anchor()..buffer.max_anchor(), false)
|
||||
.count()
|
||||
== 1
|
||||
});
|
||||
@@ -1237,7 +1237,7 @@ async fn test_share_project(
|
||||
buffer_a.read_with(cx_a, |buffer, _| {
|
||||
buffer
|
||||
.snapshot()
|
||||
.selections_in_range(text::Anchor::MIN..text::Anchor::MAX, false)
|
||||
.selections_in_range(buffer.min_anchor()..buffer.max_anchor(), false)
|
||||
.count()
|
||||
== 0
|
||||
});
|
||||
|
||||
@@ -429,7 +429,7 @@ impl ProjectDiagnosticsEditor {
|
||||
prev_excerpt_id = excerpt_id;
|
||||
first_excerpt_id.get_or_insert(prev_excerpt_id);
|
||||
group_state.excerpts.push(excerpt_id);
|
||||
let header_position = (excerpt_id, language::Anchor::MIN);
|
||||
let header_position = (excerpt_id, snapshot.min_anchor());
|
||||
|
||||
if is_first_excerpt_for_group {
|
||||
is_first_excerpt_for_group = false;
|
||||
|
||||
@@ -1194,7 +1194,7 @@ mod tests {
|
||||
use rand::prelude::*;
|
||||
use settings::SettingsStore;
|
||||
use std::{cmp::Reverse, env, sync::Arc};
|
||||
use text::Patch;
|
||||
use text::{BufferId, Patch};
|
||||
use util::post_inc;
|
||||
|
||||
#[test]
|
||||
@@ -1205,7 +1205,9 @@ mod tests {
|
||||
Anchor::min(),
|
||||
&InlayHint {
|
||||
label: InlayHintLabel::String("a".to_string()),
|
||||
position: text::Anchor::default(),
|
||||
position: text::Anchor::Start {
|
||||
buffer_id: BufferId::new(1).unwrap()
|
||||
},
|
||||
padding_left: false,
|
||||
padding_right: false,
|
||||
tooltip: None,
|
||||
@@ -1225,7 +1227,9 @@ mod tests {
|
||||
Anchor::min(),
|
||||
&InlayHint {
|
||||
label: InlayHintLabel::String("a".to_string()),
|
||||
position: text::Anchor::default(),
|
||||
position: text::Anchor::Start {
|
||||
buffer_id: BufferId::new(1).unwrap()
|
||||
},
|
||||
padding_left: true,
|
||||
padding_right: true,
|
||||
tooltip: None,
|
||||
@@ -1245,7 +1249,9 @@ mod tests {
|
||||
Anchor::min(),
|
||||
&InlayHint {
|
||||
label: InlayHintLabel::String(" a ".to_string()),
|
||||
position: text::Anchor::default(),
|
||||
position: text::Anchor::Start {
|
||||
buffer_id: BufferId::new(1).unwrap()
|
||||
},
|
||||
padding_left: false,
|
||||
padding_right: false,
|
||||
tooltip: None,
|
||||
@@ -1265,7 +1271,9 @@ mod tests {
|
||||
Anchor::min(),
|
||||
&InlayHint {
|
||||
label: InlayHintLabel::String(" a ".to_string()),
|
||||
position: text::Anchor::default(),
|
||||
position: text::Anchor::Start {
|
||||
buffer_id: BufferId::new(1).unwrap()
|
||||
},
|
||||
padding_left: true,
|
||||
padding_right: true,
|
||||
tooltip: None,
|
||||
|
||||
@@ -3119,59 +3119,60 @@ impl Editor {
|
||||
|
||||
fn linked_editing_ranges_for(
|
||||
&self,
|
||||
selection: Range<text::Anchor>,
|
||||
cx: &AppContext,
|
||||
_selection: Range<text::Anchor>,
|
||||
_cx: &AppContext,
|
||||
) -> Option<HashMap<Model<Buffer>, Vec<Range<text::Anchor>>>> {
|
||||
if self.linked_edit_ranges.is_empty() {
|
||||
return None;
|
||||
}
|
||||
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;
|
||||
}
|
||||
let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
self.linked_edit_ranges
|
||||
.get(end_buffer_id, selection.start..selection.end, &snapshot)
|
||||
.map(|ranges| (ranges, snapshot, buffer))
|
||||
})?;
|
||||
use text::ToOffset as TO;
|
||||
// find offset from the start of current range to current cursor position
|
||||
let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
|
||||
todo!()
|
||||
// if self.linked_edit_ranges.is_empty() {
|
||||
// return None;
|
||||
// }
|
||||
// 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;
|
||||
// }
|
||||
// let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
|
||||
// let snapshot = buffer.read(cx).snapshot();
|
||||
// self.linked_edit_ranges
|
||||
// .get(end_buffer_id, selection.start..selection.end, &snapshot)
|
||||
// .map(|ranges| (ranges, snapshot, buffer))
|
||||
// })?;
|
||||
// use text::ToOffset as TO;
|
||||
// // find offset from the start of current range to current cursor position
|
||||
// let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
|
||||
|
||||
let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
|
||||
let start_difference = start_offset - start_byte_offset;
|
||||
let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
|
||||
let end_difference = end_offset - start_byte_offset;
|
||||
// Current range has associated linked ranges.
|
||||
let mut linked_edits = HashMap::<_, Vec<_>>::default();
|
||||
for range in linked_ranges.iter() {
|
||||
let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
|
||||
let end_offset = start_offset + end_difference;
|
||||
let start_offset = start_offset + start_difference;
|
||||
if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
|
||||
continue;
|
||||
}
|
||||
if self.selections.disjoint_anchor_ranges().iter().any(|s| {
|
||||
if s.start.buffer_id != selection.start.buffer_id
|
||||
|| s.end.buffer_id != selection.end.buffer_id
|
||||
{
|
||||
return false;
|
||||
}
|
||||
TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
|
||||
&& TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
|
||||
}) {
|
||||
continue;
|
||||
}
|
||||
let start = buffer_snapshot.anchor_after(start_offset);
|
||||
let end = buffer_snapshot.anchor_after(end_offset);
|
||||
linked_edits
|
||||
.entry(buffer.clone())
|
||||
.or_default()
|
||||
.push(start..end);
|
||||
}
|
||||
Some(linked_edits)
|
||||
// let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
|
||||
// let start_difference = start_offset - start_byte_offset;
|
||||
// let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
|
||||
// let end_difference = end_offset - start_byte_offset;
|
||||
// // Current range has associated linked ranges.
|
||||
// let mut linked_edits = HashMap::<_, Vec<_>>::default();
|
||||
// for range in linked_ranges.iter() {
|
||||
// let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
|
||||
// let end_offset = start_offset + end_difference;
|
||||
// let start_offset = start_offset + start_difference;
|
||||
// if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
|
||||
// continue;
|
||||
// }
|
||||
// if self.selections.disjoint_anchor_ranges().iter().any(|s| {
|
||||
// if s.start.buffer_id != selection.start.buffer_id
|
||||
// || s.end.buffer_id != selection.end.buffer_id
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
|
||||
// && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
|
||||
// }) {
|
||||
// continue;
|
||||
// }
|
||||
// let start = buffer_snapshot.anchor_after(start_offset);
|
||||
// let end = buffer_snapshot.anchor_after(end_offset);
|
||||
// linked_edits
|
||||
// .entry(buffer.clone())
|
||||
// .or_default()
|
||||
// .push(start..end);
|
||||
// }
|
||||
// Some(linked_edits)
|
||||
}
|
||||
|
||||
pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
|
||||
@@ -5640,7 +5641,7 @@ impl Editor {
|
||||
for selection in selections.iter() {
|
||||
let selection_start = snapshot.anchor_before(selection.start).text_anchor;
|
||||
let selection_end = snapshot.anchor_after(selection.end).text_anchor;
|
||||
if selection_start.buffer_id != selection_end.buffer_id {
|
||||
if selection_start.buffer_id() != selection_end.buffer_id() {
|
||||
continue;
|
||||
}
|
||||
if let Some(ranges) =
|
||||
@@ -11657,13 +11658,14 @@ impl Editor {
|
||||
let start = highlight.range.start.to_display_point(&snapshot);
|
||||
let end = highlight.range.end.to_display_point(&snapshot);
|
||||
let start_row = start.row().0;
|
||||
let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
|
||||
&& end.column() == 0
|
||||
{
|
||||
end.row().0.saturating_sub(1)
|
||||
} else {
|
||||
end.row().0
|
||||
};
|
||||
let end_row =
|
||||
if !matches!(highlight.range.end.text_anchor, text::Anchor::End { .. })
|
||||
&& end.column() == 0
|
||||
{
|
||||
end.row().0.saturating_sub(1)
|
||||
} else {
|
||||
end.row().0
|
||||
};
|
||||
for row in start_row..=end_row {
|
||||
let used_index =
|
||||
used_highlight_orders.entry(row).or_insert(highlight.index);
|
||||
@@ -12967,7 +12969,7 @@ fn snippet_completions(
|
||||
return vec![];
|
||||
}
|
||||
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(snapshot.min_anchor()..buffer_position);
|
||||
|
||||
let mut lines = chunks.lines();
|
||||
let Some(line_at) = lines.next().filter(|line| !line.is_empty()) else {
|
||||
|
||||
@@ -738,7 +738,12 @@ async fn test_navigation_history(cx: &mut TestAppContext) {
|
||||
|
||||
// Ensure we don't panic when navigation data contains invalid anchors *and* points.
|
||||
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::Character {
|
||||
buffer_id: invalid_anchor.text_anchor.buffer_id(),
|
||||
insertion_id: clock::Lamport::MAX,
|
||||
offset: 42,
|
||||
bias: Bias::Left,
|
||||
};
|
||||
let invalid_point = Point::new(9999, 0);
|
||||
editor.navigate(
|
||||
Box::new(NavigationData {
|
||||
|
||||
@@ -169,65 +169,66 @@ impl TasksForRanges {
|
||||
|
||||
fn remove_cached_ranges_from_query(
|
||||
&mut self,
|
||||
buffer_snapshot: &BufferSnapshot,
|
||||
query_range: Range<language::Anchor>,
|
||||
_buffer_snapshot: &BufferSnapshot,
|
||||
_query_range: Range<language::Anchor>,
|
||||
) -> Vec<Range<language::Anchor>> {
|
||||
let mut ranges_to_query = Vec::new();
|
||||
let mut latest_cached_range = None::<&mut Range<language::Anchor>>;
|
||||
for cached_range in self
|
||||
.sorted_ranges
|
||||
.iter_mut()
|
||||
.skip_while(|cached_range| {
|
||||
cached_range
|
||||
.end
|
||||
.cmp(&query_range.start, buffer_snapshot)
|
||||
.is_lt()
|
||||
})
|
||||
.take_while(|cached_range| {
|
||||
cached_range
|
||||
.start
|
||||
.cmp(&query_range.end, buffer_snapshot)
|
||||
.is_le()
|
||||
})
|
||||
{
|
||||
match latest_cached_range {
|
||||
Some(latest_cached_range) => {
|
||||
if latest_cached_range.end.offset.saturating_add(1) < cached_range.start.offset
|
||||
{
|
||||
ranges_to_query.push(latest_cached_range.end..cached_range.start);
|
||||
cached_range.start = latest_cached_range.end;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if query_range
|
||||
.start
|
||||
.cmp(&cached_range.start, buffer_snapshot)
|
||||
.is_lt()
|
||||
{
|
||||
ranges_to_query.push(query_range.start..cached_range.start);
|
||||
cached_range.start = query_range.start;
|
||||
}
|
||||
}
|
||||
}
|
||||
latest_cached_range = Some(cached_range);
|
||||
}
|
||||
todo!()
|
||||
// let mut ranges_to_query = Vec::new();
|
||||
// let mut latest_cached_range = None::<&mut Range<language::Anchor>>;
|
||||
// for cached_range in self
|
||||
// .sorted_ranges
|
||||
// .iter_mut()
|
||||
// .skip_while(|cached_range| {
|
||||
// cached_range
|
||||
// .end
|
||||
// .cmp(&query_range.start, buffer_snapshot)
|
||||
// .is_lt()
|
||||
// })
|
||||
// .take_while(|cached_range| {
|
||||
// cached_range
|
||||
// .start
|
||||
// .cmp(&query_range.end, buffer_snapshot)
|
||||
// .is_le()
|
||||
// })
|
||||
// {
|
||||
// match latest_cached_range {
|
||||
// Some(latest_cached_range) => {
|
||||
// if latest_cached_range.end.offset.saturating_add(1) < cached_range.start.offset
|
||||
// {
|
||||
// ranges_to_query.push(latest_cached_range.end..cached_range.start);
|
||||
// cached_range.start = latest_cached_range.end;
|
||||
// }
|
||||
// }
|
||||
// None => {
|
||||
// if query_range
|
||||
// .start
|
||||
// .cmp(&cached_range.start, buffer_snapshot)
|
||||
// .is_lt()
|
||||
// {
|
||||
// ranges_to_query.push(query_range.start..cached_range.start);
|
||||
// cached_range.start = query_range.start;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// latest_cached_range = Some(cached_range);
|
||||
// }
|
||||
|
||||
match latest_cached_range {
|
||||
Some(latest_cached_range) => {
|
||||
if latest_cached_range.end.offset.saturating_add(1) < query_range.end.offset {
|
||||
ranges_to_query.push(latest_cached_range.end..query_range.end);
|
||||
latest_cached_range.end = query_range.end;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
ranges_to_query.push(query_range.clone());
|
||||
self.sorted_ranges.push(query_range);
|
||||
self.sorted_ranges
|
||||
.sort_by(|range_a, range_b| range_a.start.cmp(&range_b.start, buffer_snapshot));
|
||||
}
|
||||
}
|
||||
// match latest_cached_range {
|
||||
// Some(latest_cached_range) => {
|
||||
// if latest_cached_range.end.offset.saturating_add(1) < query_range.end.offset {
|
||||
// ranges_to_query.push(latest_cached_range.end..query_range.end);
|
||||
// latest_cached_range.end = query_range.end;
|
||||
// }
|
||||
// }
|
||||
// None => {
|
||||
// ranges_to_query.push(query_range.clone());
|
||||
// self.sorted_ranges.push(query_range);
|
||||
// self.sorted_ranges
|
||||
// .sort_by(|range_a, range_b| range_a.start.cmp(&range_b.start, buffer_snapshot));
|
||||
// }
|
||||
// }
|
||||
|
||||
ranges_to_query
|
||||
// ranges_to_query
|
||||
}
|
||||
|
||||
fn invalidate_range(&mut self, buffer: &BufferSnapshot, range: &Range<language::Anchor>) {
|
||||
|
||||
@@ -15,6 +15,7 @@ pub(super) struct LinkedEditingRanges(
|
||||
);
|
||||
|
||||
impl LinkedEditingRanges {
|
||||
#[allow(dead_code)] // todo!()
|
||||
pub(super) fn get(
|
||||
&self,
|
||||
id: BufferId,
|
||||
|
||||
@@ -41,7 +41,7 @@ impl sum_tree::Item for InternalDiffHunk {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DiffHunkSummary {
|
||||
buffer_range: Range<Anchor>,
|
||||
}
|
||||
@@ -49,8 +49,10 @@ pub struct DiffHunkSummary {
|
||||
impl sum_tree::Summary for DiffHunkSummary {
|
||||
type Context = text::BufferSnapshot;
|
||||
|
||||
fn zero(_cx: &Self::Context) -> Self {
|
||||
Default::default()
|
||||
fn zero(buffer: &Self::Context) -> Self {
|
||||
Self {
|
||||
buffer_range: buffer.min_anchor()..buffer.min_anchor(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_summary(&mut self, other: &Self, buffer: &Self::Context) {
|
||||
|
||||
@@ -835,7 +835,7 @@ impl Buffer {
|
||||
branch
|
||||
.edits_since_in_range::<usize>(
|
||||
&self.version,
|
||||
range.unwrap_or(Anchor::MIN..Anchor::MAX),
|
||||
range.unwrap_or(self.min_anchor()..self.max_anchor()),
|
||||
)
|
||||
.map(|edit| {
|
||||
(
|
||||
|
||||
@@ -2496,15 +2496,17 @@ fn assert_diff_hunks(
|
||||
cx: &mut TestAppContext,
|
||||
expected_hunks: &[(Range<u32>, &str, &str)],
|
||||
) {
|
||||
let (snapshot, diff_base) = buffer.read_with(cx, |buffer, _| {
|
||||
(buffer.snapshot(), buffer.diff_base().unwrap().to_string())
|
||||
buffer.read_with(cx, |buffer, _| {
|
||||
let snapshot = buffer.snapshot();
|
||||
let diff_base = buffer.diff_base().unwrap().to_string();
|
||||
assert_hunks(
|
||||
snapshot
|
||||
.git_diff_hunks_intersecting_range(snapshot.min_anchor()..snapshot.max_anchor()),
|
||||
&snapshot,
|
||||
&diff_base,
|
||||
expected_hunks,
|
||||
);
|
||||
});
|
||||
assert_hunks(
|
||||
snapshot.git_diff_hunks_intersecting_range(Anchor::MIN..Anchor::MAX),
|
||||
&snapshot,
|
||||
&diff_base,
|
||||
expected_hunks,
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test(iterations = 100)]
|
||||
@@ -2786,7 +2788,7 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
|
||||
for buffer in &buffers {
|
||||
let buffer = buffer.read(cx).snapshot();
|
||||
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<_>>()))
|
||||
.collect::<Vec<_>>();
|
||||
let expected_remote_selections = active_selections
|
||||
|
||||
@@ -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 {
|
||||
type Context = text::BufferSnapshot;
|
||||
|
||||
fn zero(_cx: &Self::Context) -> Self {
|
||||
Default::default()
|
||||
fn zero(buffer: &Self::Context) -> Self {
|
||||
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) {
|
||||
|
||||
@@ -6,7 +6,7 @@ use clock::ReplicaId;
|
||||
use lsp::{DiagnosticSeverity, LanguageServerId};
|
||||
use rpc::proto;
|
||||
use serde_json::Value;
|
||||
use std::{ops::Range, str::FromStr, sync::Arc};
|
||||
use std::{ops::Range, str::FromStr, sync::Arc, u32};
|
||||
use text::*;
|
||||
|
||||
pub use proto::{BufferState, Operation};
|
||||
@@ -221,15 +221,36 @@ pub fn serialize_diagnostics<'a>(
|
||||
|
||||
/// Serializes an [`Anchor`] to be sent over RPC.
|
||||
pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
|
||||
proto::Anchor {
|
||||
replica_id: anchor.timestamp.replica_id as u32,
|
||||
timestamp: anchor.timestamp.value,
|
||||
offset: anchor.offset as u64,
|
||||
bias: match anchor.bias {
|
||||
Bias::Left => proto::Bias::Left as i32,
|
||||
Bias::Right => proto::Bias::Right as i32,
|
||||
match *anchor {
|
||||
Anchor::Start { buffer_id } => proto::Anchor {
|
||||
replica_id: 0,
|
||||
timestamp: 0,
|
||||
offset: 0,
|
||||
bias: proto::Bias::Left 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.
|
||||
pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
|
||||
let buffer_id = if let Some(id) = anchor.buffer_id {
|
||||
Some(BufferId::new(id).ok()?)
|
||||
let buffer_id = BufferId::new(anchor.buffer_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 {
|
||||
None
|
||||
};
|
||||
Some(Anchor {
|
||||
timestamp: clock::Lamport {
|
||||
replica_id: anchor.replica_id as ReplicaId,
|
||||
value: anchor.timestamp,
|
||||
},
|
||||
offset: anchor.offset as usize,
|
||||
bias: match proto::Bias::from_i32(anchor.bias)? {
|
||||
proto::Bias::Left => Bias::Left,
|
||||
proto::Bias::Right => Bias::Right,
|
||||
},
|
||||
buffer_id,
|
||||
})
|
||||
Some(Anchor::Character {
|
||||
insertion_id: clock::Lamport {
|
||||
replica_id: anchor.replica_id as ReplicaId,
|
||||
value: anchor.timestamp,
|
||||
},
|
||||
offset: anchor.offset as usize,
|
||||
bias: match proto::Bias::from_i32(anchor.bias)? {
|
||||
proto::Bias::Left => Bias::Left,
|
||||
proto::Bias::Right => Bias::Right,
|
||||
},
|
||||
buffer_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a `[clock::Lamport`] timestamp for the given [`proto::Operation`].
|
||||
|
||||
@@ -303,7 +303,7 @@ impl SyntaxSnapshot {
|
||||
let slice = cursor.slice(
|
||||
&SyntaxLayerPosition {
|
||||
depth: depth + 1,
|
||||
range: Anchor::MIN..Anchor::MAX,
|
||||
range: text.min_anchor()..text.max_anchor(),
|
||||
language: None,
|
||||
},
|
||||
Bias::Left,
|
||||
@@ -459,7 +459,7 @@ impl SyntaxSnapshot {
|
||||
start_point: Point::zero().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,
|
||||
});
|
||||
|
||||
@@ -474,7 +474,7 @@ impl SyntaxSnapshot {
|
||||
} else {
|
||||
SyntaxLayerPosition {
|
||||
depth: max_depth + 1,
|
||||
range: Anchor::MAX..Anchor::MAX,
|
||||
range: text.max_anchor()..text.max_anchor(),
|
||||
language: None,
|
||||
}
|
||||
};
|
||||
@@ -485,7 +485,7 @@ impl SyntaxSnapshot {
|
||||
|
||||
let bounded_position = SyntaxLayerPositionBeforeChange {
|
||||
position: position.clone(),
|
||||
change: changed_regions.start_position(),
|
||||
change: changed_regions.start_position(text),
|
||||
};
|
||||
if bounded_position.cmp(cursor.start(), text).is_gt() {
|
||||
let slice = cursor.slice(&bounded_position, Bias::Left, text);
|
||||
@@ -1608,11 +1608,11 @@ impl ChangedRegion {
|
||||
}
|
||||
|
||||
impl ChangeRegionSet {
|
||||
fn start_position(&self) -> ChangeStartPosition {
|
||||
fn start_position(&self, text: &BufferSnapshot) -> ChangeStartPosition {
|
||||
self.0.first().map_or(
|
||||
ChangeStartPosition {
|
||||
depth: usize::MAX,
|
||||
position: Anchor::MAX,
|
||||
position: text.max_anchor(),
|
||||
},
|
||||
|region| ChangeStartPosition {
|
||||
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 {
|
||||
type Context = BufferSnapshot;
|
||||
|
||||
fn zero(_cx: &BufferSnapshot) -> Self {
|
||||
Default::default()
|
||||
fn zero(buffer: &BufferSnapshot) -> Self {
|
||||
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) {
|
||||
@@ -1686,7 +1680,7 @@ impl sum_tree::Summary for SyntaxLayerSummary {
|
||||
self.max_depth = other.max_depth;
|
||||
self.range = other.range.clone();
|
||||
} else {
|
||||
if self.range == (Anchor::MAX..Anchor::MAX) {
|
||||
if self.range == (buffer.max_anchor()..buffer.max_anchor()) {
|
||||
self.range.start = other.range.start;
|
||||
}
|
||||
if other.range.end.cmp(&self.range.end, buffer).is_gt() {
|
||||
|
||||
@@ -16,19 +16,21 @@ pub struct Anchor {
|
||||
|
||||
impl Anchor {
|
||||
pub fn min() -> Self {
|
||||
Self {
|
||||
buffer_id: None,
|
||||
excerpt_id: ExcerptId::min(),
|
||||
text_anchor: text::Anchor::MIN,
|
||||
}
|
||||
todo!()
|
||||
// Self {
|
||||
// buffer_id: None,
|
||||
// excerpt_id: ExcerptId::min(),
|
||||
// text_anchor: text::Anchor::MIN,
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn max() -> Self {
|
||||
Self {
|
||||
buffer_id: None,
|
||||
excerpt_id: ExcerptId::max(),
|
||||
text_anchor: text::Anchor::MAX,
|
||||
}
|
||||
todo!()
|
||||
// Self {
|
||||
// buffer_id: None,
|
||||
// excerpt_id: ExcerptId::max(),
|
||||
// text_anchor: text::Anchor::MAX,
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn cmp(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering {
|
||||
@@ -47,33 +49,36 @@ impl Anchor {
|
||||
}
|
||||
|
||||
pub fn bias(&self) -> Bias {
|
||||
self.text_anchor.bias
|
||||
todo!()
|
||||
// self.text_anchor.bias
|
||||
}
|
||||
|
||||
pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
|
||||
if self.text_anchor.bias != Bias::Left {
|
||||
if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
|
||||
return Self {
|
||||
buffer_id: self.buffer_id,
|
||||
excerpt_id: self.excerpt_id,
|
||||
text_anchor: self.text_anchor.bias_left(&excerpt.buffer),
|
||||
};
|
||||
}
|
||||
}
|
||||
*self
|
||||
pub fn bias_left(&self, _snapshot: &MultiBufferSnapshot) -> Anchor {
|
||||
todo!()
|
||||
// if self.text_anchor.bias != Bias::Left {
|
||||
// if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
|
||||
// return Self {
|
||||
// buffer_id: self.buffer_id,
|
||||
// excerpt_id: self.excerpt_id,
|
||||
// text_anchor: self.text_anchor.bias_left(&excerpt.buffer),
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// *self
|
||||
}
|
||||
|
||||
pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
|
||||
if self.text_anchor.bias != Bias::Right {
|
||||
if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
|
||||
return Self {
|
||||
buffer_id: self.buffer_id,
|
||||
excerpt_id: self.excerpt_id,
|
||||
text_anchor: self.text_anchor.bias_right(&excerpt.buffer),
|
||||
};
|
||||
}
|
||||
}
|
||||
*self
|
||||
pub fn bias_right(&self, _snapshot: &MultiBufferSnapshot) -> Anchor {
|
||||
todo!()
|
||||
// if self.text_anchor.bias != Bias::Right {
|
||||
// if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
|
||||
// return Self {
|
||||
// buffer_id: self.buffer_id,
|
||||
// excerpt_id: self.excerpt_id,
|
||||
// text_anchor: self.text_anchor.bias_right(&excerpt.buffer),
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// *self
|
||||
}
|
||||
|
||||
pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
|
||||
|
||||
@@ -437,19 +437,20 @@ impl MultiBuffer {
|
||||
self.capability == Capability::ReadOnly
|
||||
}
|
||||
|
||||
pub fn singleton(buffer: Model<Buffer>, cx: &mut ModelContext<Self>) -> Self {
|
||||
let mut this = Self::new(buffer.read(cx).capability());
|
||||
this.singleton = true;
|
||||
this.push_excerpts(
|
||||
buffer,
|
||||
[ExcerptRange {
|
||||
context: text::Anchor::MIN..text::Anchor::MAX,
|
||||
primary: None,
|
||||
}],
|
||||
cx,
|
||||
);
|
||||
this.snapshot.borrow_mut().singleton = true;
|
||||
this
|
||||
pub fn singleton(_buffer: Model<Buffer>, _cx: &mut ModelContext<Self>) -> Self {
|
||||
todo!()
|
||||
// let mut this = Self::new(buffer.read(cx).capability());
|
||||
// this.singleton = true;
|
||||
// this.push_excerpts(
|
||||
// buffer,
|
||||
// [ExcerptRange {
|
||||
// context: text::Anchor::MIN..text::Anchor::MAX,
|
||||
// primary: None,
|
||||
// }],
|
||||
// cx,
|
||||
// );
|
||||
// this.snapshot.borrow_mut().singleton = true;
|
||||
// this
|
||||
}
|
||||
|
||||
/// Returns an up-to-date snapshot of the MultiBuffer.
|
||||
@@ -3056,106 +3057,107 @@ impl MultiBufferSnapshot {
|
||||
summaries
|
||||
}
|
||||
|
||||
pub fn refresh_anchors<'a, I>(&'a self, anchors: I) -> Vec<(usize, Anchor, bool)>
|
||||
pub fn refresh_anchors<'a, I>(&'a self, _anchors: I) -> Vec<(usize, Anchor, bool)>
|
||||
where
|
||||
I: 'a + IntoIterator<Item = &'a Anchor>,
|
||||
{
|
||||
let mut anchors = anchors.into_iter().enumerate().peekable();
|
||||
let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
|
||||
cursor.next(&());
|
||||
todo!()
|
||||
// let mut anchors = anchors.into_iter().enumerate().peekable();
|
||||
// let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
|
||||
// cursor.next(&());
|
||||
|
||||
let mut result = Vec::new();
|
||||
// let mut result = Vec::new();
|
||||
|
||||
while let Some((_, anchor)) = anchors.peek() {
|
||||
let old_excerpt_id = anchor.excerpt_id;
|
||||
// while let Some((_, anchor)) = anchors.peek() {
|
||||
// let old_excerpt_id = anchor.excerpt_id;
|
||||
|
||||
// Find the location where this anchor's excerpt should be.
|
||||
let old_locator = self.excerpt_locator_for_id(old_excerpt_id);
|
||||
cursor.seek_forward(&Some(old_locator), Bias::Left, &());
|
||||
// // Find the location where this anchor's excerpt should be.
|
||||
// let old_locator = self.excerpt_locator_for_id(old_excerpt_id);
|
||||
// cursor.seek_forward(&Some(old_locator), Bias::Left, &());
|
||||
|
||||
if cursor.item().is_none() {
|
||||
cursor.next(&());
|
||||
}
|
||||
// if cursor.item().is_none() {
|
||||
// cursor.next(&());
|
||||
// }
|
||||
|
||||
let next_excerpt = cursor.item();
|
||||
let prev_excerpt = cursor.prev_item();
|
||||
// let next_excerpt = cursor.item();
|
||||
// let prev_excerpt = cursor.prev_item();
|
||||
|
||||
// Process all of the anchors for this excerpt.
|
||||
while let Some((_, anchor)) = anchors.peek() {
|
||||
if anchor.excerpt_id != old_excerpt_id {
|
||||
break;
|
||||
}
|
||||
let (anchor_ix, anchor) = anchors.next().unwrap();
|
||||
let mut anchor = *anchor;
|
||||
// // Process all of the anchors for this excerpt.
|
||||
// while let Some((_, anchor)) = anchors.peek() {
|
||||
// if anchor.excerpt_id != old_excerpt_id {
|
||||
// break;
|
||||
// }
|
||||
// let (anchor_ix, anchor) = anchors.next().unwrap();
|
||||
// let mut anchor = *anchor;
|
||||
|
||||
// Leave min and max anchors unchanged if invalid or
|
||||
// if the old excerpt still exists at this location
|
||||
let mut kept_position = next_excerpt
|
||||
.map_or(false, |e| e.id == old_excerpt_id && e.contains(&anchor))
|
||||
|| old_excerpt_id == ExcerptId::max()
|
||||
|| old_excerpt_id == ExcerptId::min();
|
||||
// // Leave min and max anchors unchanged if invalid or
|
||||
// // if the old excerpt still exists at this location
|
||||
// let mut kept_position = next_excerpt
|
||||
// .map_or(false, |e| e.id == old_excerpt_id && e.contains(&anchor))
|
||||
// || old_excerpt_id == ExcerptId::max()
|
||||
// || old_excerpt_id == ExcerptId::min();
|
||||
|
||||
// If the old excerpt no longer exists at this location, then attempt to
|
||||
// find an equivalent position for this anchor in an adjacent excerpt.
|
||||
if !kept_position {
|
||||
for excerpt in [next_excerpt, prev_excerpt].iter().filter_map(|e| *e) {
|
||||
if excerpt.contains(&anchor) {
|
||||
anchor.excerpt_id = excerpt.id;
|
||||
kept_position = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// // If the old excerpt no longer exists at this location, then attempt to
|
||||
// // find an equivalent position for this anchor in an adjacent excerpt.
|
||||
// if !kept_position {
|
||||
// for excerpt in [next_excerpt, prev_excerpt].iter().filter_map(|e| *e) {
|
||||
// if excerpt.contains(&anchor) {
|
||||
// anchor.excerpt_id = excerpt.id;
|
||||
// kept_position = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// If there's no adjacent excerpt that contains the anchor's position,
|
||||
// then report that the anchor has lost its position.
|
||||
if !kept_position {
|
||||
anchor = if let Some(excerpt) = next_excerpt {
|
||||
let mut text_anchor = excerpt
|
||||
.range
|
||||
.context
|
||||
.start
|
||||
.bias(anchor.text_anchor.bias, &excerpt.buffer);
|
||||
if text_anchor
|
||||
.cmp(&excerpt.range.context.end, &excerpt.buffer)
|
||||
.is_gt()
|
||||
{
|
||||
text_anchor = excerpt.range.context.end;
|
||||
}
|
||||
Anchor {
|
||||
buffer_id: Some(excerpt.buffer_id),
|
||||
excerpt_id: excerpt.id,
|
||||
text_anchor,
|
||||
}
|
||||
} else if let Some(excerpt) = prev_excerpt {
|
||||
let mut text_anchor = excerpt
|
||||
.range
|
||||
.context
|
||||
.end
|
||||
.bias(anchor.text_anchor.bias, &excerpt.buffer);
|
||||
if text_anchor
|
||||
.cmp(&excerpt.range.context.start, &excerpt.buffer)
|
||||
.is_lt()
|
||||
{
|
||||
text_anchor = excerpt.range.context.start;
|
||||
}
|
||||
Anchor {
|
||||
buffer_id: Some(excerpt.buffer_id),
|
||||
excerpt_id: excerpt.id,
|
||||
text_anchor,
|
||||
}
|
||||
} else if anchor.text_anchor.bias == Bias::Left {
|
||||
Anchor::min()
|
||||
} else {
|
||||
Anchor::max()
|
||||
};
|
||||
}
|
||||
// // If there's no adjacent excerpt that contains the anchor's position,
|
||||
// // then report that the anchor has lost its position.
|
||||
// if !kept_position {
|
||||
// anchor = if let Some(excerpt) = next_excerpt {
|
||||
// let mut text_anchor = excerpt
|
||||
// .range
|
||||
// .context
|
||||
// .start
|
||||
// .bias(anchor.text_anchor.bias, &excerpt.buffer);
|
||||
// if text_anchor
|
||||
// .cmp(&excerpt.range.context.end, &excerpt.buffer)
|
||||
// .is_gt()
|
||||
// {
|
||||
// text_anchor = excerpt.range.context.end;
|
||||
// }
|
||||
// Anchor {
|
||||
// buffer_id: Some(excerpt.buffer_id),
|
||||
// excerpt_id: excerpt.id,
|
||||
// text_anchor,
|
||||
// }
|
||||
// } else if let Some(excerpt) = prev_excerpt {
|
||||
// let mut text_anchor = excerpt
|
||||
// .range
|
||||
// .context
|
||||
// .end
|
||||
// .bias(anchor.text_anchor.bias, &excerpt.buffer);
|
||||
// if text_anchor
|
||||
// .cmp(&excerpt.range.context.start, &excerpt.buffer)
|
||||
// .is_lt()
|
||||
// {
|
||||
// text_anchor = excerpt.range.context.start;
|
||||
// }
|
||||
// Anchor {
|
||||
// buffer_id: Some(excerpt.buffer_id),
|
||||
// excerpt_id: excerpt.id,
|
||||
// text_anchor,
|
||||
// }
|
||||
// } else if anchor.text_anchor.bias == Bias::Left {
|
||||
// Anchor::min()
|
||||
// } else {
|
||||
// Anchor::max()
|
||||
// };
|
||||
// }
|
||||
|
||||
result.push((anchor_ix, anchor, kept_position));
|
||||
}
|
||||
}
|
||||
result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self));
|
||||
result
|
||||
// result.push((anchor_ix, anchor, kept_position));
|
||||
// }
|
||||
// }
|
||||
// result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self));
|
||||
// result
|
||||
}
|
||||
|
||||
pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
|
||||
|
||||
51
crates/multi_buffer2/Cargo.toml
Normal file
51
crates/multi_buffer2/Cargo.toml
Normal file
@@ -0,0 +1,51 @@
|
||||
[package]
|
||||
name = "multi_buffer2"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/multi_buffer2.rs"
|
||||
doctest = false
|
||||
|
||||
[features]
|
||||
test-support = [
|
||||
"text/test-support",
|
||||
"language/test-support",
|
||||
"gpui/test-support",
|
||||
"util/test-support",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
clock.workspace = true
|
||||
collections.workspace = true
|
||||
ctor.workspace = true
|
||||
env_logger.workspace = true
|
||||
futures.workspace = true
|
||||
gpui.workspace = true
|
||||
itertools.workspace = true
|
||||
language.workspace = true
|
||||
log.workspace = true
|
||||
parking_lot.workspace = true
|
||||
rand.workspace = true
|
||||
settings.workspace = true
|
||||
serde.workspace = true
|
||||
smallvec.workspace = true
|
||||
sum_tree.workspace = true
|
||||
text.workspace = true
|
||||
theme.workspace = true
|
||||
util.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
gpui = { workspace = true, features = ["test-support"] }
|
||||
language = { workspace = true, features = ["test-support"] }
|
||||
rand.workspace = true
|
||||
rpc = { workspace = true, features = ["test-support"] }
|
||||
settings = { workspace = true, features = ["test-support"] }
|
||||
text = { workspace = true, features = ["test-support"] }
|
||||
util = { workspace = true, features = ["test-support"] }
|
||||
1
crates/multi_buffer2/LICENSE-GPL
Symbolic link
1
crates/multi_buffer2/LICENSE-GPL
Symbolic link
@@ -0,0 +1 @@
|
||||
../../LICENSE-GPL
|
||||
1291
crates/multi_buffer2/src/multi_buffer2.rs
Normal file
1291
crates/multi_buffer2/src/multi_buffer2.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1451,8 +1451,9 @@ impl LspStore {
|
||||
|
||||
let actions = this
|
||||
.update(cx, move |this, cx| {
|
||||
let range = buffer.read(cx).min_anchor()..buffer.read(cx).max_anchor();
|
||||
let request = GetCodeActions {
|
||||
range: text::Anchor::MIN..text::Anchor::MAX,
|
||||
range,
|
||||
kinds: Some(code_actions),
|
||||
};
|
||||
let server = LanguageServerToQuery::Other(language_server.server_id());
|
||||
@@ -1769,9 +1770,7 @@ impl LspStore {
|
||||
});
|
||||
|
||||
buffer
|
||||
.update(&mut cx, |buffer, _| {
|
||||
buffer.wait_for_edits(Some(position.timestamp))
|
||||
})?
|
||||
.update(&mut cx, |buffer, _| buffer.wait_for_anchors(Some(position)))?
|
||||
.await?;
|
||||
this.update(&mut cx, |this, cx| {
|
||||
let position = position.to_point_utf16(buffer.read(cx));
|
||||
@@ -2417,7 +2416,7 @@ impl LspStore {
|
||||
cx.spawn(move |_, mut cx| async move {
|
||||
buffer_handle
|
||||
.update(&mut cx, |buffer, _| {
|
||||
buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
|
||||
buffer.wait_for_anchors(vec![range_start, range_end])
|
||||
})?
|
||||
.await
|
||||
.context("waiting for inlay hint request range edits")?;
|
||||
|
||||
@@ -576,7 +576,7 @@ async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) {
|
||||
DiagnosticSet::from_sorted_entries(
|
||||
vec![DiagnosticEntry {
|
||||
diagnostic: Default::default(),
|
||||
range: Anchor::MIN..Anchor::MAX,
|
||||
range: buffer.min_anchor()..buffer.max_anchor(),
|
||||
}],
|
||||
&buffer.snapshot(),
|
||||
),
|
||||
|
||||
@@ -6,43 +6,68 @@ use std::{cmp::Ordering, fmt::Debug, ops::Range};
|
||||
use sum_tree::Bias;
|
||||
|
||||
/// A timestamped position in a buffer
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Default)]
|
||||
pub struct Anchor {
|
||||
pub timestamp: clock::Lamport,
|
||||
/// The byte offset in the buffer
|
||||
pub offset: usize,
|
||||
/// Describes which character the anchor is biased towards
|
||||
pub bias: Bias,
|
||||
pub buffer_id: Option<BufferId>,
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
|
||||
pub enum Anchor {
|
||||
Start {
|
||||
buffer_id: BufferId,
|
||||
},
|
||||
End {
|
||||
buffer_id: BufferId,
|
||||
},
|
||||
Character {
|
||||
buffer_id: BufferId,
|
||||
insertion_id: clock::Lamport,
|
||||
offset: usize,
|
||||
bias: Bias,
|
||||
},
|
||||
}
|
||||
|
||||
impl Anchor {
|
||||
pub const MIN: Self = Self {
|
||||
timestamp: clock::Lamport::MIN,
|
||||
offset: usize::MIN,
|
||||
bias: Bias::Left,
|
||||
buffer_id: None,
|
||||
};
|
||||
|
||||
pub const MAX: Self = Self {
|
||||
timestamp: clock::Lamport::MAX,
|
||||
offset: usize::MAX,
|
||||
bias: Bias::Right,
|
||||
buffer_id: None,
|
||||
};
|
||||
pub fn buffer_id(&self) -> BufferId {
|
||||
match self {
|
||||
Anchor::Start { buffer_id } => *buffer_id,
|
||||
Anchor::End { buffer_id } => *buffer_id,
|
||||
Anchor::Character { buffer_id, .. } => *buffer_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cmp(&self, other: &Anchor, buffer: &BufferSnapshot) -> Ordering {
|
||||
let fragment_id_comparison = if self.timestamp == other.timestamp {
|
||||
Ordering::Equal
|
||||
} else {
|
||||
buffer
|
||||
.fragment_id_for_anchor(self)
|
||||
.cmp(buffer.fragment_id_for_anchor(other))
|
||||
};
|
||||
debug_assert_eq!(
|
||||
self.buffer_id(),
|
||||
other.buffer_id(),
|
||||
"anchors belong to different buffers"
|
||||
);
|
||||
|
||||
fragment_id_comparison
|
||||
.then_with(|| self.offset.cmp(&other.offset))
|
||||
.then_with(|| self.bias.cmp(&other.bias))
|
||||
match (self, other) {
|
||||
(Anchor::Start { .. }, Anchor::Start { .. }) => Ordering::Equal,
|
||||
(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 {
|
||||
@@ -70,18 +95,42 @@ impl Anchor {
|
||||
}
|
||||
|
||||
pub fn bias_left(&self, buffer: &BufferSnapshot) -> Anchor {
|
||||
if self.bias == Bias::Left {
|
||||
*self
|
||||
} else {
|
||||
buffer.anchor_before(self)
|
||||
match self {
|
||||
Anchor::Start { buffer_id } => Anchor::Start {
|
||||
buffer_id: *buffer_id,
|
||||
},
|
||||
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 {
|
||||
if self.bias == Bias::Right {
|
||||
*self
|
||||
} else {
|
||||
buffer.anchor_after(self)
|
||||
match self {
|
||||
Anchor::Start { .. } => buffer.anchor_after(0),
|
||||
Anchor::End { buffer_id } => Anchor::End {
|
||||
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.
|
||||
pub fn is_valid(&self, buffer: &BufferSnapshot) -> bool {
|
||||
if *self == Anchor::MIN || *self == Anchor::MAX {
|
||||
true
|
||||
} else if self.buffer_id != Some(buffer.remote_id) {
|
||||
false
|
||||
} else {
|
||||
let fragment_id = buffer.fragment_id_for_anchor(self);
|
||||
let mut fragment_cursor = buffer.fragments.cursor::<(Option<&Locator>, usize)>(&None);
|
||||
fragment_cursor.seek(&Some(fragment_id), Bias::Left, &None);
|
||||
fragment_cursor
|
||||
.item()
|
||||
.map_or(false, |fragment| fragment.visible)
|
||||
match self {
|
||||
Anchor::Start { buffer_id } | Anchor::End { buffer_id } => {
|
||||
*buffer_id == buffer.remote_id
|
||||
}
|
||||
Anchor::Character { buffer_id, .. } => {
|
||||
if *buffer_id == buffer.remote_id {
|
||||
let fragment_id = buffer.fragment_id_for_anchor(self);
|
||||
let mut fragment_cursor =
|
||||
buffer.fragments.cursor::<(Option<&Locator>, usize)>(&None);
|
||||
fragment_cursor.seek(&Some(fragment_id), Bias::Left, &None);
|
||||
fragment_cursor
|
||||
.item()
|
||||
.map_or(false, |fragment| fragment.visible)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1542,16 +1542,15 @@ impl Buffer {
|
||||
) -> impl 'static + Future<Output = Result<()>> {
|
||||
let mut futures = Vec::new();
|
||||
for anchor in anchors {
|
||||
if !self.version.observed(anchor.timestamp)
|
||||
&& anchor != Anchor::MAX
|
||||
&& anchor != Anchor::MIN
|
||||
{
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.edit_id_resolvers
|
||||
.entry(anchor.timestamp)
|
||||
.or_default()
|
||||
.push(tx);
|
||||
futures.push(rx);
|
||||
if let Anchor::Character { insertion_id, .. } = anchor {
|
||||
if !self.version.observed(insertion_id) {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.edit_id_resolvers
|
||||
.entry(insertion_id)
|
||||
.or_default()
|
||||
.push(tx);
|
||||
futures.push(rx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1928,6 +1927,18 @@ impl BufferSnapshot {
|
||||
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 {
|
||||
self.visible_text.max_point()
|
||||
}
|
||||
@@ -2129,41 +2140,50 @@ impl BufferSnapshot {
|
||||
let mut position = D::zero(&());
|
||||
|
||||
anchors.map(move |(anchor, payload)| {
|
||||
if *anchor == Anchor::MIN {
|
||||
return (D::zero(&()), payload);
|
||||
} else if *anchor == Anchor::MAX {
|
||||
return (D::from_text_summary(&self.visible_text.summary()), payload);
|
||||
}
|
||||
debug_assert_eq!(
|
||||
anchor.buffer_id(),
|
||||
self.remote_id,
|
||||
"anchor belongs to a different buffer"
|
||||
);
|
||||
|
||||
let anchor_key = InsertionFragmentKey {
|
||||
timestamp: anchor.timestamp,
|
||||
split_offset: anchor.offset,
|
||||
};
|
||||
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(&());
|
||||
match *anchor {
|
||||
Anchor::Start { .. } => (D::zero(&()), payload),
|
||||
Anchor::End { .. } => (D::from_text_summary(&self.visible_text.summary()), payload),
|
||||
Anchor::Character {
|
||||
insertion_id,
|
||||
offset,
|
||||
bias,
|
||||
..
|
||||
} => {
|
||||
let anchor_key = InsertionFragmentKey {
|
||||
timestamp: insertion_id,
|
||||
split_offset: offset,
|
||||
};
|
||||
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
|
||||
D: TextDimension,
|
||||
{
|
||||
if *anchor == Anchor::MIN {
|
||||
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)
|
||||
}
|
||||
self.summaries_for_anchors([anchor]).next().unwrap()
|
||||
}
|
||||
|
||||
fn fragment_id_for_anchor(&self, anchor: &Anchor) -> &Locator {
|
||||
if *anchor == Anchor::MIN {
|
||||
Locator::min_ref()
|
||||
} else if *anchor == Anchor::MAX {
|
||||
Locator::max_ref()
|
||||
} 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)
|
||||
{
|
||||
debug_assert_eq!(
|
||||
anchor.buffer_id(),
|
||||
self.remote_id,
|
||||
"anchor belongs to a different buffer"
|
||||
);
|
||||
|
||||
match *anchor {
|
||||
Anchor::Start { .. } => Locator::min_ref(),
|
||||
Anchor::End { .. } => Locator::max_ref(),
|
||||
Anchor::Character {
|
||||
insertion_id,
|
||||
offset,
|
||||
bias,
|
||||
..
|
||||
} => {
|
||||
let anchor_key = InsertionFragmentKey {
|
||||
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(&());
|
||||
}
|
||||
} 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 {
|
||||
if bias == Bias::Left && offset == 0 {
|
||||
Anchor::MIN
|
||||
self.min_anchor()
|
||||
} else if bias == Bias::Right && offset == self.len() {
|
||||
Anchor::MAX
|
||||
self.max_anchor()
|
||||
} else {
|
||||
let mut fragment_cursor = self.fragments.cursor::<usize>(&None);
|
||||
fragment_cursor.seek(&offset, bias, &None);
|
||||
let fragment = fragment_cursor.item().unwrap();
|
||||
let overshoot = offset - *fragment_cursor.start();
|
||||
Anchor {
|
||||
timestamp: fragment.timestamp,
|
||||
Anchor::Character {
|
||||
insertion_id: fragment.timestamp,
|
||||
offset: fragment.insertion_offset + overshoot,
|
||||
bias,
|
||||
buffer_id: Some(self.remote_id),
|
||||
buffer_id: self.remote_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_resolve(&self, anchor: &Anchor) -> bool {
|
||||
*anchor == Anchor::MIN
|
||||
|| *anchor == Anchor::MAX
|
||||
|| (Some(self.remote_id) == anchor.buffer_id && self.version.observed(anchor.timestamp))
|
||||
match *anchor {
|
||||
Anchor::Start { buffer_id } => self.remote_id == buffer_id,
|
||||
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 {
|
||||
@@ -2318,7 +2311,7 @@ impl BufferSnapshot {
|
||||
where
|
||||
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>(
|
||||
@@ -2328,7 +2321,7 @@ impl BufferSnapshot {
|
||||
where
|
||||
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>(
|
||||
@@ -2366,10 +2359,20 @@ impl BufferSnapshot {
|
||||
|
||||
let start_fragment_id = self.fragment_id_for_anchor(&range.start);
|
||||
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 deleted_start = cursor.start().1.deleted;
|
||||
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 {
|
||||
visible_start += overshoot;
|
||||
} else {
|
||||
@@ -2377,6 +2380,11 @@ impl BufferSnapshot {
|
||||
}
|
||||
}
|
||||
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 {
|
||||
visible_cursor: self.visible_text.cursor(visible_start),
|
||||
@@ -2386,7 +2394,8 @@ impl BufferSnapshot {
|
||||
since,
|
||||
old_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,
|
||||
}
|
||||
}
|
||||
@@ -2516,17 +2525,17 @@ impl<'a, D: TextDimension + Ord, F: FnMut(&FragmentSummary) -> bool> Iterator fo
|
||||
break;
|
||||
}
|
||||
|
||||
let start_anchor = Anchor {
|
||||
timestamp: fragment.timestamp,
|
||||
let start_anchor = Anchor::Character {
|
||||
insertion_id: fragment.timestamp,
|
||||
offset: fragment.insertion_offset,
|
||||
bias: Bias::Right,
|
||||
buffer_id: Some(self.buffer_id),
|
||||
buffer_id: self.buffer_id,
|
||||
};
|
||||
let end_anchor = Anchor {
|
||||
timestamp: fragment.timestamp,
|
||||
let end_anchor = Anchor::Character {
|
||||
insertion_id: fragment.timestamp,
|
||||
offset: fragment.insertion_offset + fragment.len,
|
||||
bias: Bias::Left,
|
||||
buffer_id: Some(self.buffer_id),
|
||||
buffer_id: self.buffer_id,
|
||||
};
|
||||
|
||||
if !fragment.was_visible(self.since, self.undos) && fragment.visible {
|
||||
|
||||
Reference in New Issue
Block a user