feat: add Cmd-B sidebar toggle shortcut (#1775)

Co-authored-by: Dr. Lukas Metzger <lukas@mba.lan>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-11-06 20:48:20 -06:00
1 parent 9778b6e56a
commit b912a31e00
5 files changed
+61 -7

No files matched your search

+1
View File
@@ -631,6 +631,7 @@ export const CORE_KEYBINDING_ACTIONS: readonly string[] = [
"previousTab", "previousTab",
"openCommandPalette", "openCommandPalette",
"reconnectSession", "reconnectSession",
"toggleSidebar",
]; ];
/** /**
+2 -1
View File
@@ -1054,7 +1054,8 @@
"actionNextTab": "Switch to next tab", "actionNextTab": "Switch to next tab",
"actionPreviousTab": "Switch to previous tab", "actionPreviousTab": "Switch to previous tab",
"actionOpenCommandPalette": "Open quick search", "actionOpenCommandPalette": "Open quick search",
"actionReconnectSession": "Reconnect current session" "actionReconnectSession": "Reconnect current session",
"actionToggleSidebar": "Toggle sidebar"
}, },
"userProfile": { "userProfile": {
"preset_simple": "Simple", "preset_simple": "Simple",
@@ -8,7 +8,10 @@ import {
} from "@/lib/app-keyboard-shortcuts"; } from "@/lib/app-keyboard-shortcuts";
import { getUserPreferences } from "@/main-axios"; import { getUserPreferences } from "@/main-axios";
import { parseCustomKeybindings } from "@/api/open-tabs-api"; import { parseCustomKeybindings } from "@/api/open-tabs-api";
import { findMatchingKeybinding } from "@/lib/keybinding-match"; import {
eventMatchesCombo,
findMatchingKeybinding,
} from "@/lib/keybinding-match";
import type { import type {
CustomKeybinding, CustomKeybinding,
KeybindingActionType, KeybindingActionType,
@@ -16,6 +19,7 @@ import type {
import { import {
GLOBAL_KEYBINDING_EVENT, GLOBAL_KEYBINDING_EVENT,
getKeybindingAction, getKeybindingAction,
listKeybindingDefaults,
runKeybindingAction, runKeybindingAction,
} from "@/shell/keybinding-registry"; } from "@/shell/keybinding-registry";
import { globalShortcutHandler } from "@/lib/global-shortcut-handler"; import { globalShortcutHandler } from "@/lib/global-shortcut-handler";
@@ -53,7 +57,7 @@ export function useShellKeybindings({
if (cancelled) return; if (cancelled) return;
globalKeybindingsRef.current = parseCustomKeybindings( globalKeybindingsRef.current = parseCustomKeybindings(
prefs.customKeybindings, prefs.customKeybindings,
).filter((binding) => binding.enabled); );
}) })
.catch(() => {}); .catch(() => {});
}; };
@@ -78,6 +82,10 @@ export function useShellKeybindings({
(termRef?.current as TabHandle | null)?.reconnect?.(); (termRef?.current as TabHandle | null)?.reconnect?.();
return; return;
} }
if (type === "toggleSidebar") {
regions.left.setOpen((open) => !open);
return;
}
const currentTabs = tabsRef.current.filter( const currentTabs = tabsRef.current.filter(
(tab) => !tab.parentSplitTabId, (tab) => !tab.parentSplitTabId,
); );
@@ -97,16 +105,32 @@ export function useShellKeybindings({
) )
return; return;
// Only actions that run anywhere; a terminal's own are its to handle. // Only actions that run anywhere; a terminal's own are its to handle.
const customBindings = globalKeybindingsRef.current;
const binding = findMatchingKeybinding( const binding = findMatchingKeybinding(
event, event,
globalKeybindingsRef.current.filter( customBindings.filter(
(entry) => getKeybindingAction(entry.action.type)?.scope === "global", (entry) =>
entry.enabled &&
getKeybindingAction(entry.action.type)?.scope === "global",
), ),
); );
if (!binding) return; if (binding) {
event.preventDefault();
event.stopPropagation();
runKeybindingAction(binding.action);
return;
}
const defaultBinding = listKeybindingDefaults().find(
(entry) =>
!customBindings.some(
(custom) => custom.overridesDefaultId === entry.id,
) && eventMatchesCombo(event, entry.combo),
);
if (!defaultBinding || !getKeybindingAction(defaultBinding.id)) return;
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
runKeybindingAction(binding.action); runKeybindingAction({ type: defaultBinding.id });
}; };
const handleAction = (event: Event) => const handleAction = (event: Event) =>
runAction( runAction(
+20
View File
@@ -84,6 +84,11 @@ const SHELL_ACTIONS: KeybindingActionDef[] = [
"newUi.sidebar.keybindings.actionReconnectSession", "newUi.sidebar.keybindings.actionReconnectSession",
1003, 1003,
), ),
shellAction(
"toggleSidebar",
"newUi.sidebar.keybindings.actionToggleSidebar",
1004,
),
]; ];
export const SHELL_KEYBINDING_ACTION_IDS = SHELL_ACTIONS.map( export const SHELL_KEYBINDING_ACTION_IDS = SHELL_ACTIONS.map(
@@ -97,6 +102,21 @@ function install(): void {
for (const action of SHELL_ACTIONS) { for (const action of SHELL_ACTIONS) {
if (!actions.get(action.id)) actions.register(action); if (!actions.get(action.id)) actions.register(action);
} }
if (!defaults.get("toggleSidebar")) {
defaults.register({
id: "toggleSidebar",
combo: {
key: "KeyB",
isCode: true,
ctrl: false,
alt: false,
shift: false,
meta: true,
},
descriptionKey: "newUi.sidebar.keybindings.actionToggleSidebar",
order: 1004,
});
}
} }
install(); install();
@@ -4,6 +4,7 @@ import {
SHELL_KEYBINDING_ACTION_IDS, SHELL_KEYBINDING_ACTION_IDS,
getKeybindingAction, getKeybindingAction,
listKeybindingActions, listKeybindingActions,
listKeybindingDefaults,
registerKeybindingAction, registerKeybindingAction,
resetKeybindingRegistry, resetKeybindingRegistry,
runKeybindingAction, runKeybindingAction,
@@ -17,6 +18,13 @@ describe("keybinding registry", () => {
SHELL_KEYBINDING_ACTION_IDS, SHELL_KEYBINDING_ACTION_IDS,
); );
expect(getKeybindingAction("nextTab")?.scope).toBe("global"); expect(getKeybindingAction("nextTab")?.scope).toBe("global");
expect(getKeybindingAction("toggleSidebar")?.scope).toBe("global");
expect(listKeybindingDefaults()).toEqual([
expect.objectContaining({
id: "toggleSidebar",
combo: expect.objectContaining({ key: "KeyB", meta: true }),
}),
]);
}); });
it("runs a shell action by telling the shell", () => { it("runs a shell action by telling the shell", () => {