Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions crates/buffer_diff/src/buffer_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct PendingHunk {
#[derive(Debug, Clone)]
pub struct DiffHunkSummary {
buffer_range: Range<Anchor>,
base_text_byte_range: Range<usize>,
}

impl sum_tree::Item for InternalDiffHunk {
Expand All @@ -96,6 +97,7 @@ impl sum_tree::Item for InternalDiffHunk {
fn summary(&self, _cx: &text::BufferSnapshot) -> Self::Summary {
DiffHunkSummary {
buffer_range: self.buffer_range.clone(),
base_text_byte_range: self.diff_base_byte_range.clone(),
}
}
}
Expand All @@ -106,6 +108,7 @@ impl sum_tree::Item for PendingHunk {
fn summary(&self, _cx: &text::BufferSnapshot) -> Self::Summary {
DiffHunkSummary {
buffer_range: self.buffer_range.clone(),
base_text_byte_range: self.diff_base_byte_range.clone(),
}
}
}
Expand All @@ -116,6 +119,7 @@ impl sum_tree::Summary for DiffHunkSummary {
fn zero(_cx: Self::Context<'_>) -> Self {
DiffHunkSummary {
buffer_range: Anchor::MIN..Anchor::MIN,
base_text_byte_range: 0..0,
}
}

Expand All @@ -125,6 +129,16 @@ impl sum_tree::Summary for DiffHunkSummary {
.start
.min(&other.buffer_range.start, buffer);
self.buffer_range.end = *self.buffer_range.end.max(&other.buffer_range.end, buffer);

self.base_text_byte_range.start = self
.base_text_byte_range
.start
.min(other.base_text_byte_range.start);

self.base_text_byte_range.end = self
.base_text_byte_range
.end
.max(other.base_text_byte_range.end);
}
}

Expand Down Expand Up @@ -305,6 +319,39 @@ impl BufferDiffSnapshot {
let (new_id, new_empty) = (right.remote_id(), right.is_empty());
new_id == old_id || (new_empty && old_empty)
}

pub fn base_text_offset(
&self,
anchor: Anchor,
bias: Bias,
buffer: &language::BufferSnapshot,
) -> usize {
let mut cursor = self.inner.hunks.cursor(buffer);
cursor.seek(&anchor, Bias::Left);
match cursor.item() {
Some(hunk) => {
if anchor.cmp(&hunk.buffer_range.start, buffer).is_ge()
&& anchor.cmp(&hunk.buffer_range.end, buffer).is_lt()
{
match bias {
Bias::Left => hunk.diff_base_byte_range.start,
Bias::Right => hunk.diff_base_byte_range.end,
}
} else {
let overshoot = anchor.to_offset(buffer) as isize
- cursor.start().buffer_range.end.to_offset(buffer) as isize;

(cursor.start().base_text_byte_range.end as isize + overshoot) as usize
}
}
None => {
let overshoot = anchor.to_offset(buffer) as isize
- cursor.start().buffer_range.end.to_offset(buffer) as isize;

(cursor.start().base_text_byte_range.end as isize + overshoot) as usize
}
}
}
}

impl BufferDiffInner {
Expand Down Expand Up @@ -946,6 +993,7 @@ impl BufferDiff {
if self.secondary_diff.is_some() {
self.inner.pending_hunks = SumTree::from_summary(DiffHunkSummary {
buffer_range: Anchor::min_min_range_for_buffer(self.buffer_id),
base_text_byte_range: 0..0,
});
cx.emit(BufferDiffEvent::DiffChanged {
changed_range: Some(Anchor::min_max_range_for_buffer(self.buffer_id)),
Expand Down Expand Up @@ -1438,6 +1486,75 @@ mod tests {
);
}

#[gpui::test]
async fn test_base_text_offset(cx: &mut gpui::TestAppContext) {
let diff_base = "
zero
one
two
three
four
five
six
seven
eight
nine
ten
"
.unindent();

let buffer_text = "
zero
one
alpha
two
THREE
FOUR
FIVE
six
seven
ten
"
.unindent();

let buffer = cx.new(|cx| {
language::Buffer::local_normalized(
Rope::from(buffer_text.as_str()),
text::LineEnding::default(),
cx,
)
});
let text_buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.text_snapshot());
let diff = BufferDiffSnapshot::new_sync(text_buffer_snapshot, diff_base, cx);

let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());

let offset_before_changes = 5;
let anchor_before_changes = buffer_snapshot.anchor_before(offset_before_changes);

let offset_before_changes_in_base_text =
diff.base_text_offset(anchor_before_changes, Bias::Left, &buffer_snapshot);
assert_eq!(offset_before_changes, offset_before_changes_in_base_text);

let offset_within_changes = 21;
let anchor_within_changes = buffer_snapshot.anchor_before(offset_within_changes);

let offset_within_changes_in_base_text_with_bias_left =
diff.base_text_offset(anchor_within_changes, Bias::Left, &buffer_snapshot);
assert_eq!(offset_within_changes_in_base_text_with_bias_left, 13);

let offset_within_changes_in_base_text_with_bias_right =
diff.base_text_offset(anchor_within_changes, Bias::Right, &buffer_snapshot);
assert_eq!(offset_within_changes_in_base_text_with_bias_right, 29);

let offset_after_changes = 47;
let anchor_after_changes = buffer_snapshot.anchor_before(offset_after_changes);

let offset_after_changes_in_base_text =
diff.base_text_offset(anchor_after_changes, Bias::Left, &buffer_snapshot);
assert_eq!(offset_after_changes_in_base_text, 52);
}

#[gpui::test]
async fn test_buffer_diff_with_secondary(cx: &mut gpui::TestAppContext) {
let head_text = "
Expand Down
39 changes: 36 additions & 3 deletions crates/editor/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20445,9 +20445,42 @@ impl Editor {
buffer_ranges.last()
}?;

let selection = text::ToPoint::to_point(&range.start, buffer).row
..text::ToPoint::to_point(&range.end, buffer).row;
Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
let selection = text::ToPoint::to_point(&range.start, buffer).row
..text::ToPoint::to_point(&range.end, buffer).row;

return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
};

let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);

let start_anchor = buffer.anchor_before(&range.start);
let end_anchor = buffer.anchor_before(&range.end);

let range_is_point = range.start == range.end;

let start_offset =
buffer_diff_snapshot.base_text_offset(start_anchor, Bias::Left, &buffer);

let end_offset = if range_is_point {
start_offset
} else {
buffer_diff_snapshot.base_text_offset(end_anchor, Bias::Right, &buffer)
};

let start_row_in_base_buffer = buffer_diff_snapshot
.base_text()
.offset_to_point(start_offset)
.row;
let end_row_in_base_buffer = buffer_diff_snapshot
.base_text()
.offset_to_point(end_offset)
.row;

Some((
multi_buffer.buffer(buffer.remote_id()).unwrap(),
start_row_in_base_buffer..end_row_in_base_buffer,
))
});

let Some((buffer, selection)) = buffer_and_selection else {
Expand Down
Loading