Reduce frequency of workspace save (#11183)

Conrad Irwin and Mikayla created

Co-Authored-By: Mikayla <mikayla@zed.dev>

Release Notes:


- N/A

---------

Co-authored-by: Mikayla <mikayla@zed.dev>

Change summary

crates/workspace/src/item.rs       |  2 
crates/workspace/src/pane_group.rs |  4 +-
crates/workspace/src/workspace.rs  | 59 ++++++++++++++++++++-----------
crates/zed/src/zed.rs              |  3 +
4 files changed, 42 insertions(+), 26 deletions(-)

Detailed changes

crates/workspace/src/item.rs 🔗

@@ -603,7 +603,7 @@ impl<T: Item> ItemHandle for View<T> {
         }
 
         cx.defer(|workspace, cx| {
-            workspace.serialize_workspace(cx).detach();
+            workspace.serialize_workspace(cx);
         });
     }
 

crates/workspace/src/pane_group.rs 🔗

@@ -749,7 +749,7 @@ mod element {
             }
 
             workspace
-                .update(cx, |this, cx| this.schedule_serialize(cx))
+                .update(cx, |this, cx| this.serialize_workspace(cx))
                 .log_err();
             cx.stop_propagation();
             cx.refresh();
@@ -935,7 +935,7 @@ mod element {
                                     let mut borrow = flexes.lock();
                                     *borrow = vec![1.; borrow.len()];
                                     workspace
-                                        .update(cx, |this, cx| this.schedule_serialize(cx))
+                                        .update(cx, |this, cx| this.serialize_workspace(cx))
                                         .log_err();
 
                                     cx.refresh();

crates/workspace/src/workspace.rs 🔗

@@ -631,7 +631,7 @@ impl Workspace {
 
                 project::Event::WorktreeRemoved(_) | project::Event::WorktreeAdded => {
                     this.update_window_title(cx);
-                    this.serialize_workspace(cx).detach();
+                    this.serialize_workspace(cx);
                 }
 
                 project::Event::DisconnectedFromHost => {
@@ -823,15 +823,15 @@ impl Workspace {
                 ThemeSettings::reload_current_theme(cx);
             }),
             cx.observe(&left_dock, |this, _, cx| {
-                this.serialize_workspace(cx).detach();
+                this.serialize_workspace(cx);
                 cx.notify();
             }),
             cx.observe(&bottom_dock, |this, _, cx| {
-                this.serialize_workspace(cx).detach();
+                this.serialize_workspace(cx);
                 cx.notify();
             }),
             cx.observe(&right_dock, |this, _, cx| {
-                this.serialize_workspace(cx).detach();
+                this.serialize_workspace(cx);
                 cx.notify();
             }),
             cx.on_release(|this, window, cx| {
@@ -1897,7 +1897,7 @@ impl Workspace {
         }
 
         cx.notify();
-        self.serialize_workspace(cx).detach();
+        self.serialize_workspace(cx);
     }
 
     pub fn close_all_docks(&mut self, cx: &mut ViewContext<Self>) {
@@ -1911,7 +1911,7 @@ impl Workspace {
 
         cx.focus_self();
         cx.notify();
-        self.serialize_workspace(cx).detach();
+        self.serialize_workspace(cx);
     }
 
     /// Transfer focus to the panel of the given type.
@@ -1934,6 +1934,8 @@ impl Workspace {
         cx: &mut ViewContext<Self>,
         should_focus: impl Fn(&dyn PanelHandle, &mut ViewContext<Dock>) -> bool,
     ) -> Option<Arc<dyn PanelHandle>> {
+        let mut result_panel = None;
+        let mut serialize = false;
         for dock in [&self.left_dock, &self.bottom_dock, &self.right_dock] {
             if let Some(panel_index) = dock.read(cx).panel_index_for_type::<T>() {
                 let mut focus_center = false;
@@ -1956,12 +1958,18 @@ impl Workspace {
                     self.active_pane.update(cx, |pane, cx| pane.focus(cx))
                 }
 
-                self.serialize_workspace(cx).detach();
-                cx.notify();
-                return panel;
+                result_panel = panel;
+                serialize = true;
+                break;
             }
         }
-        None
+
+        if serialize {
+            self.serialize_workspace(cx);
+        }
+
+        cx.notify();
+        result_panel
     }
 
     /// Open the panel of the given type
@@ -2559,7 +2567,7 @@ impl Workspace {
             }
         }
 
-        self.serialize_workspace(cx).detach();
+        self.serialize_workspace(cx);
     }
 
     pub fn split_pane(
@@ -3511,17 +3519,22 @@ impl Workspace {
         cx.notify();
     }
 
-    fn schedule_serialize(&mut self, cx: &mut ViewContext<Self>) {
-        self._schedule_serialize = Some(cx.spawn(|this, mut cx| async move {
-            cx.background_executor()
-                .timer(Duration::from_millis(100))
-                .await;
-            this.update(&mut cx, |this, cx| this.serialize_workspace(cx).detach())
+    fn serialize_workspace(&mut self, cx: &mut ViewContext<Self>) {
+        if self._schedule_serialize.is_none() {
+            self._schedule_serialize = Some(cx.spawn(|this, mut cx| async move {
+                cx.background_executor()
+                    .timer(Duration::from_millis(100))
+                    .await;
+                this.update(&mut cx, |this, cx| {
+                    this.serialize_workspace_internal(cx).detach();
+                    this._schedule_serialize.take();
+                })
                 .log_err();
-        }));
+            }));
+        }
     }
 
-    fn serialize_workspace(&self, cx: &mut WindowContext) -> Task<()> {
+    fn serialize_workspace_internal(&self, cx: &mut WindowContext) -> Task<()> {
         fn serialize_pane_handle(pane_handle: &View<Pane>, cx: &WindowContext) -> SerializedPane {
             let (items, active) = {
                 let pane = pane_handle.read(cx);
@@ -3741,9 +3754,11 @@ impl Workspace {
             })?;
 
             // Serialize ourself to make sure our timestamps and any pane / item changes are replicated
-            workspace.update(&mut cx, |workspace, cx| {
-                workspace.serialize_workspace(cx).detach()
-            })?;
+            workspace
+                .update(&mut cx, |workspace, cx| {
+                    workspace.serialize_workspace_internal(cx).detach();
+                })
+                .ok();
 
             Ok(opened_items)
         })

crates/zed/src/zed.rs 🔗

@@ -2842,11 +2842,12 @@ mod tests {
             handle_keymap_file_changes(keymap_rx, cx);
         });
         workspace
-            .update(cx, |workspace, _| {
+            .update(cx, |workspace, cx| {
                 workspace.register_action(|_, _: &A, _cx| {});
                 workspace.register_action(|_, _: &B, _cx| {});
                 workspace.register_action(|_, _: &ActivatePreviousPane, _cx| {});
                 workspace.register_action(|_, _: &ActivatePrevItem, _cx| {});
+                cx.notify();
             })
             .unwrap();
         executor.run_until_parked();