Add split-pane layout store and navigation shortcuts

This commit is contained in:
Mohamed Boudra
2026-03-18 01:36:54 +07:00
parent 30dd54a318
commit 30a225ce9f
22 changed files with 4710 additions and 375 deletions
+11
View File
@@ -18,6 +18,17 @@ export type KeyboardActionId =
| "workspace.tab.close.current"
| "workspace.tab.navigate.index"
| "workspace.tab.navigate.relative"
| "workspace.pane.split.right"
| "workspace.pane.split.down"
| "workspace.pane.focus.left"
| "workspace.pane.focus.right"
| "workspace.pane.focus.up"
| "workspace.pane.focus.down"
| "workspace.pane.move-tab.left"
| "workspace.pane.move-tab.right"
| "workspace.pane.move-tab.up"
| "workspace.pane.move-tab.down"
| "workspace.pane.close"
| "workspace.navigate.index"
| "workspace.navigate.relative"
| "sidebar.toggle.left"
@@ -13,7 +13,18 @@ export type KeyboardActionId =
| "workspace.tab.new"
| "workspace.tab.close-current"
| "workspace.tab.navigate-index"
| "workspace.tab.navigate-relative";
| "workspace.tab.navigate-relative"
| "workspace.pane.split.right"
| "workspace.pane.split.down"
| "workspace.pane.focus.left"
| "workspace.pane.focus.right"
| "workspace.pane.focus.up"
| "workspace.pane.focus.down"
| "workspace.pane.move-tab.left"
| "workspace.pane.move-tab.right"
| "workspace.pane.move-tab.up"
| "workspace.pane.move-tab.down"
| "workspace.pane.close";
export type KeyboardActionDefinition =
| { id: "message-input.focus"; scope: KeyboardActionScope }
@@ -24,7 +35,18 @@ export type KeyboardActionDefinition =
| { id: "workspace.tab.new"; scope: KeyboardActionScope }
| { id: "workspace.tab.close-current"; scope: KeyboardActionScope }
| { id: "workspace.tab.navigate-index"; scope: KeyboardActionScope; index: number }
| { id: "workspace.tab.navigate-relative"; scope: KeyboardActionScope; delta: 1 | -1 };
| { id: "workspace.tab.navigate-relative"; scope: KeyboardActionScope; delta: 1 | -1 }
| { id: "workspace.pane.split.right"; scope: KeyboardActionScope }
| { id: "workspace.pane.split.down"; scope: KeyboardActionScope }
| { id: "workspace.pane.focus.left"; scope: KeyboardActionScope }
| { id: "workspace.pane.focus.right"; scope: KeyboardActionScope }
| { id: "workspace.pane.focus.up"; scope: KeyboardActionScope }
| { id: "workspace.pane.focus.down"; scope: KeyboardActionScope }
| { id: "workspace.pane.move-tab.left"; scope: KeyboardActionScope }
| { id: "workspace.pane.move-tab.right"; scope: KeyboardActionScope }
| { id: "workspace.pane.move-tab.up"; scope: KeyboardActionScope }
| { id: "workspace.pane.move-tab.down"; scope: KeyboardActionScope }
| { id: "workspace.pane.close"; scope: KeyboardActionScope };
export type KeyboardActionHandler = {
handlerId: string;
@@ -169,6 +169,42 @@ describe("keyboard-shortcuts", () => {
context: { isMac: true, isTauri: true },
action: "workspace.tab.close.current",
},
{
name: "matches Cmd+Backslash to split pane right on macOS",
event: { key: "\\", code: "Backslash", metaKey: true },
context: { isMac: true },
action: "workspace.pane.split.right",
},
{
name: "matches Cmd+Shift+Backslash to split pane down on macOS",
event: { key: "|", code: "Backslash", metaKey: true, shiftKey: true },
context: { isMac: true },
action: "workspace.pane.split.down",
},
{
name: "matches Cmd+Shift+ArrowRight to focus pane right on macOS",
event: { key: "ArrowRight", code: "ArrowRight", metaKey: true, shiftKey: true },
context: { isMac: true },
action: "workspace.pane.focus.right",
},
{
name: "matches Cmd+Shift+Alt+ArrowDown to move tab down on macOS",
event: {
key: "ArrowDown",
code: "ArrowDown",
metaKey: true,
shiftKey: true,
altKey: true,
},
context: { isMac: true },
action: "workspace.pane.move-tab.down",
},
{
name: "matches Cmd+Shift+W to close pane on macOS",
event: { key: "W", code: "KeyW", metaKey: true, shiftKey: true },
context: { isMac: true },
action: "workspace.pane.close",
},
{
name: "matches Cmd+B sidebar toggle on macOS",
event: { key: "b", code: "KeyB", metaKey: true },
@@ -242,6 +278,11 @@ describe("keyboard-shortcuts", () => {
event: { key: "d", code: "KeyD", metaKey: true },
context: { isMac: true, focusScope: "terminal" },
},
{
name: "does not bind pane shortcuts on non-mac platforms",
event: { key: "\\", code: "Backslash", ctrlKey: true },
context: { isMac: false },
},
{
name: "keeps space typing available in message input",
event: { key: " ", code: "Space" },
@@ -278,6 +319,8 @@ describe("keyboard-shortcut help sections", () => {
"workspace-jump-index": ["alt", "1-9"],
"workspace-tab-jump-index": ["alt", "shift", "1-9"],
"workspace-tab-close-current": ["alt", "shift", "W"],
"workspace-pane-split-right": ["mod", "\\"],
"workspace-pane-close": ["mod", "shift", "W"],
},
},
{
@@ -289,6 +332,8 @@ describe("keyboard-shortcut help sections", () => {
"workspace-jump-index": ["mod", "1-9"],
"workspace-tab-jump-index": ["alt", "1-9"],
"workspace-tab-close-current": ["mod", "W"],
"workspace-pane-split-right": ["mod", "\\"],
"workspace-pane-close": ["mod", "shift", "W"],
},
},
{
@@ -71,6 +71,10 @@ function isMod(event: KeyboardEvent): boolean {
return event.metaKey || event.ctrlKey;
}
function isMacCommand(event: KeyboardEvent): boolean {
return event.metaKey && !event.ctrlKey;
}
function parseDigit(event: KeyboardEvent): number | null {
const code = event.code ?? "";
if (code.startsWith("Digit")) {
@@ -373,6 +377,204 @@ const SHORTCUT_BINDINGS: readonly KeyboardShortcutBinding[] = [
keys: ["alt", "shift", "]"],
},
},
{
id: "workspace-pane-split-right-cmd-backslash",
action: "workspace.pane.split.right",
matches: (event) =>
isMacCommand(event) &&
!event.altKey &&
!event.shiftKey &&
event.code === "Backslash",
when: (context) =>
context.isMac && context.focusScope !== "terminal" && !context.commandCenterOpen,
help: {
id: "workspace-pane-split-right",
section: "global",
label: "Split pane right",
keys: ["mod", "\\"],
when: (context) => context.isMac,
},
},
{
id: "workspace-pane-split-down-cmd-shift-backslash",
action: "workspace.pane.split.down",
matches: (event) =>
isMacCommand(event) &&
!event.altKey &&
event.shiftKey &&
event.code === "Backslash",
when: (context) =>
context.isMac && context.focusScope !== "terminal" && !context.commandCenterOpen,
help: {
id: "workspace-pane-split-down",
section: "global",
label: "Split pane down",
keys: ["mod", "shift", "\\"],
when: (context) => context.isMac,
},
},
{
id: "workspace-pane-focus-left-cmd-shift-left",
action: "workspace.pane.focus.left",
matches: (event) =>
isMacCommand(event) &&
!event.altKey &&
event.shiftKey &&
event.code === "ArrowLeft",
when: (context) =>
context.isMac && context.focusScope !== "terminal" && !context.commandCenterOpen,
help: {
id: "workspace-pane-focus-left",
section: "global",
label: "Focus pane left",
keys: ["mod", "shift", "Left"],
when: (context) => context.isMac,
},
},
{
id: "workspace-pane-focus-right-cmd-shift-right",
action: "workspace.pane.focus.right",
matches: (event) =>
isMacCommand(event) &&
!event.altKey &&
event.shiftKey &&
event.code === "ArrowRight",
when: (context) =>
context.isMac && context.focusScope !== "terminal" && !context.commandCenterOpen,
help: {
id: "workspace-pane-focus-right",
section: "global",
label: "Focus pane right",
keys: ["mod", "shift", "Right"],
when: (context) => context.isMac,
},
},
{
id: "workspace-pane-focus-up-cmd-shift-up",
action: "workspace.pane.focus.up",
matches: (event) =>
isMacCommand(event) &&
!event.altKey &&
event.shiftKey &&
event.code === "ArrowUp",
when: (context) =>
context.isMac && context.focusScope !== "terminal" && !context.commandCenterOpen,
help: {
id: "workspace-pane-focus-up",
section: "global",
label: "Focus pane up",
keys: ["mod", "shift", "Up"],
when: (context) => context.isMac,
},
},
{
id: "workspace-pane-focus-down-cmd-shift-down",
action: "workspace.pane.focus.down",
matches: (event) =>
isMacCommand(event) &&
!event.altKey &&
event.shiftKey &&
event.code === "ArrowDown",
when: (context) =>
context.isMac && context.focusScope !== "terminal" && !context.commandCenterOpen,
help: {
id: "workspace-pane-focus-down",
section: "global",
label: "Focus pane down",
keys: ["mod", "shift", "Down"],
when: (context) => context.isMac,
},
},
{
id: "workspace-pane-move-tab-left-cmd-shift-alt-left",
action: "workspace.pane.move-tab.left",
matches: (event) =>
isMacCommand(event) &&
event.altKey &&
event.shiftKey &&
event.code === "ArrowLeft",
when: (context) =>
context.isMac && context.focusScope !== "terminal" && !context.commandCenterOpen,
help: {
id: "workspace-pane-move-tab-left",
section: "global",
label: "Move tab left",
keys: ["mod", "shift", "alt", "Left"],
when: (context) => context.isMac,
},
},
{
id: "workspace-pane-move-tab-right-cmd-shift-alt-right",
action: "workspace.pane.move-tab.right",
matches: (event) =>
isMacCommand(event) &&
event.altKey &&
event.shiftKey &&
event.code === "ArrowRight",
when: (context) =>
context.isMac && context.focusScope !== "terminal" && !context.commandCenterOpen,
help: {
id: "workspace-pane-move-tab-right",
section: "global",
label: "Move tab right",
keys: ["mod", "shift", "alt", "Right"],
when: (context) => context.isMac,
},
},
{
id: "workspace-pane-move-tab-up-cmd-shift-alt-up",
action: "workspace.pane.move-tab.up",
matches: (event) =>
isMacCommand(event) &&
event.altKey &&
event.shiftKey &&
event.code === "ArrowUp",
when: (context) =>
context.isMac && context.focusScope !== "terminal" && !context.commandCenterOpen,
help: {
id: "workspace-pane-move-tab-up",
section: "global",
label: "Move tab up",
keys: ["mod", "shift", "alt", "Up"],
when: (context) => context.isMac,
},
},
{
id: "workspace-pane-move-tab-down-cmd-shift-alt-down",
action: "workspace.pane.move-tab.down",
matches: (event) =>
isMacCommand(event) &&
event.altKey &&
event.shiftKey &&
event.code === "ArrowDown",
when: (context) =>
context.isMac && context.focusScope !== "terminal" && !context.commandCenterOpen,
help: {
id: "workspace-pane-move-tab-down",
section: "global",
label: "Move tab down",
keys: ["mod", "shift", "alt", "Down"],
when: (context) => context.isMac,
},
},
{
id: "workspace-pane-close-cmd-shift-w",
action: "workspace.pane.close",
matches: (event) =>
isMacCommand(event) &&
!event.altKey &&
event.shiftKey &&
(event.code === "KeyW" || event.key.toLowerCase() === "w"),
when: (context) =>
context.isMac && context.focusScope !== "terminal" && !context.commandCenterOpen,
help: {
id: "workspace-pane-close",
section: "global",
label: "Close pane",
keys: ["mod", "shift", "W"],
when: (context) => context.isMac,
},
},
{
id: "command-center-toggle",
action: "command-center.toggle",