Detailed changes
@@ -624,6 +624,7 @@ impl ActionLog {
let task = if let Some(existing_file_content) = existing_file_content {
// Capture the agent's content before restoring existing file content
let agent_content = buffer.read(cx).text();
+ let buffer_id = buffer.read(cx).remote_id();
buffer.update(cx, |buffer, cx| {
buffer.start_transaction();
@@ -636,7 +637,10 @@ impl ActionLog {
undo_info = Some(PerBufferUndo {
buffer: buffer.downgrade(),
- edits_to_restore: vec![(Anchor::MIN..Anchor::MAX, agent_content)],
+ edits_to_restore: vec![(
+ Anchor::min_for_buffer(buffer_id)..Anchor::max_for_buffer(buffer_id),
+ agent_content,
+ )],
status: UndoBufferStatus::Created {
had_existing_content: true,
},
@@ -876,8 +880,8 @@ impl ActionLog {
let mut valid_edits = Vec::new();
for (anchor_range, text_to_restore) in per_buffer_undo.edits_to_restore {
- if anchor_range.start.buffer_id == Some(buffer.remote_id())
- && anchor_range.end.buffer_id == Some(buffer.remote_id())
+ if anchor_range.start.buffer_id == buffer.remote_id()
+ && anchor_range.end.buffer_id == buffer.remote_id()
{
valid_edits.push((anchor_range, text_to_restore));
}
@@ -1645,7 +1645,7 @@ mod tests {
completion_provider.completions(
excerpt_id,
&buffer,
- text::Anchor::MAX,
+ text::Anchor::max_for_buffer(buffer.read(cx).remote_id()),
CompletionContext {
trigger_kind: CompletionTriggerKind::TRIGGER_CHARACTER,
trigger_character: Some("@".into()),
@@ -158,9 +158,9 @@ impl sum_tree::Item for PendingHunk {
impl sum_tree::Summary for DiffHunkSummary {
type Context<'a> = &'a text::BufferSnapshot;
- fn zero(_cx: Self::Context<'_>) -> Self {
+ fn zero(buffer: &text::BufferSnapshot) -> Self {
DiffHunkSummary {
- buffer_range: Anchor::MIN..Anchor::MIN,
+ buffer_range: Anchor::min_min_range_for_buffer(buffer.remote_id()),
diff_base_byte_range: 0..0,
}
}
@@ -1614,7 +1614,7 @@ impl BufferDiff {
) {
let hunks = self
.snapshot(cx)
- .hunks_intersecting_range(Anchor::MIN..Anchor::MAX, buffer)
+ .hunks_intersecting_range(Anchor::min_max_range_for_buffer(buffer.remote_id()), buffer)
.collect::<Vec<_>>();
let Some(secondary) = self.secondary_diff.clone() else {
return;
@@ -400,7 +400,7 @@ mod tests {
capture_example(
project.clone(),
buffer.clone(),
- Anchor::MIN,
+ Anchor::min_for_buffer(buffer.read(cx).remote_id()),
events,
true,
cx,
@@ -1995,7 +1995,10 @@ impl EditPredictionStore {
cx: &mut AsyncApp,
) -> Result<Option<(Entity<Buffer>, language::Anchor)>> {
let collaborator_cursor_rows: Vec<u32> = active_buffer_snapshot
- .selections_in_range(Anchor::MIN..Anchor::MAX, false)
+ .selections_in_range(
+ Anchor::min_max_range_for_buffer(active_buffer_snapshot.remote_id()),
+ false,
+ )
.flat_map(|(_, _, _, selections)| {
selections.map(|s| s.head().to_point(active_buffer_snapshot).row)
})
@@ -2071,7 +2074,10 @@ impl EditPredictionStore {
candidate_buffer.read_with(cx, |buffer, _cx| {
let snapshot = buffer.snapshot();
let has_collaborators = snapshot
- .selections_in_range(Anchor::MIN..Anchor::MAX, false)
+ .selections_in_range(
+ Anchor::max_max_range_for_buffer(snapshot.remote_id()),
+ false,
+ )
.next()
.is_some();
let position = buffer
@@ -54,7 +54,6 @@ pub async fn apply_diff(
let mut included_files: HashMap<String, Entity<Buffer>> = HashMap::default();
- let ranges = [Anchor::MIN..Anchor::MAX];
let mut diff = DiffParser::new(diff_str);
let mut current_file = None;
let mut edits: Vec<(std::ops::Range<Anchor>, Arc<str>)> = vec![];
@@ -115,7 +114,7 @@ pub async fn apply_diff(
edits.extend(resolve_hunk_edits_in_buffer(
hunk,
buffer,
- ranges.as_slice(),
+ &[Anchor::min_max_range_for_buffer(buffer.remote_id())],
status,
)?);
anyhow::Ok(())
@@ -7,7 +7,7 @@ use project::{Completion, CompletionSource};
use settings::SnippetSortOrder;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
-use text::Anchor;
+use text::{Anchor, BufferId};
#[gpui::test]
async fn test_sort_kind(cx: &mut TestAppContext) {
@@ -393,7 +393,7 @@ impl CompletionBuilder {
kind: Option<CompletionItemKind>,
) -> Completion {
Completion {
- replace_range: Anchor::MIN..Anchor::MAX,
+ replace_range: Anchor::min_max_range_for_buffer(BufferId::new(1)),
new_text: label.to_string(),
label: CodeLabel::plain(label.to_string(), filter_text),
documentation: None,
@@ -23412,7 +23412,7 @@ async fn test_display_diff_hunks(cx: &mut TestAppContext) {
multibuffer.set_excerpts_for_path(
PathKey::with_sort_prefix(0, buffer.read(cx).file().unwrap().path().clone()),
buffer.clone(),
- vec![text::Anchor::MIN.to_point(&snapshot)..text::Anchor::MAX.to_point(&snapshot)],
+ vec![Point::zero()..snapshot.max_point()],
2,
cx,
);
@@ -223,7 +223,11 @@ impl CommitView {
editor
.buffer()
.read(cx)
- .buffer_anchor_to_anchor(&message_buffer, Anchor::MAX, cx)
+ .buffer_anchor_to_anchor(
+ &message_buffer,
+ Anchor::max_for_buffer(&message_buffer.read(cx).remote_id()),
+ cx,
+ )
.map(|anchor| BlockProperties {
placement: BlockPlacement::Below(anchor),
height: Some(1),
@@ -431,7 +435,9 @@ impl CommitView {
let base_text = diff.base_text();
- for hunk in diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, buffer) {
+ for hunk in
+ diff.hunks_intersecting_range(Anchor::min_max_range_for_buffer(buffer_id), buffer)
+ {
let added_rows = hunk.range.end.row.saturating_sub(hunk.range.start.row);
total_additions += added_rows;
@@ -559,7 +559,9 @@ impl ProjectDiff {
let base_text = diff.base_text();
- for hunk in diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, buffer) {
+ for hunk in
+ diff.hunks_intersecting_range(Anchor::min_max_range_for_buffer(buffer_id), buffer)
+ {
let added_rows = hunk.range.end.row.saturating_sub(hunk.range.start.row);
total_additions += added_rows;
@@ -326,23 +326,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<'a> = &'a text::BufferSnapshot;
- fn zero(_cx: Self::Context<'_>) -> Self {
- Default::default()
+ fn zero(buffer: &text::BufferSnapshot) -> Self {
+ Self {
+ start: Anchor::min_for_buffer(buffer.remote_id()),
+ end: Anchor::max_for_buffer(buffer.remote_id()),
+ min_start: Anchor::max_for_buffer(buffer.remote_id()),
+ max_end: Anchor::min_for_buffer(buffer.remote_id()),
+ count: 0,
+ }
}
fn add_summary(&mut self, other: &Self, buffer: Self::Context<'_>) {
@@ -260,7 +260,7 @@ pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
Bias::Left => proto::Bias::Left as i32,
Bias::Right => proto::Bias::Right as i32,
},
- buffer_id: anchor.buffer_id.map(Into::into),
+ buffer_id: Some(anchor.buffer_id.into()),
}
}
@@ -498,7 +498,7 @@ pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
timestamp,
anchor.offset as u32,
bias,
- buffer_id,
+ buffer_id.expect("FIXME rework anchor ser/de"),
))
}
@@ -18,7 +18,7 @@ use std::{
};
use streaming_iterator::StreamingIterator;
use sum_tree::{Bias, Dimensions, SeekTarget, SumTree};
-use text::{Anchor, BufferSnapshot, OffsetRangeExt, Point, Rope, ToOffset, ToPoint};
+use text::{Anchor, BufferId, BufferSnapshot, OffsetRangeExt, Point, Rope, ToOffset, ToPoint};
use tree_sitter::{
Node, Query, QueryCapture, QueryCaptures, QueryCursor, QueryMatch, QueryMatches,
QueryPredicateArg,
@@ -567,7 +567,7 @@ impl SyntaxSnapshot {
let bounded_position = SyntaxLayerPositionBeforeChange {
position: position.clone(),
- change: changed_regions.start_position(),
+ change: changed_regions.start_position(text.remote_id()),
};
if bounded_position.cmp(cursor.start(), text).is_gt() {
let slice = cursor.slice(&bounded_position, Bias::Left);
@@ -1925,11 +1925,11 @@ impl ChangedRegion {
}
impl ChangeRegionSet {
- fn start_position(&self) -> ChangeStartPosition {
+ fn start_position(&self, buffer_id: BufferId) -> ChangeStartPosition {
self.0.first().map_or(
ChangeStartPosition {
depth: usize::MAX,
- position: Anchor::MAX,
+ position: Anchor::max_for_buffer(buffer_id),
},
|region| ChangeStartPosition {
depth: region.depth,
@@ -1978,32 +1978,28 @@ impl ChangeRegionSet {
}
}
-impl Default for SyntaxLayerSummary {
- fn default() -> Self {
+impl sum_tree::Summary for SyntaxLayerSummary {
+ type Context<'a> = &'a BufferSnapshot;
+
+ fn zero(buffer: &BufferSnapshot) -> Self {
Self {
max_depth: 0,
min_depth: 0,
- range: Anchor::MAX..Anchor::MIN,
- last_layer_range: Anchor::MIN..Anchor::MAX,
+ range: Anchor::max_for_buffer(buffer.remote_id())
+ ..Anchor::min_for_buffer(buffer.remote_id()),
+ last_layer_range: Anchor::min_for_buffer(buffer.remote_id())
+ ..Anchor::max_for_buffer(buffer.remote_id()),
last_layer_language: None,
contains_unknown_injections: false,
}
}
-}
-
-impl sum_tree::Summary for SyntaxLayerSummary {
- type Context<'a> = &'a BufferSnapshot;
-
- fn zero(_cx: &BufferSnapshot) -> Self {
- Default::default()
- }
fn add_summary(&mut self, other: &Self, buffer: Self::Context<'_>) {
if other.max_depth > self.max_depth {
self.max_depth = other.max_depth;
self.range = other.range.clone();
} else {
- if self.range == (Anchor::MAX..Anchor::MAX) {
+ if self.range.start.is_min() && self.range.end.is_max() {
self.range.start = other.range.start;
}
if other.range.end.cmp(&self.range.end, buffer).is_gt() {
@@ -10,29 +10,12 @@ use std::{
ops::{Add, AddAssign, Range, Sub},
};
use sum_tree::Bias;
-use text::BufferId;
/// A multibuffer anchor derived from an anchor into a specific excerpted buffer.
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
pub struct ExcerptAnchor {
- /// The position within the excerpt's underlying buffer. This is a stable
- /// reference that remains valid as the buffer text is edited.
- pub(crate) timestamp: clock::Lamport,
-
- /// The byte offset into the text inserted in the operation
- /// at `timestamp`.
- pub(crate) offset: u32,
- /// Whether this anchor stays attached to the character *before* or *after*
- /// the offset.
- pub(crate) bias: Bias,
- pub(crate) buffer_id: BufferId,
- /// Refers to the path key that the buffer had when this anchor was created,
- /// so that ordering is stable when the path key for a buffer changes
+ pub(crate) text_anchor: text::Anchor,
pub(crate) path: PathKeyIndex,
- /// When present, indicates this anchor points into deleted text within an
- /// expanded diff hunk. The anchor references a position in the diff base
- /// (original) text rather than the current buffer text. This is used when
- /// displaying inline diffs where deleted lines are shown.
pub(crate) diff_base_anchor: Option<text::Anchor>,
}
@@ -50,7 +33,7 @@ pub enum Anchor {
impl std::fmt::Debug for ExcerptAnchor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Anchor")
- .field("text_anchor", &self.text_anchor())
+ .field("text_anchor", &self.text_anchor)
.field("diff_base_anchor", &self.diff_base_anchor)
.finish()
}
@@ -86,7 +69,7 @@ impl From<ExcerptAnchor> for Anchor {
impl ExcerptAnchor {
pub(crate) fn text_anchor(&self) -> text::Anchor {
- text::Anchor::new(self.timestamp, self.offset, self.bias, Some(self.buffer_id))
+ self.text_anchor
}
pub(crate) fn with_diff_base_anchor(mut self, diff_base_anchor: text::Anchor) -> Self {
@@ -109,8 +92,8 @@ impl ExcerptAnchor {
// in the case that you removed the buffer containing self,
// and added the buffer containing other with the same path key
// (ordering is arbitrary but consistent)
- if self.buffer_id != other.buffer_id {
- return self.buffer_id.cmp(&other.buffer_id);
+ if self.text_anchor.buffer_id != other.text_anchor.buffer_id {
+ return self.text_anchor.buffer_id.cmp(&other.text_anchor.buffer_id);
}
let Some(buffer) = snapshot.buffer_for_path(&self_path_key) else {
@@ -124,7 +107,7 @@ impl ExcerptAnchor {
if (self.diff_base_anchor.is_some() || other.diff_base_anchor.is_some())
&& let Some(base_text) = snapshot
.diffs
- .get(&self.buffer_id)
+ .get(&self.text_anchor.buffer_id)
.map(|diff| diff.base_text())
{
let self_anchor = self.diff_base_anchor.filter(|a| a.is_valid(base_text));
@@ -147,16 +130,16 @@ impl ExcerptAnchor {
}
fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Self {
- if self.bias == Bias::Left {
+ if self.text_anchor.bias == Bias::Left {
return *self;
}
- let Some(buffer) = snapshot.buffer_for_id(self.buffer_id) else {
+ let Some(buffer) = snapshot.buffer_for_id(self.text_anchor.buffer_id) else {
return *self;
};
let text_anchor = self.text_anchor().bias_left(&buffer);
let ret = Self::in_buffer(self.path, text_anchor);
if let Some(diff_base_anchor) = self.diff_base_anchor {
- if let Some(diff) = snapshot.diffs.get(&self.buffer_id)
+ if let Some(diff) = snapshot.diffs.get(&self.text_anchor.buffer_id)
&& diff_base_anchor.is_valid(&diff.base_text())
{
ret.with_diff_base_anchor(diff_base_anchor.bias_left(diff.base_text()))
@@ -169,16 +152,16 @@ impl ExcerptAnchor {
}
fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Self {
- if self.bias == Bias::Right {
+ if self.text_anchor.bias == Bias::Right {
return *self;
}
- let Some(buffer) = snapshot.buffer_for_id(self.buffer_id) else {
+ let Some(buffer) = snapshot.buffer_for_id(self.text_anchor.buffer_id) else {
return *self;
};
let text_anchor = self.text_anchor().bias_right(&buffer);
let ret = Self::in_buffer(self.path, text_anchor);
if let Some(diff_base_anchor) = self.diff_base_anchor {
- if let Some(diff) = snapshot.diffs.get(&self.buffer_id)
+ if let Some(diff) = snapshot.diffs.get(&self.text_anchor.buffer_id)
&& diff_base_anchor.is_valid(&diff.base_text())
{
ret.with_diff_base_anchor(diff_base_anchor.bias_right(diff.base_text()))
@@ -192,16 +175,10 @@ impl ExcerptAnchor {
#[track_caller]
pub(crate) fn in_buffer(path: PathKeyIndex, text_anchor: text::Anchor) -> Self {
- let Some(buffer_id) = text_anchor.buffer_id else {
- panic!("text_anchor must have a buffer_id");
- };
ExcerptAnchor {
path,
diff_base_anchor: None,
- timestamp: text_anchor.timestamp(),
- buffer_id,
- offset: text_anchor.offset,
- bias: text_anchor.bias,
+ text_anchor,
}
}
@@ -214,7 +191,7 @@ impl ExcerptAnchor {
let Some(excerpt) = cursor.item() else {
return false;
};
- excerpt.buffer_id == self.buffer_id
+ excerpt.buffer_id == self.text_anchor.buffer_id
&& excerpt
.range
.context
@@ -291,7 +268,7 @@ impl Anchor {
match self {
Anchor::Min => Bias::Left,
Anchor::Max => Bias::Right,
- Anchor::Excerpt(anchor) => anchor.bias,
+ Anchor::Excerpt(anchor) => anchor.text_anchor.bias,
}
}
@@ -801,7 +801,7 @@ impl ExcerptRange<text::Anchor> {
#[derive(Clone, Debug)]
pub struct ExcerptSummary {
path_key: PathKey,
- max_anchor: text::Anchor,
+ max_anchor: Option<text::Anchor>,
widest_line_number: u32,
text: MBTextSummary,
count: usize,
@@ -811,7 +811,7 @@ impl ExcerptSummary {
pub fn min() -> Self {
ExcerptSummary {
path_key: PathKey::min(),
- max_anchor: text::Anchor::MIN,
+ max_anchor: None,
widest_line_number: 0,
text: MBTextSummary::default(),
count: 0,
@@ -1660,7 +1660,7 @@ impl MultiBuffer {
.start
.excerpt_anchor()
.map(|excerpt_anchor| excerpt_anchor.text_anchor())
- .unwrap_or(text::Anchor::MIN),
+ .unwrap_or(text::Anchor::min_for_buffer(excerpt.buffer_id)),
buffer,
)
.clone();
@@ -1670,7 +1670,7 @@ impl MultiBuffer {
.end
.excerpt_anchor()
.map(|excerpt_anchor| excerpt_anchor.text_anchor())
- .unwrap_or(text::Anchor::MAX),
+ .unwrap_or(text::Anchor::max_for_buffer(excerpt.buffer_id)),
buffer,
)
.clone();
@@ -1842,7 +1842,7 @@ impl MultiBuffer {
pub fn buffer_for_anchor(&self, anchor: Anchor, cx: &App) -> Option<Entity<Buffer>> {
match anchor {
Anchor::Min => Some(self.snapshot(cx).excerpts.first()?.buffer(self)),
- Anchor::Excerpt(excerpt_anchor) => self.buffer(excerpt_anchor.buffer_id),
+ Anchor::Excerpt(excerpt_anchor) => self.buffer(excerpt_anchor.text_anchor.buffer_id),
Anchor::Max => Some(self.snapshot(cx).excerpts.first()?.buffer(self)),
}
}
@@ -1935,14 +1935,14 @@ impl MultiBuffer {
let mut futures = Vec::new();
for anchor in anchors {
if let Some(excerpt_anchor) = anchor.excerpt_anchor() {
- if let Some(buffer) = self.buffers.get(&excerpt_anchor.buffer_id) {
+ if let Some(buffer) = self.buffers.get(&excerpt_anchor.text_anchor.buffer_id) {
buffer.buffer.update(cx, |buffer, _| {
futures.push(buffer.wait_for_anchors([excerpt_anchor.text_anchor()]))
});
} else {
error = Some(anyhow!(
"buffer {:?} is not part of this multi-buffer",
- excerpt_anchor.buffer_id
+ excerpt_anchor.text_anchor.buffer_id
));
break;
}
@@ -1966,7 +1966,11 @@ impl MultiBuffer {
) -> Option<(Entity<Buffer>, text::Anchor)> {
let snapshot = self.read(cx);
let anchor = snapshot.anchor_before(position).excerpt_anchor()?;
- let buffer = self.buffers.get(&anchor.buffer_id)?.buffer.clone();
+ let buffer = self
+ .buffers
+ .get(&anchor.text_anchor.buffer_id)?
+ .buffer
+ .clone();
Some((buffer, anchor.text_anchor()))
}
@@ -3591,13 +3595,8 @@ impl MultiBufferSnapshot {
let mut anchors = anchors.peekable();
let mut cursor = self.excerpts.cursor::<ExcerptSummary>(());
'anchors: while let Some(anchor) = anchors.peek() {
- let Some(buffer_id) = anchor.buffer_id else {
- anchors.next();
- result.push(None);
- continue 'anchors;
- };
- let mut same_buffer_anchors =
- anchors.peeking_take_while(|a| a.buffer_id.is_some_and(|b| buffer_id == b));
+ let buffer_id = anchor.buffer_id;
+ let mut same_buffer_anchors = anchors.peeking_take_while(|a| a.buffer_id == buffer_id);
if let Some(buffer) = self.buffers.get(&buffer_id) {
let path = &buffer.path_key;
@@ -4920,7 +4919,7 @@ impl MultiBufferSnapshot {
// A right-biased anchor at a transform boundary belongs to the
// *next* transform, so advance past the current one.
- if anchor.bias == Bias::Right && at_transform_end {
+ if anchor.text_anchor.bias == Bias::Right && at_transform_end {
diff_transforms.next();
continue;
}
@@ -5074,6 +5073,7 @@ impl MultiBufferSnapshot {
let mut summaries = Vec::new();
while let Some(anchor) = anchors.peek() {
+ dbg!(&anchor);
let target = anchor.seek_target(self);
let excerpt_anchor = match anchor {
Anchor::Min => {
@@ -5121,6 +5121,7 @@ impl MultiBufferSnapshot {
if !excerpt.contains(&excerpt_anchor, self) {
return None;
}
+ anchors.next();
Some((excerpt_anchor.text_anchor(), excerpt_anchor))
}),
)
@@ -5304,10 +5305,7 @@ impl MultiBufferSnapshot {
/// Wraps the [`text::Anchor`] in a [`crate::Anchor`] if this multi-buffer is a singleton.
pub fn as_singleton_anchor(&self, text_anchor: text::Anchor) -> Option<Anchor> {
let buffer = self.as_singleton()?;
- if text_anchor
- .buffer_id
- .is_none_or(|id| id == buffer.remote_id())
- {
+ if text_anchor.buffer_id == buffer.remote_id() {
// todo!() bit hacky, but always right for singletons
Some(Anchor::in_buffer(PathKeyIndex(0), text_anchor))
} else {
@@ -6242,7 +6240,7 @@ impl MultiBufferSnapshot {
anchor
.excerpt_anchor()
.map(|anchor| anchor.text_anchor())
- .unwrap_or(text::Anchor::MIN),
+ .unwrap_or(text::Anchor::min_for_buffer(buffer_snapshot.remote_id())),
theme,
)
.into_iter()
@@ -6376,7 +6374,7 @@ impl MultiBufferSnapshot {
pub fn buffer_id_for_anchor(&self, anchor: Anchor) -> Option<BufferId> {
match anchor {
Anchor::Min => self.excerpts.first().map(|excerpt| excerpt.buffer_id),
- Anchor::Excerpt(excerpt_anchor) => Some(excerpt_anchor.buffer_id),
+ Anchor::Excerpt(excerpt_anchor) => Some(excerpt_anchor.text_anchor.buffer_id),
Anchor::Max => self.excerpts.last().map(|excerpt| excerpt.buffer_id),
}
}
@@ -7051,7 +7049,7 @@ impl Excerpt {
pub(crate) fn contains(&self, anchor: &ExcerptAnchor, snapshot: &MultiBufferSnapshot) -> bool {
self.path_key_index == anchor.path
- && self.buffer_id == anchor.buffer_id
+ && self.buffer_id == anchor.text_anchor.buffer_id
&& self
.range
.contains(&anchor.text_anchor(), self.buffer_snapshot(snapshot))
@@ -7245,7 +7243,7 @@ impl sum_tree::Item for Excerpt {
}
ExcerptSummary {
path_key: self.path_key.clone(),
- max_anchor: self.range.context.end,
+ max_anchor: Some(self.range.context.end),
widest_line_number: self.max_buffer_row,
text: text.into(),
count: 1,
@@ -7372,14 +7370,13 @@ impl sum_tree::SeekTarget<'_, ExcerptSummary, ExcerptSummary> for AnchorSeekTarg
// the goal is that if you seek to buffer_id 1 (path key a)
// and you find that path key a now belongs to buffer_id 2,
// we'll seek past buffer_id 2.
- if let Some(buffer_id) = cursor_location.max_anchor.buffer_id
- && buffer_id != snapshot.remote_id()
+ if cursor_location.max_anchor.map(|a| a.buffer_id) != Some(snapshot.remote_id())
{
Ordering::Greater
} else {
anchor
.text_anchor()
- .cmp(&cursor_location.max_anchor, snapshot)
+ .cmp(&cursor_location.max_anchor.unwrap(), snapshot)
}
} else {
// shouldn't happen because we expect this buffer not to have any excerpts
@@ -3623,6 +3623,7 @@ async fn test_summaries_for_anchors(cx: &mut TestAppContext) {
});
cx.run_until_parked();
+ dbg!("BEFORE");
let multibuffer = cx.new(|cx| {
let mut multibuffer = MultiBuffer::new(Capability::ReadWrite);
multibuffer.set_all_diff_hunks_expanded(cx);
@@ -3645,10 +3646,12 @@ async fn test_summaries_for_anchors(cx: &mut TestAppContext) {
multibuffer
});
+ dbg!("BEFORE");
let (mut snapshot, mut subscription) = multibuffer.update(cx, |multibuffer, cx| {
(multibuffer.snapshot(cx), multibuffer.subscribe())
});
+ dbg!("BEFORE");
assert_new_snapshot(
&multibuffer,
&mut snapshot,
@@ -3665,6 +3668,7 @@ async fn test_summaries_for_anchors(cx: &mut TestAppContext) {
),
);
+ dbg!("BEFORE");
let anchor_1 = multibuffer.read_with(cx, |multibuffer, cx| {
multibuffer
.buffer_anchor_to_anchor(
@@ -3674,9 +3678,11 @@ async fn test_summaries_for_anchors(cx: &mut TestAppContext) {
)
.unwrap()
});
+ dbg!("BEFORE");
let point_1 = snapshot.summaries_for_anchors::<Point, _>([&anchor_1])[0];
assert_eq!(point_1, Point::new(0, 0));
+ dbg!("BEFORE");
let anchor_2 = multibuffer.read_with(cx, |multibuffer, cx| {
multibuffer
.buffer_anchor_to_anchor(
@@ -3686,7 +3692,9 @@ async fn test_summaries_for_anchors(cx: &mut TestAppContext) {
)
.unwrap()
});
+ dbg!("BEFORE");
let point_2 = snapshot.summaries_for_anchors::<Point, _>([&anchor_2])[0];
+ dbg!("AFTER");
assert_eq!(point_2, Point::new(3, 0));
}
@@ -545,10 +545,11 @@ impl MultiBuffer {
})
}
drop(cursor);
- snapshot.excerpts = new_excerpts;
if changed_trailing_excerpt {
snapshot.trailing_excerpt_update_count += 1;
+ new_excerpts.update_last(|excerpt| excerpt.has_trailing_newline = false, ())
}
+ snapshot.excerpts = new_excerpts;
let edits =
Self::sync_diff_transforms(&mut snapshot, vec![edit], DiffChangeKind::BufferEdited);
@@ -1784,7 +1784,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: Anchor::min_max_range_for_buffer(buffer.remote_id()),
}],
&buffer.snapshot(),
),
@@ -7986,9 +7986,10 @@ async fn test_unstaged_diff_for_buffer(cx: &mut gpui::TestAppContext) {
unstaged_diff.update(cx, |unstaged_diff, cx| {
let snapshot = buffer.read(cx).snapshot();
assert_hunks(
- unstaged_diff
- .snapshot(cx)
- .hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot),
+ unstaged_diff.snapshot(cx).hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(snapshot.remote_id()),
+ &snapshot,
+ ),
&snapshot,
&unstaged_diff.base_text(cx).text(),
&[(
@@ -8077,8 +8078,10 @@ async fn test_uncommitted_diff_for_buffer(cx: &mut gpui::TestAppContext) {
diff_1.update(cx, |diff, cx| {
let snapshot = buffer_1.read(cx).snapshot();
assert_hunks(
- diff.snapshot(cx)
- .hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot),
+ diff.snapshot(cx).hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(snapshot.remote_id()),
+ &snapshot,
+ ),
&snapshot,
&diff.base_text_string(cx).unwrap(),
&[
@@ -8119,8 +8122,10 @@ async fn test_uncommitted_diff_for_buffer(cx: &mut gpui::TestAppContext) {
diff_1.update(cx, |diff, cx| {
let snapshot = buffer_1.read(cx).snapshot();
assert_hunks(
- diff.snapshot(cx)
- .hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot),
+ diff.snapshot(cx).hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(snapshot.remote_id()),
+ &snapshot,
+ ),
&snapshot,
&diff.base_text(cx).text(),
&[(
@@ -8149,8 +8154,10 @@ async fn test_uncommitted_diff_for_buffer(cx: &mut gpui::TestAppContext) {
diff_2.update(cx, |diff, cx| {
let snapshot = buffer_2.read(cx).snapshot();
assert_hunks(
- diff.snapshot(cx)
- .hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot),
+ diff.snapshot(cx).hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(snapshot.remote_id()),
+ &snapshot,
+ ),
&snapshot,
&diff.base_text_string(cx).unwrap(),
&[(
@@ -8171,8 +8178,10 @@ async fn test_uncommitted_diff_for_buffer(cx: &mut gpui::TestAppContext) {
diff_2.update(cx, |diff, cx| {
let snapshot = buffer_2.read(cx).snapshot();
assert_hunks(
- diff.snapshot(cx)
- .hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot),
+ diff.snapshot(cx).hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(snapshot.remote_id()),
+ &snapshot,
+ ),
&snapshot,
&diff.base_text_string(cx).unwrap(),
&[(
@@ -24,7 +24,7 @@ pub struct Anchor {
/// Whether this anchor stays attached to the character *before* or *after*
/// the offset.
pub bias: Bias,
- pub buffer_id: Option<BufferId>,
+ pub buffer_id: BufferId,
}
impl Debug for Anchor {
@@ -46,28 +46,7 @@ impl Debug for Anchor {
}
impl Anchor {
- pub const MIN: Self = Self {
- timestamp_replica_id: clock::Lamport::MIN.replica_id,
- timestamp_value: clock::Lamport::MIN.value,
- offset: u32::MIN,
- bias: Bias::Left,
- buffer_id: None,
- };
-
- pub const MAX: Self = Self {
- timestamp_replica_id: clock::Lamport::MAX.replica_id,
- timestamp_value: clock::Lamport::MAX.value,
- offset: u32::MAX,
- bias: Bias::Right,
- buffer_id: None,
- };
-
- pub fn new(
- timestamp: clock::Lamport,
- offset: u32,
- bias: Bias,
- buffer_id: Option<BufferId>,
- ) -> Self {
+ pub fn new(timestamp: clock::Lamport, offset: u32, bias: Bias, buffer_id: BufferId) -> Self {
Self {
timestamp_replica_id: timestamp.replica_id,
timestamp_value: timestamp.value,
@@ -83,7 +62,7 @@ impl Anchor {
timestamp_value: clock::Lamport::MIN.value,
offset: u32::MIN,
bias: Bias::Left,
- buffer_id: Some(buffer_id),
+ buffer_id,
}
}
@@ -93,7 +72,7 @@ impl Anchor {
timestamp_value: clock::Lamport::MAX.value,
offset: u32::MAX,
bias: Bias::Right,
- buffer_id: Some(buffer_id),
+ buffer_id,
}
}
@@ -171,7 +150,7 @@ impl Anchor {
pub fn is_valid(&self, buffer: &BufferSnapshot) -> bool {
if self.is_min() || self.is_max() {
true
- } else if self.buffer_id.is_none_or(|id| id != buffer.remote_id) {
+ } else if self.buffer_id != buffer.remote_id {
false
} else {
let Some(fragment_id) = buffer.try_fragment_id_for_anchor(self) else {
@@ -2413,7 +2413,7 @@ impl BufferSnapshot {
} else if anchor.is_max() {
self.visible_text.len()
} else {
- debug_assert_eq!(anchor.buffer_id, Some(self.remote_id));
+ debug_assert_eq!(anchor.buffer_id, self.remote_id);
debug_assert!(
self.version.observed(anchor.timestamp()),
"Anchor timestamp {:?} not observed by buffer {:?}",
@@ -2445,7 +2445,7 @@ impl BufferSnapshot {
#[cold]
fn panic_bad_anchor(&self, anchor: &Anchor) -> ! {
- if anchor.buffer_id.is_some_and(|id| id != self.remote_id) {
+ if anchor.buffer_id != self.remote_id {
panic!(
"invalid anchor - buffer id does not match: anchor {anchor:?}; buffer id: {}, version: {:?}",
self.remote_id, self.version
@@ -2566,7 +2566,7 @@ impl BufferSnapshot {
fragment.timestamp,
fragment.insertion_offset + overshoot as u32,
bias,
- Some(self.remote_id),
+ self.remote_id,
)
}
}
@@ -2574,8 +2574,7 @@ impl BufferSnapshot {
pub fn can_resolve(&self, anchor: &Anchor) -> bool {
anchor.is_min()
|| anchor.is_max()
- || (Some(self.remote_id) == anchor.buffer_id
- && self.version.observed(anchor.timestamp()))
+ || (self.remote_id == anchor.buffer_id && self.version.observed(anchor.timestamp()))
}
pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
@@ -2601,7 +2600,10 @@ impl BufferSnapshot {
where
D: TextDimension + Ord,
{
- self.edits_since_in_range(since, Anchor::MIN..Anchor::MAX)
+ self.edits_since_in_range(
+ since,
+ Anchor::min_for_buffer(self.remote_id)..Anchor::max_for_buffer(self.remote_id),
+ )
}
pub fn anchored_edits_since<'a, D>(
@@ -2611,7 +2613,10 @@ impl BufferSnapshot {
where
D: TextDimension + Ord,
{
- self.anchored_edits_since_in_range(since, Anchor::MIN..Anchor::MAX)
+ self.anchored_edits_since_in_range(
+ since,
+ Anchor::min_for_buffer(self.remote_id)..Anchor::max_for_buffer(self.remote_id),
+ )
}
pub fn edits_since_in_range<'a, D>(
@@ -2874,13 +2879,13 @@ impl<D: TextDimension + Ord, F: FnMut(&FragmentSummary) -> bool> Iterator for Ed
fragment.timestamp,
fragment.insertion_offset,
Bias::Right,
- Some(self.buffer_id),
+ self.buffer_id,
);
let end_anchor = Anchor::new(
fragment.timestamp,
fragment.insertion_offset + fragment.len,
Bias::Left,
- Some(self.buffer_id),
+ self.buffer_id,
);
if !fragment.was_visible(self.since, self.undos) && fragment.visible {