Remove focus side effects from toggle dock commands

Mikayla Maki and max created

co-authored-by: max <max@zed.dev>

Change summary

crates/workspace/src/dock.rs      |  7 --
crates/workspace/src/workspace.rs | 77 +++++++++++++++++++++++++++++---
2 files changed, 70 insertions(+), 14 deletions(-)

Detailed changes

crates/workspace/src/dock.rs 🔗

@@ -201,7 +201,7 @@ impl Dock {
         self.active_panel_index
     }
 
-    pub fn set_open(&mut self, open: bool, cx: &mut ViewContext<Self>) {
+    pub(crate) fn set_open(&mut self, open: bool, cx: &mut ViewContext<Self>) {
         if open != self.is_open {
             self.is_open = open;
             if let Some(active_panel) = self.panel_entries.get(self.active_panel_index) {
@@ -212,11 +212,6 @@ impl Dock {
         }
     }
 
-    pub fn toggle_open(&mut self, cx: &mut ViewContext<Self>) {
-        self.set_open(!self.is_open, cx);
-        cx.notify();
-    }
-
     pub fn set_panel_zoomed(
         &mut self,
         panel: &AnyViewHandle,

crates/workspace/src/workspace.rs 🔗

@@ -1583,10 +1583,27 @@ impl Workspace {
             DockPosition::Bottom => &self.bottom_dock,
             DockPosition::Right => &self.right_dock,
         };
-        dock.update(cx, |dock, cx| {
-            let open = !dock.is_open();
-            dock.set_open(open, cx);
+        let focus_center = dock.update(cx, |dock, cx| {
+            let was_open = dock.is_open();
+            dock.set_open(!was_open, cx);
+
+            if let Some(active_panel) = dock.active_panel() {
+                if was_open {
+                    if active_panel.has_focus(cx) {
+                        return true;
+                    }
+                } else if active_panel.is_zoomed(cx) {
+                    cx.focus(active_panel.as_any());
+                }
+            }
+
+            false
         });
+
+        if focus_center {
+            cx.focus_self();
+        }
+
         cx.notify();
         self.serialize_workspace(cx);
     }
@@ -1639,15 +1656,13 @@ impl Workspace {
                             if panel.is_zoomed(cx) {
                                 dock.set_open(false, cx);
                             }
-                            true
+                            return true
                         } else {
                             dock.set_open(true, cx);
                             cx.focus(panel.as_any());
-                            false
                         }
-                    } else {
-                        false
                     }
+                    false
                 });
 
                 if focus_center {
@@ -4151,7 +4166,7 @@ mod tests {
     }
 
     #[gpui::test]
-    async fn test_toggle_panel_focus(cx: &mut gpui::TestAppContext) {
+    async fn test_toggle_docks_and_panels(cx: &mut gpui::TestAppContext) {
         init_test(cx);
         let fs = FakeFs::new(cx.background());
 
@@ -4191,6 +4206,28 @@ mod tests {
             assert!(!panel.has_focus(cx));
         });
 
+        // Close the dock
+        workspace.update(cx, |workspace, cx| {
+            workspace.toggle_dock(DockPosition::Right, cx);
+        });
+
+        workspace.read_with(cx, |workspace, cx| {
+            assert!(!workspace.right_dock().read(cx).is_open());
+            assert!(!panel.is_zoomed(cx));
+            assert!(!panel.has_focus(cx));
+        });
+
+        // Open the dock
+        workspace.update(cx, |workspace, cx| {
+            workspace.toggle_dock(DockPosition::Right, cx);
+        });
+
+        workspace.read_with(cx, |workspace, cx| {
+            assert!(workspace.right_dock().read(cx).is_open());
+            assert!(!panel.is_zoomed(cx));
+            assert!(!panel.has_focus(cx));
+        });
+
         // Focus and zoom panel
         panel.update(cx, |panel, cx| {
             cx.focus_self();
@@ -4224,6 +4261,30 @@ mod tests {
             assert!(panel.is_zoomed(cx));
             assert!(panel.has_focus(cx));
         });
+
+        // Close the dock while it is zoomed
+        workspace.update(cx, |workspace, cx| {
+            workspace.toggle_dock(DockPosition::Right, cx)
+        });
+
+        workspace.read_with(cx, |workspace, cx| {
+            assert!(!workspace.right_dock().read(cx).is_open());
+            assert!(panel.is_zoomed(cx));
+            assert!(workspace.zoomed.is_none());
+            assert!(!panel.has_focus(cx));
+        });
+
+        // Opening the dock, when it's zoomed, retains focus
+        workspace.update(cx, |workspace, cx| {
+            workspace.toggle_dock(DockPosition::Right, cx)
+        });
+
+        workspace.read_with(cx, |workspace, cx| {
+            assert!(workspace.right_dock().read(cx).is_open());
+            assert!(panel.is_zoomed(cx));
+            assert!(workspace.zoomed.is_some());
+            assert!(panel.has_focus(cx));
+        });
     }
 
     #[gpui::test]