Do less work when revealing entries in the outline panel (#20031)

Before this change, we were trying to determine current element before
debouncing, causing a lot of extra work on caret movement. Now, we only
do this for the task that managed to wait the entire debounce period.

Closes https://github.com/zed-industries/zed/issues/19817
Closes https://github.com/zed-industries/zed/issues/14235

Release Notes:

- Fixed outline panel-related performance issues when selections change
in the large document
([#19817](https://github.com/zed-industries/zed/issues/19817)),
([#14235](https://github.com/zed-industries/zed/issues/14235))
This commit is contained in:
Kirill Bulatov 2024-10-31 16:29:19 +02:00 committed by GitHub
parent 9dad897d49
commit f766f6ceae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1440,26 +1440,26 @@ impl OutlinePanel {
}
}
fn reveal_entry_for_selection(
&mut self,
editor: &View<Editor>,
cx: &mut ViewContext<'_, Self>,
) {
fn reveal_entry_for_selection(&mut self, editor: View<Editor>, cx: &mut ViewContext<'_, Self>) {
if !self.active {
return;
}
if !OutlinePanelSettings::get_global(cx).auto_reveal_entries {
return;
}
let Some(entry_with_selection) = self.location_for_editor_selection(editor, cx) else {
self.selected_entry = SelectedEntry::None;
cx.notify();
return;
};
let project = self.project.clone();
self.reveal_selection_task = cx.spawn(|outline_panel, mut cx| async move {
cx.background_executor().timer(UPDATE_DEBOUNCE).await;
let entry_with_selection = outline_panel.update(&mut cx, |outline_panel, cx| {
outline_panel.location_for_editor_selection(&editor, cx)
})?;
let Some(entry_with_selection) = entry_with_selection else {
outline_panel.update(&mut cx, |outline_panel, cx| {
outline_panel.selected_entry = SelectedEntry::None;
cx.notify();
})?;
return Ok(());
};
let related_buffer_entry = match &entry_with_selection {
PanelEntry::Fs(FsEntry::File(worktree_id, _, buffer_id, _)) => {
project.update(&mut cx, |project, cx| {
@ -2436,7 +2436,7 @@ impl OutlinePanel {
}
fn location_for_editor_selection(
&mut self,
&self,
editor: &View<Editor>,
cx: &mut ViewContext<Self>,
) -> Option<PanelEntry> {
@ -2500,7 +2500,7 @@ impl OutlinePanel {
}
fn outline_location(
&mut self,
&self,
buffer_id: BufferId,
excerpt_id: ExcerptId,
multi_buffer_snapshot: editor::MultiBufferSnapshot,
@ -4321,7 +4321,7 @@ fn subscribe_for_editor_events(
editor,
move |outline_panel, editor, e: &EditorEvent, cx| match e {
EditorEvent::SelectionsChanged { local: true } => {
outline_panel.reveal_entry_for_selection(&editor, cx);
outline_panel.reveal_entry_for_selection(editor, cx);
cx.notify();
}
EditorEvent::ExcerptsAdded { excerpts, .. } => {
@ -4479,7 +4479,13 @@ mod tests {
cx.executor()
.advance_clock(UPDATE_DEBOUNCE + Duration::from_millis(100));
cx.run_until_parked();
outline_panel.update(cx, |outline_panel, _| {
outline_panel.update(cx, |outline_panel, cx| {
// Project search re-adds items to the buffer, removing the caret from it.
// Select the first entry and move 4 elements down.
for _ in 0..6 {
outline_panel.select_next(&SelectNext, cx);
}
assert_eq!(
display_entries(
&outline_panel.cached_entries,
@ -4795,7 +4801,7 @@ mod tests {
r#"/
public/lottie/
syntax-tree.json
search: { "something": "static" } <==== selected
search: { "something": "static" }
src/
app/(site)/
(about)/jobs/[slug]/
@ -4811,8 +4817,11 @@ mod tests {
});
outline_panel.update(cx, |outline_panel, cx| {
outline_panel.select_next(&SelectNext, cx);
outline_panel.select_next(&SelectNext, cx);
// After the search is done, we have updated the outline panel contents and caret is not in any excerot, so there are no selections.
// Move to 5th element in the list (0th action will selection the first element)
for _ in 0..6 {
outline_panel.select_next(&SelectNext, cx);
}
outline_panel.collapse_selected_entry(&CollapseSelectedEntry, cx);
});
cx.run_until_parked();