Improve outline panel initial update (#24500)
Closes https://github.com/zed-industries/zed/issues/24128 * removed unnecessary debounces when updating the panel data * removed all "loading"-related messages to snow nothing when initial data is loaded, thus reducing flickering Release Notes: - Improved outline panel initial update
This commit is contained in:
parent
3582fc4636
commit
b1055878c7
1 changed files with 82 additions and 48 deletions
|
@ -5,7 +5,10 @@ use std::{
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
ops::Range,
|
ops::Range,
|
||||||
path::{Path, PathBuf, MAIN_SEPARATOR_STR},
|
path::{Path, PathBuf, MAIN_SEPARATOR_STR},
|
||||||
sync::{atomic::AtomicBool, Arc, OnceLock},
|
sync::{
|
||||||
|
atomic::{self, AtomicBool},
|
||||||
|
Arc, OnceLock,
|
||||||
|
},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
u32,
|
u32,
|
||||||
};
|
};
|
||||||
|
@ -103,6 +106,7 @@ pub struct OutlinePanel {
|
||||||
active_item: Option<ActiveItem>,
|
active_item: Option<ActiveItem>,
|
||||||
_subscriptions: Vec<Subscription>,
|
_subscriptions: Vec<Subscription>,
|
||||||
updating_fs_entries: bool,
|
updating_fs_entries: bool,
|
||||||
|
updating_cached_entries: bool,
|
||||||
new_entries_for_fs_update: HashSet<ExcerptId>,
|
new_entries_for_fs_update: HashSet<ExcerptId>,
|
||||||
fs_entries_update_task: Task<()>,
|
fs_entries_update_task: Task<()>,
|
||||||
cached_entries_update_task: Task<()>,
|
cached_entries_update_task: Task<()>,
|
||||||
|
@ -777,7 +781,10 @@ impl OutlinePanel {
|
||||||
excerpt.invalidate_outlines();
|
excerpt.invalidate_outlines();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outline_panel.update_non_fs_items(window, cx);
|
let update_cached_items = outline_panel.update_non_fs_items(window, cx);
|
||||||
|
if update_cached_items {
|
||||||
|
outline_panel.update_cached_entries(Some(UPDATE_DEBOUNCE), window, cx);
|
||||||
|
}
|
||||||
} else if &outline_panel_settings != new_settings {
|
} else if &outline_panel_settings != new_settings {
|
||||||
outline_panel_settings = *new_settings;
|
outline_panel_settings = *new_settings;
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
@ -814,6 +821,7 @@ impl OutlinePanel {
|
||||||
active_item: None,
|
active_item: None,
|
||||||
pending_serialization: Task::ready(None),
|
pending_serialization: Task::ready(None),
|
||||||
updating_fs_entries: false,
|
updating_fs_entries: false,
|
||||||
|
updating_cached_entries: false,
|
||||||
new_entries_for_fs_update: HashSet::default(),
|
new_entries_for_fs_update: HashSet::default(),
|
||||||
preserve_selection_on_buffer_fold_toggles: HashSet::default(),
|
preserve_selection_on_buffer_fold_toggles: HashSet::default(),
|
||||||
fs_entries_update_task: Task::ready(()),
|
fs_entries_update_task: Task::ready(()),
|
||||||
|
@ -2896,8 +2904,8 @@ impl OutlinePanel {
|
||||||
outline_panel.fs_entries = new_fs_entries;
|
outline_panel.fs_entries = new_fs_entries;
|
||||||
outline_panel.fs_entries_depth = new_depth_map;
|
outline_panel.fs_entries_depth = new_depth_map;
|
||||||
outline_panel.fs_children_count = new_children_count;
|
outline_panel.fs_children_count = new_children_count;
|
||||||
outline_panel.update_cached_entries(Some(UPDATE_DEBOUNCE), window, cx);
|
|
||||||
outline_panel.update_non_fs_items(window, cx);
|
outline_panel.update_non_fs_items(window, cx);
|
||||||
|
outline_panel.update_cached_entries(debounce, window, cx);
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
})
|
})
|
||||||
|
@ -2922,7 +2930,11 @@ impl OutlinePanel {
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>| {
|
cx: &mut Context<Self>| {
|
||||||
if matches!(e, SearchEvent::MatchesInvalidated) {
|
if matches!(e, SearchEvent::MatchesInvalidated) {
|
||||||
outline_panel.update_search_matches(window, cx);
|
let update_cached_items = outline_panel.update_search_matches(window, cx);
|
||||||
|
if update_cached_items {
|
||||||
|
outline_panel.selected_entry.invalidate();
|
||||||
|
outline_panel.update_cached_entries(Some(UPDATE_DEBOUNCE), window, cx);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
outline_panel.autoscroll(cx);
|
outline_panel.autoscroll(cx);
|
||||||
},
|
},
|
||||||
|
@ -3188,10 +3200,12 @@ impl OutlinePanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
let syntax_theme = cx.theme().syntax().clone();
|
let syntax_theme = cx.theme().syntax().clone();
|
||||||
|
let first_update = Arc::new(AtomicBool::new(true));
|
||||||
for (buffer_id, (buffer_snapshot, excerpt_ranges)) in excerpt_fetch_ranges {
|
for (buffer_id, (buffer_snapshot, excerpt_ranges)) in excerpt_fetch_ranges {
|
||||||
for (excerpt_id, excerpt_range) in excerpt_ranges {
|
for (excerpt_id, excerpt_range) in excerpt_ranges {
|
||||||
let syntax_theme = syntax_theme.clone();
|
let syntax_theme = syntax_theme.clone();
|
||||||
let buffer_snapshot = buffer_snapshot.clone();
|
let buffer_snapshot = buffer_snapshot.clone();
|
||||||
|
let first_update = first_update.clone();
|
||||||
self.outline_fetch_tasks.insert(
|
self.outline_fetch_tasks.insert(
|
||||||
(buffer_id, excerpt_id),
|
(buffer_id, excerpt_id),
|
||||||
cx.spawn_in(window, |outline_panel, mut cx| async move {
|
cx.spawn_in(window, |outline_panel, mut cx| async move {
|
||||||
|
@ -3215,13 +3229,16 @@ impl OutlinePanel {
|
||||||
.or_default()
|
.or_default()
|
||||||
.get_mut(&excerpt_id)
|
.get_mut(&excerpt_id)
|
||||||
{
|
{
|
||||||
|
let debounce = if first_update
|
||||||
|
.fetch_and(false, atomic::Ordering::AcqRel)
|
||||||
|
{
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(UPDATE_DEBOUNCE)
|
||||||
|
};
|
||||||
excerpt.outlines = ExcerptOutlines::Outlines(fetched_outlines);
|
excerpt.outlines = ExcerptOutlines::Outlines(fetched_outlines);
|
||||||
|
outline_panel.update_cached_entries(debounce, window, cx);
|
||||||
}
|
}
|
||||||
outline_panel.update_cached_entries(
|
|
||||||
Some(UPDATE_DEBOUNCE),
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
}),
|
}),
|
||||||
|
@ -3376,6 +3393,7 @@ impl OutlinePanel {
|
||||||
|
|
||||||
let is_singleton = self.is_singleton_active(cx);
|
let is_singleton = self.is_singleton_active(cx);
|
||||||
let query = self.query(cx);
|
let query = self.query(cx);
|
||||||
|
self.updating_cached_entries = true;
|
||||||
self.cached_entries_update_task = cx.spawn_in(window, |outline_panel, mut cx| async move {
|
self.cached_entries_update_task = cx.spawn_in(window, |outline_panel, mut cx| async move {
|
||||||
if let Some(debounce) = debounce {
|
if let Some(debounce) = debounce {
|
||||||
cx.background_executor().timer(debounce).await;
|
cx.background_executor().timer(debounce).await;
|
||||||
|
@ -3410,6 +3428,7 @@ impl OutlinePanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
outline_panel.autoscroll(cx);
|
outline_panel.autoscroll(cx);
|
||||||
|
outline_panel.updating_cached_entries = false;
|
||||||
cx.notify();
|
cx.notify();
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
@ -3915,19 +3934,27 @@ impl OutlinePanel {
|
||||||
!self.collapsed_entries.contains(&entry_to_check)
|
!self.collapsed_entries.contains(&entry_to_check)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_non_fs_items(&mut self, window: &mut Window, cx: &mut Context<OutlinePanel>) {
|
fn update_non_fs_items(&mut self, window: &mut Window, cx: &mut Context<OutlinePanel>) -> bool {
|
||||||
if !self.active {
|
if !self.active {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update_search_matches(window, cx);
|
let mut update_cached_items = false;
|
||||||
|
update_cached_items |= self.update_search_matches(window, cx);
|
||||||
self.fetch_outdated_outlines(window, cx);
|
self.fetch_outdated_outlines(window, cx);
|
||||||
self.autoscroll(cx);
|
if update_cached_items {
|
||||||
|
self.selected_entry.invalidate();
|
||||||
|
}
|
||||||
|
update_cached_items
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_search_matches(&mut self, window: &mut Window, cx: &mut Context<OutlinePanel>) {
|
fn update_search_matches(
|
||||||
|
&mut self,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<OutlinePanel>,
|
||||||
|
) -> bool {
|
||||||
if !self.active {
|
if !self.active {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let project_search = self
|
let project_search = self
|
||||||
|
@ -4010,10 +4037,7 @@ impl OutlinePanel {
|
||||||
cx,
|
cx,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if update_cached_entries {
|
update_cached_entries
|
||||||
self.selected_entry.invalidate();
|
|
||||||
self.update_cached_entries(Some(UPDATE_DEBOUNCE), window, cx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
@ -4426,18 +4450,20 @@ impl OutlinePanel {
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Div {
|
) -> Div {
|
||||||
let contents = if self.cached_entries.is_empty() {
|
let contents = if self.cached_entries.is_empty() {
|
||||||
let header = if self.updating_fs_entries {
|
let header = if self.updating_fs_entries || self.updating_cached_entries {
|
||||||
"Loading outlines"
|
None
|
||||||
} else if query.is_some() {
|
} else if query.is_some() {
|
||||||
"No matches for query"
|
Some("No matches for query")
|
||||||
} else {
|
} else {
|
||||||
"No outlines available"
|
Some("No outlines available")
|
||||||
};
|
};
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
.flex_1()
|
.flex_1()
|
||||||
.justify_center()
|
.justify_center()
|
||||||
.size_full()
|
.size_full()
|
||||||
|
.when_some(header, |panel, header| {
|
||||||
|
panel
|
||||||
.child(h_flex().justify_center().child(Label::new(header)))
|
.child(h_flex().justify_center().child(Label::new(header)))
|
||||||
.when_some(query.clone(), |panel, query| {
|
.when_some(query.clone(), |panel, query| {
|
||||||
panel.child(h_flex().justify_center().child(Label::new(query)))
|
panel.child(h_flex().justify_center().child(Label::new(query)))
|
||||||
|
@ -4447,20 +4473,19 @@ impl OutlinePanel {
|
||||||
.pt(DynamicSpacing::Base04.rems(cx))
|
.pt(DynamicSpacing::Base04.rems(cx))
|
||||||
.justify_center()
|
.justify_center()
|
||||||
.child({
|
.child({
|
||||||
let keystroke = match self.position(window, cx) {
|
let keystroke =
|
||||||
DockPosition::Left => {
|
match self.position(window, cx) {
|
||||||
window.keystroke_text_for(&workspace::ToggleLeftDock)
|
DockPosition::Left => window
|
||||||
}
|
.keystroke_text_for(&workspace::ToggleLeftDock),
|
||||||
DockPosition::Bottom => {
|
DockPosition::Bottom => window
|
||||||
window.keystroke_text_for(&workspace::ToggleBottomDock)
|
.keystroke_text_for(&workspace::ToggleBottomDock),
|
||||||
}
|
DockPosition::Right => window
|
||||||
DockPosition::Right => {
|
.keystroke_text_for(&workspace::ToggleRightDock),
|
||||||
window.keystroke_text_for(&workspace::ToggleRightDock)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
Label::new(format!("Toggle this panel with {keystroke}"))
|
Label::new(format!("Toggle this panel with {keystroke}"))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
let list_contents = {
|
let list_contents = {
|
||||||
let items_len = self.cached_entries.len();
|
let items_len = self.cached_entries.len();
|
||||||
|
@ -4995,11 +5020,17 @@ fn subscribe_for_editor_events(
|
||||||
}
|
}
|
||||||
EditorEvent::ExcerptsExpanded { ids } => {
|
EditorEvent::ExcerptsExpanded { ids } => {
|
||||||
outline_panel.invalidate_outlines(ids);
|
outline_panel.invalidate_outlines(ids);
|
||||||
outline_panel.update_non_fs_items(window, cx);
|
let update_cached_items = outline_panel.update_non_fs_items(window, cx);
|
||||||
|
if update_cached_items {
|
||||||
|
outline_panel.update_cached_entries(Some(UPDATE_DEBOUNCE), window, cx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EditorEvent::ExcerptsEdited { ids } => {
|
EditorEvent::ExcerptsEdited { ids } => {
|
||||||
outline_panel.invalidate_outlines(ids);
|
outline_panel.invalidate_outlines(ids);
|
||||||
outline_panel.update_non_fs_items(window, cx);
|
let update_cached_items = outline_panel.update_non_fs_items(window, cx);
|
||||||
|
if update_cached_items {
|
||||||
|
outline_panel.update_cached_entries(Some(UPDATE_DEBOUNCE), window, cx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EditorEvent::BufferFoldToggled { ids, .. } => {
|
EditorEvent::BufferFoldToggled { ids, .. } => {
|
||||||
outline_panel.invalidate_outlines(ids);
|
outline_panel.invalidate_outlines(ids);
|
||||||
|
@ -5073,7 +5104,10 @@ fn subscribe_for_editor_events(
|
||||||
excerpt.invalidate_outlines();
|
excerpt.invalidate_outlines();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outline_panel.update_non_fs_items(window, cx);
|
let update_cached_items = outline_panel.update_non_fs_items(window, cx);
|
||||||
|
if update_cached_items {
|
||||||
|
outline_panel.update_cached_entries(Some(UPDATE_DEBOUNCE), window, cx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue