Skip to content

hotkey pane#108

Merged
Kitenite merged 7 commits into
mainfrom
hotkey-pane
Nov 20, 2025
Merged

hotkey pane#108
Kitenite merged 7 commits into
mainfrom
hotkey-pane

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Nov 20, 2025

Summary by CodeRabbit

  • New Features

    • Global keyboard shortcuts for workspace navigation, tab management, pane splitting, and pane focus.
    • New horizontal and vertical tab-splitting with pane-level focus/navigation.
  • Improvements

    • Centralized, consistent shortcut handling and stricter handler return behavior for reliability.
    • UI components wired to split/close pane actions (replace prior placeholders).
  • Tests

    • Comprehensive tests for vertical and horizontal tab-splitting scenarios.
  • Documentation

    • Minor formatting cleanup.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 20, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a centralized global keyboard-shortcut hook and wires it into MainScreen; enforces boolean-return handlers in shortcut infra; replaces legacy split shortcuts with splitHorizontal/splitVertical and adds pane-focus handlers; implements tab-splitting actions in TabsState, updates UI components and tests to exercise splitting.

Changes

Cohort / File(s) Summary
Shortcut infra & API
apps/desktop/src/renderer/lib/keyboard-shortcuts.ts, apps/desktop/src/renderer/lib/shortcuts.ts
KeyboardShortcut.handler now returns boolean. Replaced createSplitView/createVerticalSplit with splitHorizontal/splitVertical; added focusPaneLeft/Right/Up/Down. Added createSplitPaneShortcuts.
Global shortcuts hook
apps/desktop/src/renderer/hooks/useGlobalShortcuts.ts
New useGlobalShortcuts() hook that reads workspace/tab/UI state, composes workspace/tab/pane shortcut groups, registers a keydown listener via createShortcutHandler, and cleans up on unmount.
Integration (UI)
apps/desktop/src/renderer/screens/main/index.tsx
Imports and invokes useGlobalShortcuts in MainScreen to enable global shortcut handling.
Tabs store & hooks
apps/desktop/src/renderer/stores/tabs/store.ts
Added splitTabVertical and splitTabHorizontal actions, internal helpers to split/convert tabs/groups, use of MosaicBranch and updateTree, and exported hooks useSplitTabVertical/useSplitTabHorizontal.
Tab view components
apps/desktop/src/renderer/screens/main/components/.../GroupTabView/index.tsx, .../SingleTabView.tsx
Wired new split hooks into GroupTabView and SingleTabView, replaced placeholder stubs with real split/close handlers and context-menu integrations; render and handler memoization updated.
Tests
apps/desktop/src/renderer/stores/tabs/store.test.ts
Added tests covering vertical/horizontal split behavior for single and group tabs and per-id split scenarios.
Config / Docs
apps/desktop/tsconfig.json, apps/desktop/CLAUDE.md
Added bun-types to tsconfig types; minor formatting change in CLAUDE.md.

Sequence Diagram(s)

sequenceDiagram
    participant Main as MainScreen
    participant Hook as useGlobalShortcuts
    participant Stores as State Stores
    participant Factories as Shortcut Factories
    participant Builder as createShortcutHandler
    participant DOM as Window (keydown)

    Main->>Hook: mount / invoke hook
    Hook->>Stores: read workspace, tabs, UI state
    Note over Hook,Factories: Build workspace/tab/pane shortcut groups
    Hook->>Factories: createWorkspaceShortcuts/createTabShortcuts/createSplitPaneShortcuts
    Factories-->>Hook: KeyboardShortcutGroups
    Hook->>Builder: merge groups -> handler fn
    Builder-->>Hook: listener function
    Hook->>DOM: register keydown listener
    DOM->>Builder: keydown event
    Builder->>Builder: match shortcut -> call handler
    alt handler returns false
        Builder-->>DOM: preventDefault & stopPropagation
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas to inspect closely:
    • Correctness of the KeyboardShortcut.handler boolean contract across factories and usages.
    • Edge cases in splitTabVertical / splitTabHorizontal (group vs single tab, path handling) and interactions with react-mosaic-component types (MosaicBranch, updateTree).
    • Lifecycle and dependency array in useGlobalShortcuts to ensure listeners re-register only when necessary.
    • UI wiring in GroupTabView/SingleTabView for context-menu actions and pane rendering.
    • New tests for coverage and expected semantics.

Possibly related PRs

  • hotkey pane #108 — Overlaps on useGlobalShortcuts, keyboard-shortcuts, shortcuts, and split handler changes; likely touching the same code paths.
  • tabs mangement interaction #105 — Related changes to the tabs store API and splitting behavior; strong code-level connection.
  • refactor 1 #69 — Touches MainScreen integration and layout wiring where useGlobalShortcuts was added.

Poem

🐇 I hopped across keys, a tiny chore,

Split panes like carrots, one then more.
Shortcuts I stitched, a nimble art,
Tabs now part and joined apart.
Click, split, focus — the desktop sings; hooray!

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is largely incomplete and does not follow the provided template. It consists only of a bullet-point list of commit messages rather than structured sections like Description, Related Issues, Type of Change, Testing, and Screenshots. Replace the commit message list with a proper PR description following the template. Include clear description of changes, related issue links, type of change selection, testing details, and any additional notes.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'hotkey pane' is vague and does not clearly convey what the pull request accomplishes. It lacks specificity about whether it adds, fixes, or refactors hotkey or pane functionality. Use a more descriptive title that clarifies the main objective, such as 'Add global keyboard shortcuts for pane navigation' or 'Implement hotkey system for workspace and pane management'.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e4181bd and ac1f52e.

📒 Files selected for processing (1)
  • apps/desktop/src/renderer/stores/tabs/store.ts (6 hunks)

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/desktop/src/renderer/hooks/useGlobalShortcuts.ts (1)

54-61: TODO: Connect split handlers to store actions.

The split handlers are currently placeholders. Once the splitTabVertical and splitTabHorizontal store methods are implemented, wire them here.

Here's how to connect them after the store methods are implemented:

 		splitVertical: () => {
-			// TODO: Implement split vertical
-			console.log("Split vertical");
+			if (!activeWorkspaceId) return;
+			const activeTabId = activeTabIds[activeWorkspaceId];
+			useTabsStore.getState().splitTabVertical(activeWorkspaceId, activeTabId || undefined);
 		},
 		splitHorizontal: () => {
-			// TODO: Implement split horizontal
-			console.log("Split horizontal");
+			if (!activeWorkspaceId) return;
+			const activeTabId = activeTabIds[activeWorkspaceId];
+			useTabsStore.getState().splitTabHorizontal(activeWorkspaceId, activeTabId || undefined);
 		},

Note: You'll need to import useTabsStore directly to call getState().

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d0ca08a and c5fdefe.

📒 Files selected for processing (5)
  • apps/desktop/src/renderer/hooks/useGlobalShortcuts.ts (1 hunks)
  • apps/desktop/src/renderer/lib/keyboard-shortcuts.ts (1 hunks)
  • apps/desktop/src/renderer/lib/shortcuts.ts (5 hunks)
  • apps/desktop/src/renderer/screens/main/index.tsx (1 hunks)
  • apps/desktop/src/renderer/stores/tabs/store.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
apps/desktop/src/renderer/hooks/useGlobalShortcuts.ts (5)
apps/desktop/src/renderer/stores/workspaces.ts (1)
  • useWorkspacesStore (27-90)
apps/desktop/src/renderer/stores/sidebar-state.ts (1)
  • useSidebarStore (17-37)
apps/desktop/src/renderer/stores/tabs/store.ts (5)
  • useTabs (616-616)
  • useActiveTabIds (617-618)
  • useSetActiveTab (623-624)
  • useAddTab (620-620)
  • useRemoveTab (621-621)
apps/desktop/src/renderer/lib/shortcuts.ts (3)
  • createWorkspaceShortcuts (37-102)
  • createTabShortcuts (104-186)
  • createSplitPaneShortcuts (188-239)
apps/desktop/src/renderer/lib/keyboard-shortcuts.ts (1)
  • createShortcutHandler (50-65)
apps/desktop/src/renderer/screens/main/index.tsx (2)
apps/old-desktop/src/renderer/screens/main/MainScreen.tsx (1)
  • MainScreen (23-225)
apps/desktop/src/renderer/hooks/useGlobalShortcuts.ts (1)
  • useGlobalShortcuts (22-163)
apps/desktop/src/renderer/lib/shortcuts.ts (1)
apps/desktop/src/renderer/lib/keyboard-shortcuts.ts (1)
  • KeyboardShortcutGroup (15-18)
🔇 Additional comments (7)
apps/desktop/src/renderer/lib/shortcuts.ts (2)

10-35: LGTM! Interface updates are clear and well-documented.

The split and pane navigation handlers are well-organized with helpful iTerm2-style comments.


37-101: LGTM! Workspace shortcuts updated correctly.

The split shortcuts follow iTerm2 conventions (Cmd+D for vertical, Cmd+Shift+D for horizontal) and integrate cleanly with the new handler interface.

apps/desktop/src/renderer/screens/main/index.tsx (1)

2-2: LGTM! Clean integration of global shortcuts.

The hook is correctly invoked at the component's top level, enabling global keyboard shortcuts for the main screen.

Also applies to: 10-10

apps/desktop/src/renderer/lib/keyboard-shortcuts.ts (1)

12-12: LGTM! Handler return type now enforces boolean.

The change from boolean | void to boolean improves type safety. All handlers in the codebase already return boolean, so this formalization is appropriate.

apps/desktop/src/renderer/hooks/useGlobalShortcuts.ts (3)

73-111: LGTM! Tab handlers are correctly implemented.

The tab navigation, creation, and jumping logic is sound with appropriate bounds checking and workspace guards. The reopenClosedTab placeholder is acceptable for initial implementation.


114-131: TODO implementations noted, but affected by shortcut conflicts.

These pane focus handlers are placeholders, which is acceptable. However, due to the shortcut key conflicts identified in apps/desktop/src/renderer/lib/shortcuts.ts (lines 188-239), these handlers won't be reachable until the conflicts are resolved.


32-162: LGTM! useEffect dependencies are correct.

The dependency array includes all external values used in the effect. The derived values (workspaceTabs, activeTabId) are correctly computed inside the effect from the tracked dependencies.

Comment on lines +188 to +239
export function createSplitPaneShortcuts(
handlers: Pick<
ShortcutHandlers,
"focusPaneLeft" | "focusPaneRight" | "focusPaneUp" | "focusPaneDown"
>,
): KeyboardShortcutGroup {
return {
name: "Split Pane Navigation",
shortcuts: [
{
key: "ArrowLeft",
modifiers: ["meta", "alt"],
description: "Focus left pane",
handler: (event) => {
event.preventDefault();
handlers.focusPaneLeft();
return false;
},
},
{
key: "ArrowRight",
modifiers: ["meta", "alt"],
description: "Focus right pane",
handler: (event) => {
event.preventDefault();
handlers.focusPaneRight();
return false;
},
},
{
key: "ArrowUp",
modifiers: ["meta", "alt"],
description: "Focus upper pane",
handler: (event) => {
event.preventDefault();
handlers.focusPaneUp();
return false;
},
},
{
key: "ArrowDown",
modifiers: ["meta", "alt"],
description: "Focus lower pane",
handler: (event) => {
event.preventDefault();
handlers.focusPaneDown();
return false;
},
},
],
};
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Shortcut key conflicts with workspace and tab navigation.

The pane navigation shortcuts conflict with existing shortcuts:

  1. Meta+Alt+ArrowLeft/Right: Used by both workspace switching (lines 51, 61) and pane focus (lines 198, 208)
  2. Meta+Alt+ArrowUp/Down: Used by both tab switching (lines 117, 127) and pane focus (lines 218, 228)

When all shortcuts are registered together in useGlobalShortcuts, only the first matching shortcut will fire, making either workspace/tab navigation or pane navigation inaccessible.

Consider using different modifiers for pane navigation, such as:

  • Option 1: Use Cmd+Opt+Ctrl+Arrows for pane focus (keeping workspace/tab nav as-is)
  • Option 2: Use Cmd+[ / Cmd+] style shortcuts (similar to tmux/vim)
  • Option 3: Make shortcuts contextual - pane navigation only when a split view is active

Apply this diff for Option 1:

 export function createSplitPaneShortcuts(
 	handlers: Pick<
 		ShortcutHandlers,
 		"focusPaneLeft" | "focusPaneRight" | "focusPaneUp" | "focusPaneDown"
 	>,
 ): KeyboardShortcutGroup {
 	return {
 		name: "Split Pane Navigation",
 		shortcuts: [
 			{
 				key: "ArrowLeft",
-				modifiers: ["meta", "alt"],
+				modifiers: ["meta", "alt", "ctrl"],
 				description: "Focus left pane",
 				handler: (event) => {
 					event.preventDefault();
 					handlers.focusPaneLeft();
 					return false;
 				},
 			},
 			{
 				key: "ArrowRight",
-				modifiers: ["meta", "alt"],
+				modifiers: ["meta", "alt", "ctrl"],
 				description: "Focus right pane",
 				handler: (event) => {
 					event.preventDefault();
 					handlers.focusPaneRight();
 					return false;
 				},
 			},
 			{
 				key: "ArrowUp",
-				modifiers: ["meta", "alt"],
+				modifiers: ["meta", "alt", "ctrl"],
 				description: "Focus upper pane",
 				handler: (event) => {
 					event.preventDefault();
 					handlers.focusPaneUp();
 					return false;
 				},
 			},
 			{
 				key: "ArrowDown",
-				modifiers: ["meta", "alt"],
+				modifiers: ["meta", "alt", "ctrl"],
 				description: "Focus lower pane",
 				handler: (event) => {
 					event.preventDefault();
 					handlers.focusPaneDown();
 					return false;
 				},
 			},
 		],
 	};
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function createSplitPaneShortcuts(
handlers: Pick<
ShortcutHandlers,
"focusPaneLeft" | "focusPaneRight" | "focusPaneUp" | "focusPaneDown"
>,
): KeyboardShortcutGroup {
return {
name: "Split Pane Navigation",
shortcuts: [
{
key: "ArrowLeft",
modifiers: ["meta", "alt"],
description: "Focus left pane",
handler: (event) => {
event.preventDefault();
handlers.focusPaneLeft();
return false;
},
},
{
key: "ArrowRight",
modifiers: ["meta", "alt"],
description: "Focus right pane",
handler: (event) => {
event.preventDefault();
handlers.focusPaneRight();
return false;
},
},
{
key: "ArrowUp",
modifiers: ["meta", "alt"],
description: "Focus upper pane",
handler: (event) => {
event.preventDefault();
handlers.focusPaneUp();
return false;
},
},
{
key: "ArrowDown",
modifiers: ["meta", "alt"],
description: "Focus lower pane",
handler: (event) => {
event.preventDefault();
handlers.focusPaneDown();
return false;
},
},
],
};
}
export function createSplitPaneShortcuts(
handlers: Pick<
ShortcutHandlers,
"focusPaneLeft" | "focusPaneRight" | "focusPaneUp" | "focusPaneDown"
>,
): KeyboardShortcutGroup {
return {
name: "Split Pane Navigation",
shortcuts: [
{
key: "ArrowLeft",
modifiers: ["meta", "alt", "ctrl"],
description: "Focus left pane",
handler: (event) => {
event.preventDefault();
handlers.focusPaneLeft();
return false;
},
},
{
key: "ArrowRight",
modifiers: ["meta", "alt", "ctrl"],
description: "Focus right pane",
handler: (event) => {
event.preventDefault();
handlers.focusPaneRight();
return false;
},
},
{
key: "ArrowUp",
modifiers: ["meta", "alt", "ctrl"],
description: "Focus upper pane",
handler: (event) => {
event.preventDefault();
handlers.focusPaneUp();
return false;
},
},
{
key: "ArrowDown",
modifiers: ["meta", "alt", "ctrl"],
description: "Focus lower pane",
handler: (event) => {
event.preventDefault();
handlers.focusPaneDown();
return false;
},
},
],
};
}
🤖 Prompt for AI Agents
In apps/desktop/src/renderer/lib/shortcuts.ts around lines 188 to 239, pane
navigation uses the same Meta+Alt+Arrow combinations as workspace/tab navigation
causing conflicts; update each pane-focus shortcut's modifiers array to include
"ctrl" so they become ["meta","alt","ctrl"] (Cmd+Opt+Ctrl+Arrow) for ArrowLeft,
ArrowRight, ArrowUp, and ArrowDown, leaving keys and handlers unchanged so pane
navigation no longer blocks workspace/tab shortcuts.

Comment thread apps/desktop/src/renderer/stores/tabs/store.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
apps/desktop/src/renderer/lib/shortcuts.ts (1)

187-238: Pane-focus shortcuts still conflict with workspace/tab navigation

createSplitPaneShortcuts uses Meta+Alt+ArrowLeft/Right/Up/Down, which are already taken by workspace and tab navigation, so only one of these behaviors will fire for each combo when all groups are registered globally. This reintroduces the same conflict noted in the earlier review.

To keep all shortcuts usable, consider updating pane-focus modifiers, for example:

 export function createSplitPaneShortcuts(
@@
 		name: "Split Pane Navigation",
 		shortcuts: [
 			{
 				key: "ArrowLeft",
-				modifiers: ["meta", "alt"],
+				modifiers: ["meta", "alt", "ctrl"],
@@
 			{
 				key: "ArrowRight",
-				modifiers: ["meta", "alt"],
+				modifiers: ["meta", "alt", "ctrl"],
@@
 			{
 				key: "ArrowUp",
-				modifiers: ["meta", "alt"],
+				modifiers: ["meta", "alt", "ctrl"],
@@
 			{
 				key: "ArrowDown",
-				modifiers: ["meta", "alt"],
+				modifiers: ["meta", "alt", "ctrl"],

This preserves existing workspace/tab navigation while giving pane focus its own distinct chord.

🧹 Nitpick comments (3)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/SingleTabView.tsx (1)

1-29: SingleTabView correctly delegates to tab store split/remove actions

Hooking useSplitTabHorizontal/useSplitTabVertical and useRemoveTab into the three handlers aligns the single-tab view with the new split/close semantics and keeps the logic centralized in the store.

You can later drop or wire up the unused isDropZone prop if it’s no longer needed.

apps/desktop/src/renderer/stores/tabs/store.test.ts (1)

180-265: Splitting tests are thorough; consider adding in-group split coverage later

The new splitTabVertical/splitTabHorizontal tests nicely validate group creation, layout orientation, child parentIds, and active tab updates, as well as the “don’t split groups” and “split specific id” cases. This should catch most regressions in the split actions.

In a follow-up, it may be worth adding a test that exercises splitting an existing group pane via the path argument, mirroring how GroupTabView calls the store.

Also applies to: 267-364

apps/desktop/src/renderer/stores/tabs/store.ts (1)

364-369: Guarding against direct group-tab closure is good; consider surfacing via UI instead of console

Blocking removeTab for group tabs avoids bypassing the group/ungroup logic, which is the right call. Depending on how this is surfaced, you may eventually want to route this through your UI/notification layer instead of console.error, but that’s a polish item, not a blocker.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c5fdefe and e4181bd.

📒 Files selected for processing (8)
  • apps/desktop/CLAUDE.md (0 hunks)
  • apps/desktop/src/renderer/hooks/useGlobalShortcuts.ts (1 hunks)
  • apps/desktop/src/renderer/lib/shortcuts.ts (5 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupTabView/index.tsx (3 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/SingleTabView.tsx (2 hunks)
  • apps/desktop/src/renderer/stores/tabs/store.test.ts (1 hunks)
  • apps/desktop/src/renderer/stores/tabs/store.ts (6 hunks)
  • apps/desktop/tsconfig.json (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/desktop/CLAUDE.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop/src/renderer/hooks/useGlobalShortcuts.ts
🧰 Additional context used
🧬 Code graph analysis (5)
apps/desktop/src/renderer/lib/shortcuts.ts (1)
apps/desktop/src/renderer/lib/keyboard-shortcuts.ts (1)
  • KeyboardShortcutGroup (15-18)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupTabView/index.tsx (2)
apps/desktop/src/renderer/stores/tabs/store.ts (2)
  • useSplitTabHorizontal (842-843)
  • useSplitTabVertical (840-841)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabContentContextMenu.tsx (1)
  • TabContentContextMenu (17-40)
apps/desktop/src/renderer/stores/tabs/store.test.ts (2)
apps/desktop/src/renderer/stores/tabs/store.ts (1)
  • useTabsStore (326-822)
apps/desktop/src/shared/types.ts (1)
  • TabType (23-30)
apps/desktop/src/renderer/stores/tabs/store.ts (3)
apps/desktop/src/renderer/stores/tabs/types.ts (1)
  • Tab (25-25)
apps/desktop/src/shared/types.ts (2)
  • TabType (23-30)
  • MosaicNode (35-35)
apps/desktop/src/renderer/stores/tabs/utils.ts (1)
  • createNewTab (10-36)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/SingleTabView.tsx (1)
apps/desktop/src/renderer/stores/tabs/store.ts (3)
  • useSplitTabHorizontal (842-843)
  • useSplitTabVertical (840-841)
  • useRemoveTab (829-829)
🔇 Additional comments (7)
apps/desktop/tsconfig.json (1)

17-17: Confirm Bun typings scope for the whole desktop app

Setting "types": ["bun-types"] means only Bun’s global type package is pulled in from @types. If any of the desktop code (Electron main, Node APIs, etc.) still relies on other global type packages (e.g. node, electron), you’ll need to add them here or split out a test-only tsconfig; otherwise those globals may lose their typings.

apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupTabView/index.tsx (1)

57-104: Split/close wiring in GroupTabView looks consistent with the store API

The new split handlers correctly delegate to splitTabHorizontal/splitTabVertical with workspaceId, tabId, and path, and handleClosePane cleanly routes pane removal through removeChildTabFromGroup. renderPane’s use of MosaicWindow plus TabContentContextMenu is memoized with the right dependencies and has a safe “Tab not found” fallback.

Also applies to: 106-142

apps/desktop/src/renderer/lib/shortcuts.ts (1)

10-35: Workspace split shortcuts are wired cleanly to the new handlers

Extending ShortcutHandlers with splitVertical/splitHorizontal and routing the "⌘D" / "⇧⌘D" entries through those handlers keeps the workspace split behavior centralized and consistent with the new tab store actions.

Also applies to: 37-45, 80-99

apps/desktop/src/renderer/stores/tabs/store.ts (4)

1-2: New imports for pane splitting look appropriate

Importing MosaicBranch/MosaicNode types and updateTree locally scopes the layout-specific concerns to this store without impacting existing behavior; no issues here.


38-47: TabsState API extensions for split actions are clear

The splitTabVertical / splitTabHorizontal signatures (workspace-scoped, optional source tab, optional path) are well-shaped for both “active tab” and targeted pane splitting use cases and align with the rest of the store API.


131-183: splitPaneInGroup maintains group invariants

The helper correctly:

  • Locates the owning group via parentId,
  • Creates a new child with the same workspaceId and parentId,
  • Uses updateTree to replace the leaf at path with a split node,
  • Returns a partial state update that only mutates tabs.

This keeps the group’s layout and children in sync; I don’t see correctness issues here.


840-843: Hook exports for split actions are consistent with existing store hooks

useSplitTabVertical and useSplitTabHorizontal mirror the other selector hooks and keep the public surface tidy; no concerns here.

Comment thread apps/desktop/src/renderer/stores/tabs/store.ts
@Kitenite Kitenite merged commit 5f7ae31 into main Nov 20, 2025
0 of 5 checks passed
@Kitenite Kitenite deleted the hotkey-pane branch November 20, 2025 20:31
This was referenced Nov 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant