workspace: Add Toggle actions to all the side panels (#49395)

Release Notes:

- Add `toggle` actions to all panels to toggle visibility

---------

Co-authored-by: Anthony Eid <hello@anthonyeid.me>
Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com>
This commit is contained in:
Cameron Mcloughlin 2026-02-17 23:06:27 +00:00 committed by GitHub
parent d2aa2e0c5a
commit ee9191ecd2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 198 additions and 3 deletions

View file

@ -145,6 +145,10 @@
"restore_on_file_reopen": true,
// Whether to automatically close files that have been deleted on disk.
"close_on_file_delete": false,
// Whether toggling a panel (e.g. with its keyboard shortcut) also closes
// the panel when it is already focused, instead of just moving focus back
// to the editor.
"close_panel_on_toggle": false,
// Relative size of the drop target in the editor that will open dropped file as a split pane (0-0.5)
// E.g. 0.25 == If you drop onto the top/bottom quarter of the pane a new vertical split will be used
// If you drop onto the left/right quarter of the pane a new horizontal split will be used

View file

@ -75,7 +75,7 @@ use zed_actions::{
agent::{
OpenAcpOnboardingModal, OpenOnboardingModal, OpenSettings, ResetAgentZoom, ResetOnboarding,
},
assistant::{OpenRulesLibrary, ToggleFocus},
assistant::{OpenRulesLibrary, Toggle, ToggleFocus},
};
const AGENT_PANEL_KEY: &str = "agent_panel";
@ -789,6 +789,22 @@ impl AgentPanel {
}
}
pub fn toggle(
workspace: &mut Workspace,
_: &Toggle,
window: &mut Window,
cx: &mut Context<Workspace>,
) {
if workspace
.panel::<Self>(cx)
.is_some_and(|panel| panel.read(cx).enabled(cx))
{
if !workspace.toggle_panel_focus::<Self>(window, cx) {
workspace.close_panel::<Self>(window, cx);
}
}
}
pub(crate) fn prompt_store(&self) -> &Option<Entity<PromptStore>> {
&self.prompt_store
}

View file

@ -45,6 +45,8 @@ use workspace::{
actions!(
collab_panel,
[
/// Toggles the collab panel.
Toggle,
/// Toggles focus on the collaboration panel.
ToggleFocus,
/// Removes the selected channel or contact.
@ -93,6 +95,11 @@ pub fn init(cx: &mut App) {
})
}
});
workspace.register_action(|workspace, _: &Toggle, window, cx| {
if !workspace.toggle_panel_focus::<CollabPanel>(window, cx) {
workspace.close_panel::<CollabPanel>(window, cx);
}
});
workspace.register_action(|_, _: &OpenChannelNotes, window, cx| {
let channel_id = ActiveCall::global(cx)
.read(cx)

View file

@ -76,6 +76,8 @@ pub struct NotificationPresenter {
actions!(
notification_panel,
[
/// Toggles the notification panel.
Toggle,
/// Toggles focus on the notification panel.
ToggleFocus
]
@ -86,6 +88,11 @@ pub fn init(cx: &mut App) {
workspace.register_action(|workspace, _: &ToggleFocus, window, cx| {
workspace.toggle_panel_focus::<NotificationPanel>(window, cx);
});
workspace.register_action(|workspace, _: &Toggle, window, cx| {
if !workspace.toggle_panel_focus::<NotificationPanel>(window, cx) {
workspace.close_panel::<NotificationPanel>(window, cx);
}
});
})
.detach();
}

View file

@ -14,8 +14,8 @@ use tasks_ui::{Spawn, TaskOverrides};
use ui::{FluentBuilder, InteractiveElement};
use util::maybe;
use workspace::{ItemHandle, ShutdownDebugAdapters, Workspace};
use zed_actions::ToggleFocus;
use zed_actions::debugger::OpenOnboardingModal;
use zed_actions::{Toggle, ToggleFocus};
pub mod attach_modal;
pub mod debugger_panel;
@ -121,6 +121,11 @@ pub fn init(cx: &mut App) {
.register_action(|workspace, _: &ToggleFocus, window, cx| {
workspace.toggle_panel_focus::<DebugPanel>(window, cx);
})
.register_action(|workspace, _: &Toggle, window, cx| {
if !workspace.toggle_panel_focus::<DebugPanel>(window, cx) {
workspace.close_panel::<DebugPanel>(window, cx);
}
})
.register_action(|workspace: &mut Workspace, _: &Start, window, cx| {
NewProcessModal::show(workspace, window, NewProcessMode::Debug, None, cx);
})

View file

@ -84,6 +84,8 @@ actions!(
[
/// Closes the git panel.
Close,
/// Toggles the git panel.
Toggle,
/// Toggles focus on the git panel.
ToggleFocus,
/// Opens the git panel menu.
@ -225,6 +227,11 @@ pub fn register(workspace: &mut Workspace) {
workspace.register_action(|workspace, _: &ToggleFocus, window, cx| {
workspace.toggle_panel_focus::<GitPanel>(window, cx);
});
workspace.register_action(|workspace, _: &Toggle, window, cx| {
if !workspace.toggle_panel_focus::<GitPanel>(window, cx) {
workspace.close_panel::<GitPanel>(window, cx);
}
});
workspace.register_action(|workspace, _: &ExpandCommitEditor, window, cx| {
CommitModal::toggle(workspace, None, window, cx)
});

View file

@ -93,6 +93,8 @@ actions!(
ToggleActiveEditorPin,
/// Unfolds the selected directory.
UnfoldDirectory,
/// Toggles the outline panel.
Toggle,
/// Toggles focus on the outline panel.
ToggleFocus,
]
@ -670,6 +672,11 @@ pub fn init(cx: &mut App) {
workspace.register_action(|workspace, _: &ToggleFocus, window, cx| {
workspace.toggle_panel_focus::<OutlinePanel>(window, cx);
});
workspace.register_action(|workspace, _: &Toggle, window, cx| {
if !workspace.toggle_panel_focus::<OutlinePanel>(window, cx) {
workspace.close_panel::<OutlinePanel>(window, cx);
}
});
})
.detach();
}

View file

@ -75,7 +75,10 @@ use workspace::{
notifications::{DetachAndPromptErr, NotifyResultExt, NotifyTaskExt},
};
use worktree::CreatedEntry;
use zed_actions::{project_panel::ToggleFocus, workspace::OpenWithSystem};
use zed_actions::{
project_panel::{Toggle, ToggleFocus},
workspace::OpenWithSystem,
};
const PROJECT_PANEL_KEY: &str = "ProjectPanel";
const NEW_ENTRY_ID: ProjectEntryId = ProjectEntryId::MAX;
@ -418,6 +421,11 @@ pub fn init(cx: &mut App) {
workspace.register_action(|workspace, _: &ToggleFocus, window, cx| {
workspace.toggle_panel_focus::<ProjectPanel>(window, cx);
});
workspace.register_action(|workspace, _: &Toggle, window, cx| {
if !workspace.toggle_panel_focus::<ProjectPanel>(window, cx) {
workspace.close_panel::<ProjectPanel>(window, cx);
}
});
workspace.register_action(|workspace, _: &ToggleHideGitIgnore, _, cx| {
let fs = workspace.app_state().fs.clone();

View file

@ -952,6 +952,7 @@ impl VsCodeSettings {
bottom_dock_layout: None,
centered_layout: None,
close_on_file_delete: None,
close_panel_on_toggle: None,
command_aliases: Default::default(),
confirm_quit: self.read_enum("window.confirmBeforeClose", |s| match s {
"always" | "keyboardOnly" => Some(true),

View file

@ -113,6 +113,12 @@ pub struct WorkspaceSettingsContent {
///
/// Default: true
pub zoomed_padding: Option<bool>,
/// Whether toggling a panel (e.g. with its keyboard shortcut) also closes
/// the panel when it is already focused, instead of just moving focus back
/// to the editor.
///
/// Default: false
pub close_panel_on_toggle: Option<bool>,
/// What draws window decorations/titlebar, the client application (Zed) or display server
/// Default: client
pub window_decorations: Option<WindowDecorations>,

View file

@ -3630,6 +3630,8 @@ impl Workspace {
/// Focus the panel of the given type if it isn't already focused. If it is
/// already focused, then transfer focus back to the workspace center.
/// When the `close_panel_on_toggle` setting is enabled, also closes the
/// panel when transferring focus back to the center.
pub fn toggle_panel_focus<T: Panel>(
&mut self,
window: &mut Window,
@ -3641,6 +3643,10 @@ impl Workspace {
did_focus_panel
});
if !did_focus_panel && WorkspaceSettings::get_global(cx).close_panel_on_toggle {
self.close_panel::<T>(window, cx);
}
telemetry::event!(
"Panel Button Clicked",
name = T::persistent_name(),
@ -10546,6 +10552,118 @@ mod tests {
});
}
#[gpui::test]
async fn test_close_panel_on_toggle(cx: &mut gpui::TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.executor());
let project = Project::test(fs, [], cx).await;
let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project, window, cx));
let panel = workspace.update_in(cx, |workspace, window, cx| {
let panel = cx.new(|cx| TestPanel::new(DockPosition::Right, 100, cx));
workspace.add_panel(panel.clone(), window, cx);
panel
});
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
pane.update_in(cx, |pane, window, cx| {
let item = cx.new(TestItem::new);
pane.add_item(Box::new(item), true, true, None, window, cx);
});
// Enable close_panel_on_toggle
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings(cx, |settings| {
settings.workspace.close_panel_on_toggle = Some(true);
});
});
// Panel starts closed. Toggling should open and focus it.
workspace.update_in(cx, |workspace, window, cx| {
assert!(!workspace.right_dock().read(cx).is_open());
workspace.toggle_panel_focus::<TestPanel>(window, cx);
});
workspace.update_in(cx, |workspace, window, cx| {
assert!(
workspace.right_dock().read(cx).is_open(),
"Dock should be open after toggling from center"
);
assert!(
panel.read(cx).focus_handle(cx).contains_focused(window, cx),
"Panel should be focused after toggling from center"
);
});
// Panel is open and focused. Toggling should close the panel and
// return focus to the center.
workspace.update_in(cx, |workspace, window, cx| {
workspace.toggle_panel_focus::<TestPanel>(window, cx);
});
workspace.update_in(cx, |workspace, window, cx| {
assert!(
!workspace.right_dock().read(cx).is_open(),
"Dock should be closed after toggling from focused panel"
);
assert!(
!panel.read(cx).focus_handle(cx).contains_focused(window, cx),
"Panel should not be focused after toggling from focused panel"
);
});
// Open the dock and focus something else so the panel is open but not
// focused. Toggling should focus the panel (not close it).
workspace.update_in(cx, |workspace, window, cx| {
workspace
.right_dock()
.update(cx, |dock, cx| dock.set_open(true, window, cx));
window.focus(&pane.read(cx).focus_handle(cx), cx);
});
workspace.update_in(cx, |workspace, window, cx| {
assert!(workspace.right_dock().read(cx).is_open());
assert!(!panel.read(cx).focus_handle(cx).contains_focused(window, cx));
workspace.toggle_panel_focus::<TestPanel>(window, cx);
});
workspace.update_in(cx, |workspace, window, cx| {
assert!(
workspace.right_dock().read(cx).is_open(),
"Dock should remain open when toggling focuses an open-but-unfocused panel"
);
assert!(
panel.read(cx).focus_handle(cx).contains_focused(window, cx),
"Panel should be focused after toggling an open-but-unfocused panel"
);
});
// Now disable the setting and verify the original behavior: toggling
// from a focused panel moves focus to center but leaves the dock open.
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings(cx, |settings| {
settings.workspace.close_panel_on_toggle = Some(false);
});
});
workspace.update_in(cx, |workspace, window, cx| {
workspace.toggle_panel_focus::<TestPanel>(window, cx);
});
workspace.update_in(cx, |workspace, window, cx| {
assert!(
workspace.right_dock().read(cx).is_open(),
"Dock should remain open when setting is disabled"
);
assert!(
!panel.read(cx).focus_handle(cx).contains_focused(window, cx),
"Panel should not be focused after toggling with setting disabled"
);
});
}
#[gpui::test]
async fn test_pane_zoom_in_out(cx: &mut TestAppContext) {
init_test(cx);

View file

@ -31,6 +31,7 @@ pub struct WorkspaceSettings {
pub text_rendering_mode: settings::TextRenderingMode,
pub resize_all_panels_in_dock: Vec<DockPosition>,
pub close_on_file_delete: bool,
pub close_panel_on_toggle: bool,
pub use_system_window_tabs: bool,
pub zoomed_padding: bool,
pub window_decorations: settings::WindowDecorations,
@ -108,6 +109,7 @@ impl Settings for WorkspaceSettings {
.map(Into::into)
.collect(),
close_on_file_delete: workspace.close_on_file_delete.unwrap(),
close_panel_on_toggle: workspace.close_panel_on_toggle.unwrap(),
use_system_window_tabs: workspace.use_system_window_tabs.unwrap(),
zoomed_padding: workspace.zoomed_padding.unwrap(),
window_decorations: workspace.window_decorations.unwrap(),

View file

@ -740,6 +740,7 @@ async fn initialize_agent_panel(
workspace
.register_action(agent_ui::AgentPanel::toggle_focus)
.register_action(agent_ui::AgentPanel::toggle)
.register_action(agent_ui::InlineAssistant::inline_assist);
}
})?;

View file

@ -302,6 +302,8 @@ pub mod project_panel {
actions!(
project_panel,
[
/// Toggles the project panel.
Toggle,
/// Toggles focus on the project panel.
ToggleFocus
]
@ -465,6 +467,8 @@ pub mod assistant {
actions!(
agent,
[
/// Toggles the agent panel.
Toggle,
#[action(deprecated_aliases = ["assistant::ToggleFocus"])]
ToggleFocus
]
@ -639,6 +643,8 @@ actions!(
actions!(
debug_panel,
[
/// Toggles the debug panel.
Toggle,
/// Toggles focus on the debug panel.
ToggleFocus
]