Fix panel state (#13668)

Yongkang Chen created

In the latest update, panel loading occasionally occurred randomly,
either before or after workspace deserialization due to their
asynchronous nature. This update addresses the issue by ensuring panels
restore their state based on serialized data, synchronizing their
loading with workspace deserialization.

Release Notes:

- Fixed [#9638](https://github.com/zed-industries/zed/issues/9638)
- Fixed [#12954](https://github.com/zed-industries/zed/issues/12954)

Change summary

crates/workspace/src/dock.rs      | 36 +++++++++++++++++++-------------
crates/workspace/src/workspace.rs | 24 +++++++++++-----------
2 files changed, 33 insertions(+), 27 deletions(-)

Detailed changes

crates/workspace/src/dock.rs 🔗

@@ -431,25 +431,12 @@ impl Dock {
             }),
         ];
 
-        let name = panel.persistent_name().to_string();
-
         self.panel_entries.push(PanelEntry {
             panel: Arc::new(panel.clone()),
             _subscriptions: subscriptions,
         });
-        if let Some(serialized) = self.serialized_dock.clone() {
-            if serialized.active_panel == Some(name) {
-                self.activate_panel(self.panel_entries.len() - 1, cx);
-                if serialized.visible {
-                    self.set_open(true, cx);
-                }
-                if serialized.zoom {
-                    if let Some(panel) = self.active_panel() {
-                        panel.set_zoomed(true, cx)
-                    };
-                }
-            }
-        } else if panel.read(cx).starts_open(cx) {
+
+        if !self.restore_state(cx) && panel.read(cx).starts_open(cx) {
             self.activate_panel(self.panel_entries.len() - 1, cx);
             self.set_open(true, cx);
         }
@@ -457,6 +444,25 @@ impl Dock {
         cx.notify()
     }
 
+    pub fn restore_state(&mut self, cx: &mut ViewContext<Self>) -> bool {
+        if let Some(serialized) = self.serialized_dock.clone() {
+            if let Some(active_panel) = serialized.active_panel {
+                if let Some(idx) = self.panel_index_for_persistent_name(active_panel.as_str(), cx) {
+                    self.activate_panel(idx, cx);
+                }
+            }
+
+            if serialized.zoom {
+                if let Some(panel) = self.active_panel() {
+                    panel.set_zoomed(true, cx)
+                }
+            }
+            self.set_open(serialized.visible, cx);
+            return true;
+        }
+        return false;
+    }
+
     pub fn remove_panel<T: Panel>(&mut self, panel: &View<T>, cx: &mut ViewContext<Self>) {
         if let Some(panel_ix) = self
             .panel_entries

crates/workspace/src/workspace.rs 🔗

@@ -3813,18 +3813,18 @@ impl Workspace {
 
                 let docks = serialized_workspace.docks;
 
-                let right = docks.right.clone();
-                workspace
-                    .right_dock
-                    .update(cx, |dock, _| dock.serialized_dock = Some(right));
-                let left = docks.left.clone();
-                workspace
-                    .left_dock
-                    .update(cx, |dock, _| dock.serialized_dock = Some(left));
-                let bottom = docks.bottom.clone();
-                workspace
-                    .bottom_dock
-                    .update(cx, |dock, _| dock.serialized_dock = Some(bottom));
+                for (dock, serialized_dock) in [
+                    (&mut workspace.right_dock, docks.right),
+                    (&mut workspace.left_dock, docks.left),
+                    (&mut workspace.bottom_dock, docks.bottom),
+                ]
+                .iter_mut()
+                {
+                    dock.update(cx, |dock, cx| {
+                        dock.serialized_dock = Some(serialized_dock.clone());
+                        dock.restore_state(cx);
+                    });
+                }
 
                 cx.notify();
             })?;