Fix excerpt jumps using selections, not the match data (#20491)

Fixes
https://github.com/zed-industries/zed/pull/20469#issuecomment-2466805325

Release Notes:

- N/A

---------

Co-authored-by: Bennet <bennet@zed.dev>
This commit is contained in:
Kirill Bulatov 2024-11-11 10:17:32 +01:00 committed by GitHub
parent 1460249a70
commit f4024cc602
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 152 additions and 70 deletions

View file

@ -1748,6 +1748,15 @@ pub(crate) struct FocusedBlock {
focus_handle: WeakFocusHandle,
}
#[derive(Clone)]
struct JumpData {
excerpt_id: ExcerptId,
position: Point,
anchor: text::Anchor,
path: Option<project::ProjectPath>,
line_offset_from_top: u32,
}
impl Editor {
pub fn single_line(cx: &mut ViewContext<Self>) -> Self {
let buffer = cx.new_model(|cx| Buffer::local("", cx));
@ -12584,47 +12593,83 @@ impl Editor {
}
pub fn open_excerpts_in_split(&mut self, _: &OpenExcerptsSplit, cx: &mut ViewContext<Self>) {
self.open_excerpts_common(true, cx)
self.open_excerpts_common(None, true, cx)
}
pub fn open_excerpts(&mut self, _: &OpenExcerpts, cx: &mut ViewContext<Self>) {
self.open_excerpts_common(false, cx)
self.open_excerpts_common(None, false, cx)
}
fn open_excerpts_common(&mut self, split: bool, cx: &mut ViewContext<Self>) {
let selections = self.selections.all::<usize>(cx);
let buffer = self.buffer.read(cx);
if buffer.is_singleton() {
cx.propagate();
return;
}
fn open_excerpts_common(
&mut self,
jump_data: Option<JumpData>,
split: bool,
cx: &mut ViewContext<Self>,
) {
let Some(workspace) = self.workspace() else {
cx.propagate();
return;
};
let mut new_selections_by_buffer = HashMap::default();
for selection in selections {
for (mut buffer_handle, mut range, _) in
buffer.range_to_buffer_ranges(selection.range(), cx)
{
// When editing branch buffers, jump to the corresponding location
// in their base buffer.
let buffer = buffer_handle.read(cx);
if let Some(base_buffer) = buffer.diff_base_buffer() {
range = buffer.range_to_version(range, &base_buffer.read(cx).version());
buffer_handle = base_buffer;
}
if self.buffer.read(cx).is_singleton() {
cx.propagate();
return;
}
if selection.reversed {
mem::swap(&mut range.start, &mut range.end);
let mut new_selections_by_buffer = HashMap::default();
match &jump_data {
Some(jump_data) => {
let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
if let Some(buffer) = multi_buffer_snapshot
.buffer_id_for_excerpt(jump_data.excerpt_id)
.and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
{
let buffer_snapshot = buffer.read(cx).snapshot();
let jump_to_point = if buffer_snapshot.can_resolve(&jump_data.anchor) {
language::ToPoint::to_point(&jump_data.anchor, &buffer_snapshot)
} else {
buffer_snapshot.clip_point(jump_data.position, Bias::Left)
};
let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
new_selections_by_buffer.insert(
buffer,
(
vec![jump_to_offset..jump_to_offset],
Some(jump_data.line_offset_from_top),
),
);
}
new_selections_by_buffer
.entry(buffer_handle)
.or_insert(Vec::new())
.push(range)
}
None => {
let selections = self.selections.all::<usize>(cx);
let buffer = self.buffer.read(cx);
for selection in selections {
for (mut buffer_handle, mut range, _) in
buffer.range_to_buffer_ranges(selection.range(), cx)
{
// When editing branch buffers, jump to the corresponding location
// in their base buffer.
let buffer = buffer_handle.read(cx);
if let Some(base_buffer) = buffer.diff_base_buffer() {
range = buffer.range_to_version(range, &base_buffer.read(cx).version());
buffer_handle = base_buffer;
}
if selection.reversed {
mem::swap(&mut range.start, &mut range.end);
}
new_selections_by_buffer
.entry(buffer_handle)
.or_insert((Vec::new(), None))
.0
.push(range)
}
}
}
}
if new_selections_by_buffer.is_empty() {
return;
}
// We defer the pane interaction because we ourselves are a workspace item
@ -12638,13 +12683,19 @@ impl Editor {
workspace.active_pane().clone()
};
for (buffer, ranges) in new_selections_by_buffer {
for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
let editor =
workspace.open_project_item::<Self>(pane.clone(), buffer, true, true, cx);
editor.update(cx, |editor, cx| {
editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
let autoscroll = match scroll_offset {
Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
None => Autoscroll::newest(),
};
let nav_history = editor.nav_history.take();
editor.change_selections(Some(autoscroll), cx, |s| {
s.select_ranges(ranges);
});
editor.nav_history = nav_history;
});
}
})