Reduce amount of workspace serialization happening (#22730)

Part of https://github.com/zed-industries/zed/issues/16472

Reduces amount of workspace serialization happening by:
* fixing the deserialization logic: now it does not set panels that are
hidden to active
* cleaning up `active_panel_index` for docks that are closed, to avoid
emitting extra events for such closed docks
* adjusting outline panel to drop active editor subscriptions on
deactivation — this way, `cx.observe` on the dock with outline panel is
not triggered (used to be triggered on every selection change before)
* adjusting workspace dock drag listener to remember previous
coordinates and only resize the dock if those had changed
* adjusting workspace pane event listener to ignore
`pane::Event::UserSavedItem` and `pane::Event::ChangeItemTitle` that
seem to happen relatively frequently but not influence values that are
serialized for the workspace
* not using `cx.observe` on docks, instead explicitly serializing on
panel zoom and size changes

Release Notes:

- Reduced amount of workspace serialization happening
This commit is contained in:
Kirill Bulatov 2025-01-07 13:00:26 +02:00 committed by GitHub
parent 4c47728d6f
commit a827f54022
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 101 additions and 66 deletions

View file

@ -4656,18 +4656,27 @@ impl Panel for OutlinePanel {
.update(&mut cx, |outline_panel, cx| { .update(&mut cx, |outline_panel, cx| {
let old_active = outline_panel.active; let old_active = outline_panel.active;
outline_panel.active = active; outline_panel.active = active;
if active && old_active != active { if old_active != active {
if let Some((active_item, active_editor)) = outline_panel if active {
.workspace if let Some((active_item, active_editor)) =
.upgrade() outline_panel.workspace.upgrade().and_then(|workspace| {
.and_then(|workspace| workspace_active_editor(workspace.read(cx), cx)) workspace_active_editor(workspace.read(cx), cx)
{ })
if outline_panel.should_replace_active_item(active_item.as_ref()) { {
outline_panel.replace_active_editor(active_item, active_editor, cx); if outline_panel.should_replace_active_item(active_item.as_ref()) {
} else { outline_panel.replace_active_editor(
outline_panel.update_fs_entries(active_editor, None, cx) active_item,
active_editor,
cx,
);
} else {
outline_panel.update_fs_entries(active_editor, None, cx)
}
return;
} }
} else if !outline_panel.pinned { }
if !outline_panel.pinned {
outline_panel.clear_previous(cx); outline_panel.clear_previous(cx);
} }
} }
@ -4814,9 +4823,11 @@ fn subscribe_for_editor_events(
cx: &mut ViewContext<OutlinePanel>, cx: &mut ViewContext<OutlinePanel>,
) -> Subscription { ) -> Subscription {
let debounce = Some(UPDATE_DEBOUNCE); let debounce = Some(UPDATE_DEBOUNCE);
cx.subscribe( cx.subscribe(editor, move |outline_panel, editor, e: &EditorEvent, cx| {
editor, if !outline_panel.active {
move |outline_panel, editor, e: &EditorEvent, cx| match e { return;
}
match e {
EditorEvent::SelectionsChanged { local: true } => { EditorEvent::SelectionsChanged { local: true } => {
outline_panel.reveal_entry_for_selection(editor, cx); outline_panel.reveal_entry_for_selection(editor, cx);
cx.notify(); cx.notify();
@ -4921,8 +4932,8 @@ fn subscribe_for_editor_events(
outline_panel.update_non_fs_items(cx); outline_panel.update_non_fs_items(cx);
} }
_ => {} _ => {}
}, }
) })
} }
fn empty_icon() -> AnyElement { fn empty_icon() -> AnyElement {

View file

@ -170,6 +170,7 @@ impl From<&dyn PanelHandle> for AnyView {
pub struct Dock { pub struct Dock {
position: DockPosition, position: DockPosition,
panel_entries: Vec<PanelEntry>, panel_entries: Vec<PanelEntry>,
workspace: WeakView<Workspace>,
is_open: bool, is_open: bool,
active_panel_index: Option<usize>, active_panel_index: Option<usize>,
focus_handle: FocusHandle, focus_handle: FocusHandle,
@ -236,6 +237,7 @@ impl Dock {
}); });
Self { Self {
position, position,
workspace: workspace.downgrade(),
panel_entries: Default::default(), panel_entries: Default::default(),
active_panel_index: None, active_panel_index: None,
is_open: false, is_open: false,
@ -337,6 +339,9 @@ impl Dock {
self.is_open = open; self.is_open = open;
if let Some(active_panel) = self.active_panel_entry() { if let Some(active_panel) = self.active_panel_entry() {
active_panel.panel.set_active(open, cx); active_panel.panel.set_active(open, cx);
if !open {
self.active_panel_index = None;
}
} }
cx.notify(); cx.notify();
@ -354,6 +359,11 @@ impl Dock {
} }
} }
self.workspace
.update(cx, |workspace, cx| {
workspace.serialize_workspace(cx);
})
.ok();
cx.notify(); cx.notify();
} }
@ -484,7 +494,8 @@ impl Dock {
}, },
); );
if !self.restore_state(cx) && panel.read(cx).starts_open(cx) { self.restore_state(cx);
if panel.read(cx).starts_open(cx) {
self.activate_panel(index, cx); self.activate_panel(index, cx);
self.set_open(true, cx); self.set_open(true, cx);
} }
@ -652,9 +663,14 @@ impl Render for Dock {
) )
.on_mouse_up( .on_mouse_up(
MouseButton::Left, MouseButton::Left,
cx.listener(|v, e: &MouseUpEvent, cx| { cx.listener(|dock, e: &MouseUpEvent, cx| {
if e.click_count == 2 { if e.click_count == 2 {
v.resize_active_panel(None, cx); dock.resize_active_panel(None, cx);
dock.workspace
.update(cx, |workspace, cx| {
workspace.serialize_workspace(cx);
})
.ok();
cx.stop_propagation(); cx.stop_propagation();
} }
}), }),

View file

@ -743,6 +743,7 @@ pub struct Workspace {
weak_self: WeakView<Self>, weak_self: WeakView<Self>,
workspace_actions: Vec<Box<dyn Fn(Div, &mut ViewContext<Self>) -> Div>>, workspace_actions: Vec<Box<dyn Fn(Div, &mut ViewContext<Self>) -> Div>>,
zoomed: Option<AnyWeakView>, zoomed: Option<AnyWeakView>,
previous_dock_drag_coordinates: Option<Point<Pixels>>,
zoomed_position: Option<DockPosition>, zoomed_position: Option<DockPosition>,
center: PaneGroup, center: PaneGroup,
left_dock: View<Dock>, left_dock: View<Dock>,
@ -1020,18 +1021,6 @@ impl Workspace {
ThemeSettings::reload_current_theme(cx); ThemeSettings::reload_current_theme(cx);
}), }),
cx.observe(&left_dock, |this, _, cx| {
this.serialize_workspace(cx);
cx.notify();
}),
cx.observe(&bottom_dock, |this, _, cx| {
this.serialize_workspace(cx);
cx.notify();
}),
cx.observe(&right_dock, |this, _, cx| {
this.serialize_workspace(cx);
cx.notify();
}),
cx.on_release(|this, window, cx| { cx.on_release(|this, window, cx| {
this.app_state.workspace_store.update(cx, |store, _| { this.app_state.workspace_store.update(cx, |store, _| {
let window = window.downcast::<Self>().unwrap(); let window = window.downcast::<Self>().unwrap();
@ -1047,6 +1036,7 @@ impl Workspace {
weak_self: weak_handle.clone(), weak_self: weak_handle.clone(),
zoomed: None, zoomed: None,
zoomed_position: None, zoomed_position: None,
previous_dock_drag_coordinates: None,
center: PaneGroup::new(center_pane.clone()), center: PaneGroup::new(center_pane.clone()),
panes: vec![center_pane.clone()], panes: vec![center_pane.clone()],
panes_by_item: Default::default(), panes_by_item: Default::default(),
@ -3060,6 +3050,7 @@ impl Workspace {
event: &pane::Event, event: &pane::Event,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
let mut serialize_workspace = true;
match event { match event {
pane::Event::AddItem { item } => { pane::Event::AddItem { item } => {
item.added_to_pane(self, pane, cx); item.added_to_pane(self, pane, cx);
@ -3070,10 +3061,14 @@ impl Workspace {
pane::Event::Split(direction) => { pane::Event::Split(direction) => {
self.split_and_clone(pane, *direction, cx); self.split_and_clone(pane, *direction, cx);
} }
pane::Event::JoinIntoNext => self.join_pane_into_next(pane, cx), pane::Event::JoinIntoNext => {
pane::Event::JoinAll => self.join_all_panes(cx), self.join_pane_into_next(pane, cx);
}
pane::Event::JoinAll => {
self.join_all_panes(cx);
}
pane::Event::Remove { focus_on_pane } => { pane::Event::Remove { focus_on_pane } => {
self.remove_pane(pane, focus_on_pane.clone(), cx) self.remove_pane(pane, focus_on_pane.clone(), cx);
} }
pane::Event::ActivateItem { local } => { pane::Event::ActivateItem { local } => {
cx.on_next_frame(|_, cx| { cx.on_next_frame(|_, cx| {
@ -3091,16 +3086,20 @@ impl Workspace {
self.update_active_view_for_followers(cx); self.update_active_view_for_followers(cx);
} }
} }
pane::Event::UserSavedItem { item, save_intent } => cx.emit(Event::UserSavedItem { pane::Event::UserSavedItem { item, save_intent } => {
pane: pane.downgrade(), cx.emit(Event::UserSavedItem {
item: item.boxed_clone(), pane: pane.downgrade(),
save_intent: *save_intent, item: item.boxed_clone(),
}), save_intent: *save_intent,
});
serialize_workspace = false;
}
pane::Event::ChangeItemTitle => { pane::Event::ChangeItemTitle => {
if pane == self.active_pane { if pane == self.active_pane {
self.active_item_path_changed(cx); self.active_item_path_changed(cx);
} }
self.update_window_edited(cx); self.update_window_edited(cx);
serialize_workspace = false;
} }
pane::Event::RemoveItem { .. } => {} pane::Event::RemoveItem { .. } => {}
pane::Event::RemovedItem { item_id } => { pane::Event::RemovedItem { item_id } => {
@ -3139,7 +3138,9 @@ impl Workspace {
} }
} }
self.serialize_workspace(cx); if serialize_workspace {
self.serialize_workspace(cx);
}
} }
pub fn unfollow_in_pane( pub fn unfollow_in_pane(
@ -4900,32 +4901,39 @@ impl Render for Workspace {
}) })
.when(self.zoomed.is_none(), |this| { .when(self.zoomed.is_none(), |this| {
this.on_drag_move(cx.listener( this.on_drag_move(cx.listener(
|workspace, e: &DragMoveEvent<DraggedDock>, cx| { move |workspace, e: &DragMoveEvent<DraggedDock>, cx| {
match e.drag(cx).0 { if workspace.previous_dock_drag_coordinates
DockPosition::Left => { != Some(e.event.position)
resize_left_dock( {
e.event.position.x workspace.previous_dock_drag_coordinates =
- workspace.bounds.left(), Some(e.event.position);
workspace, match e.drag(cx).0 {
cx, DockPosition::Left => {
); resize_left_dock(
} e.event.position.x
DockPosition::Right => { - workspace.bounds.left(),
resize_right_dock( workspace,
workspace.bounds.right() cx,
- e.event.position.x, );
workspace, }
cx, DockPosition::Right => {
); resize_right_dock(
} workspace.bounds.right()
DockPosition::Bottom => { - e.event.position.x,
resize_bottom_dock( workspace,
workspace.bounds.bottom() cx,
- e.event.position.y, );
workspace, }
cx, DockPosition::Bottom => {
); resize_bottom_dock(
} workspace.bounds.bottom()
- e.event.position.y,
workspace,
cx,
);
}
};
workspace.serialize_workspace(cx);
} }
}, },
)) ))