Focus on toggle dock (#2612)

Mikayla Maki created

This PR updates some dock behaviors. Now the toggle-dock commands
(cmd-j/b/r) also toggle focus. This also adds zoom serialization to the
docks.

Release Notes:
- Bug fix: Toggle dock commands (cmd-j/b/r) now move focus 
- Bug fix: Dock zoom is now restored with the rest of the workspace

Change summary

crates/workspace/src/persistence.rs       | 27 +++++++++--
crates/workspace/src/persistence/model.rs |  6 ++
crates/workspace/src/workspace.rs         | 54 +++++++++++++++++++++---
crates/zed/src/zed.rs                     |  2 
4 files changed, 75 insertions(+), 14 deletions(-)

Detailed changes

crates/workspace/src/persistence.rs 🔗

@@ -162,6 +162,12 @@ define_connection! {
         ALTER TABLE workspaces ADD COLUMN right_dock_active_panel TEXT;
         ALTER TABLE workspaces ADD COLUMN bottom_dock_visible INTEGER; //bool
         ALTER TABLE workspaces ADD COLUMN bottom_dock_active_panel TEXT;
+    ),
+    // Add panel zoom persistence
+    sql!(
+        ALTER TABLE workspaces ADD COLUMN left_dock_zoom INTEGER; //bool
+        ALTER TABLE workspaces ADD COLUMN right_dock_zoom INTEGER; //bool
+        ALTER TABLE workspaces ADD COLUMN bottom_dock_zoom INTEGER; //bool
     )];
 }
 
@@ -196,10 +202,13 @@ impl WorkspaceDb {
                     display,
                     left_dock_visible,
                     left_dock_active_panel,
+                    left_dock_zoom,
                     right_dock_visible,
                     right_dock_active_panel,
+                    right_dock_zoom,
                     bottom_dock_visible,
-                    bottom_dock_active_panel
+                    bottom_dock_active_panel,
+                    bottom_dock_zoom
                 FROM workspaces
                 WHERE workspace_location = ?
             })
@@ -244,22 +253,28 @@ impl WorkspaceDb {
                         workspace_location,
                         left_dock_visible,
                         left_dock_active_panel,
+                        left_dock_zoom,
                         right_dock_visible,
                         right_dock_active_panel,
+                        right_dock_zoom,
                         bottom_dock_visible,
                         bottom_dock_active_panel,
+                        bottom_dock_zoom,
                         timestamp
                     )
-                    VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, CURRENT_TIMESTAMP)
+                    VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, CURRENT_TIMESTAMP)
                     ON CONFLICT DO
                     UPDATE SET
                         workspace_location = ?2,
                         left_dock_visible = ?3,
                         left_dock_active_panel = ?4,
-                        right_dock_visible = ?5,
-                        right_dock_active_panel = ?6,
-                        bottom_dock_visible = ?7,
-                        bottom_dock_active_panel = ?8,
+                        left_dock_zoom = ?5,
+                        right_dock_visible = ?6,
+                        right_dock_active_panel = ?7,
+                        right_dock_zoom = ?8,
+                        bottom_dock_visible = ?9,
+                        bottom_dock_active_panel = ?10,
+                        bottom_dock_zoom = ?11,
                         timestamp = CURRENT_TIMESTAMP
                 ))?((workspace.id, &workspace.location, workspace.docks))
                 .context("Updating workspace")?;

crates/workspace/src/persistence/model.rs 🔗

@@ -100,16 +100,19 @@ impl Bind for DockStructure {
 pub struct DockData {
     pub(crate) visible: bool,
     pub(crate) active_panel: Option<String>,
+    pub(crate) zoom: bool,
 }
 
 impl Column for DockData {
     fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
         let (visible, next_index) = Option::<bool>::column(statement, start_index)?;
         let (active_panel, next_index) = Option::<String>::column(statement, next_index)?;
+        let (zoom, next_index) = Option::<bool>::column(statement, next_index)?;
         Ok((
             DockData {
                 visible: visible.unwrap_or(false),
                 active_panel,
+                zoom: zoom.unwrap_or(false),
             },
             next_index,
         ))
@@ -119,7 +122,8 @@ impl Column for DockData {
 impl Bind for DockData {
     fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
         let next_index = statement.bind(&self.visible, start_index)?;
-        statement.bind(&self.active_panel, next_index)
+        let next_index = statement.bind(&self.active_panel, next_index)?;
+        statement.bind(&self.zoom, next_index)
     }
 }
 

crates/workspace/src/workspace.rs 🔗

@@ -1599,9 +1599,7 @@ impl Workspace {
                         focus_center = true;
                     }
                 } else {
-                    if active_panel.is_zoomed(cx) {
-                        cx.focus(active_panel.as_any());
-                    }
+                    cx.focus(active_panel.as_any());
                     reveal_dock = true;
                 }
             }
@@ -2850,7 +2848,7 @@ impl Workspace {
         cx.notify();
     }
 
-    fn serialize_workspace(&self, cx: &AppContext) {
+    fn serialize_workspace(&self, cx: &ViewContext<Self>) {
         fn serialize_pane_handle(
             pane_handle: &ViewHandle<Pane>,
             cx: &AppContext,
@@ -2893,7 +2891,7 @@ impl Workspace {
             }
         }
 
-        fn build_serialized_docks(this: &Workspace, cx: &AppContext) -> DockStructure {
+        fn build_serialized_docks(this: &Workspace, cx: &ViewContext<Workspace>) -> DockStructure {
             let left_dock = this.left_dock.read(cx);
             let left_visible = left_dock.is_open();
             let left_active_panel = left_dock.visible_panel().and_then(|panel| {
@@ -2902,6 +2900,10 @@ impl Workspace {
                         .to_string(),
                 )
             });
+            let left_dock_zoom = left_dock
+                .visible_panel()
+                .map(|panel| panel.is_zoomed(cx))
+                .unwrap_or(false);
 
             let right_dock = this.right_dock.read(cx);
             let right_visible = right_dock.is_open();
@@ -2911,6 +2913,10 @@ impl Workspace {
                         .to_string(),
                 )
             });
+            let right_dock_zoom = right_dock
+                .visible_panel()
+                .map(|panel| panel.is_zoomed(cx))
+                .unwrap_or(false);
 
             let bottom_dock = this.bottom_dock.read(cx);
             let bottom_visible = bottom_dock.is_open();
@@ -2920,19 +2926,26 @@ impl Workspace {
                         .to_string(),
                 )
             });
+            let bottom_dock_zoom = bottom_dock
+                .visible_panel()
+                .map(|panel| panel.is_zoomed(cx))
+                .unwrap_or(false);
 
             DockStructure {
                 left: DockData {
                     visible: left_visible,
                     active_panel: left_active_panel,
+                    zoom: left_dock_zoom,
                 },
                 right: DockData {
                     visible: right_visible,
                     active_panel: right_active_panel,
+                    zoom: right_dock_zoom,
                 },
                 bottom: DockData {
                     visible: bottom_visible,
                     active_panel: bottom_active_panel,
+                    zoom: bottom_dock_zoom,
                 },
             }
         }
@@ -3045,14 +3058,31 @@ impl Workspace {
                                 dock.activate_panel(ix, cx);
                             }
                         }
+                                dock.active_panel()
+                                    .map(|panel| {
+                                        panel.set_zoomed(docks.left.zoom, cx)
+                                    });
+                                if docks.left.visible && docks.left.zoom {
+                                    cx.focus_self()
+                                }
                     });
+                    // TODO: I think the bug is that setting zoom or active undoes the bottom zoom or something
                     workspace.right_dock.update(cx, |dock, cx| {
                         dock.set_open(docks.right.visible, cx);
                         if let Some(active_panel) = docks.right.active_panel {
                             if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) {
                                 dock.activate_panel(ix, cx);
+
                             }
                         }
+                                dock.active_panel()
+                                    .map(|panel| {
+                                        panel.set_zoomed(docks.right.zoom, cx)
+                                    });
+
+                                if docks.right.visible && docks.right.zoom {
+                                    cx.focus_self()
+                                }
                     });
                     workspace.bottom_dock.update(cx, |dock, cx| {
                         dock.set_open(docks.bottom.visible, cx);
@@ -3061,8 +3091,18 @@ impl Workspace {
                                 dock.activate_panel(ix, cx);
                             }
                         }
+
+                        dock.active_panel()
+                            .map(|panel| {
+                                panel.set_zoomed(docks.bottom.zoom, cx)
+                            });
+
+                        if docks.bottom.visible && docks.bottom.zoom {
+                            cx.focus_self()
+                        }
                     });
 
+
                     cx.notify();
                 })?;
 
@@ -4425,7 +4465,7 @@ mod tests {
         workspace.read_with(cx, |workspace, cx| {
             assert!(workspace.right_dock().read(cx).is_open());
             assert!(!panel.is_zoomed(cx));
-            assert!(!panel.has_focus(cx));
+            assert!(panel.has_focus(cx));
         });
 
         // Focus and zoom panel
@@ -4500,7 +4540,7 @@ mod tests {
         workspace.read_with(cx, |workspace, cx| {
             let pane = pane.read(cx);
             assert!(!pane.is_zoomed());
-            assert!(pane.has_focus());
+            assert!(!pane.has_focus());
             assert!(workspace.right_dock().read(cx).is_open());
             assert!(workspace.zoomed.is_none());
         });

crates/zed/src/zed.rs 🔗

@@ -384,6 +384,8 @@ pub fn initialize_workspace(
                 workspace.toggle_dock(project_panel_position, cx);
             }
 
+            cx.focus_self();
+
             workspace.add_panel(terminal_panel, cx);
             if let Some(assistant_panel) = assistant_panel {
                 workspace.add_panel(assistant_panel, cx);