diff --git a/crates/workspace/src/multi_workspace.rs b/crates/workspace/src/multi_workspace.rs index ffa1b07a735558df86fe3b4bb4007ad6647a45a8..6f853bfae20f4e79ce1a17338d9d9ad6e79af42c 100644 --- a/crates/workspace/src/multi_workspace.rs +++ b/crates/workspace/src/multi_workspace.rs @@ -302,8 +302,28 @@ impl MultiWorkspace { } fn focus_active_workspace(&self, window: &mut Window, cx: &mut App) { - let pane = self.workspace().read(cx).active_pane().clone(); - let focus_handle = pane.read(cx).focus_handle(cx); + // If a dock panel is zoomed, focus it instead of the center pane. + // Otherwise, focusing the center pane triggers dismiss_zoomed_items_to_reveal + // which closes the zoomed dock. + let focus_handle = { + let workspace = self.workspace().read(cx); + let mut target = None; + for dock in workspace.all_docks() { + let dock = dock.read(cx); + if dock.is_open() { + if let Some(panel) = dock.active_panel() { + if panel.is_zoomed(window, cx) { + target = Some(panel.panel_focus_handle(cx)); + break; + } + } + } + } + target.unwrap_or_else(|| { + let pane = workspace.active_pane().clone(); + pane.read(cx).focus_handle(cx) + }) + }; window.focus(&focus_handle, cx); } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 85f4a9d8e0eed422c13715f05be72a05b841f0e9..cbaa5c7451588c369602ca0e576d713c50a839d0 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -12724,6 +12724,101 @@ mod tests { }); } + #[gpui::test] + async fn test_panel_zoom_preserved_across_workspace_switch(cx: &mut TestAppContext) { + init_test(cx); + let fs = FakeFs::new(cx.executor()); + + let project_a = Project::test(fs.clone(), [], cx).await; + let project_b = Project::test(fs, [], cx).await; + + let multi_workspace_handle = + cx.add_window(|window, cx| MultiWorkspace::test_new(project_a.clone(), window, cx)); + + let workspace_a = multi_workspace_handle + .read_with(cx, |mw, _| mw.workspace().clone()) + .unwrap(); + + let _workspace_b = multi_workspace_handle + .update(cx, |mw, window, cx| { + mw.test_add_workspace(project_b, window, cx) + }) + .unwrap(); + + // Switch to workspace A + multi_workspace_handle + .update(cx, |mw, window, cx| { + mw.activate_index(0, window, cx); + }) + .unwrap(); + + let cx = &mut VisualTestContext::from_window(multi_workspace_handle.into(), cx); + + // Add a panel to workspace A's right dock and open the dock + let panel = workspace_a.update_in(cx, |workspace, window, cx| { + let panel = cx.new(|cx| TestPanel::new(DockPosition::Right, 100, cx)); + workspace.add_panel(panel.clone(), window, cx); + workspace + .right_dock() + .update(cx, |dock, cx| dock.set_open(true, window, cx)); + panel + }); + + // Focus the panel through the workspace (matching existing test pattern) + workspace_a.update_in(cx, |workspace, window, cx| { + workspace.toggle_panel_focus::(window, cx); + }); + + // Zoom the panel + panel.update_in(cx, |panel, window, cx| { + panel.set_zoomed(true, window, cx); + }); + + // Verify the panel is zoomed and the dock is open + workspace_a.update_in(cx, |workspace, window, cx| { + assert!( + workspace.right_dock().read(cx).is_open(), + "dock should be open before switch" + ); + assert!( + panel.is_zoomed(window, cx), + "panel should be zoomed before switch" + ); + assert!( + panel.read(cx).focus_handle(cx).contains_focused(window, cx), + "panel should be focused before switch" + ); + }); + + // Switch to workspace B + multi_workspace_handle + .update(cx, |mw, window, cx| { + mw.activate_index(1, window, cx); + }) + .unwrap(); + cx.run_until_parked(); + + // Switch back to workspace A + multi_workspace_handle + .update(cx, |mw, window, cx| { + mw.activate_index(0, window, cx); + }) + .unwrap(); + cx.run_until_parked(); + + // Verify the panel is still zoomed and the dock is still open + workspace_a.update_in(cx, |workspace, window, cx| { + assert!( + workspace.right_dock().read(cx).is_open(), + "dock should still be open after switching back" + ); + assert!( + panel.is_zoomed(window, cx), + "panel should still be zoomed after switching back" + ); + }); + } + fn pane_items_paths(pane: &Entity, cx: &App) -> Vec { pane.read(cx) .items()