Skip to content

Commit cc76c99

Browse files
feat: Integrate global keymap provider and enhance view cycling with command registration and key bindings
1 parent d712931 commit cc76c99

File tree

3 files changed

+47
-20
lines changed

3 files changed

+47
-20
lines changed

src/components/WorkspaceHeader.tsx

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect, useCallback } from "react";
1+
import React, { useState, useCallback, useEffect } from "react";
22
import { Link } from "@tanstack/react-router";
33
import { SettingsIcon, BotIcon, CodeIcon, Sparkles } from "lucide-react";
44
import { SettingsModal } from "@/components/SettingsModal";
@@ -7,33 +7,53 @@ import { Button } from "@/components/ui/button";
77
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
88
import { useEditorContentStore } from "@/stores/editor-content";
99

10+
import { useCommandManager, useKeyBindingManager } from "@/services/keymaps/main";
11+
1012
export default function WorkspaceHeader() {
1113
const [settingsOpen, setSettingsOpen] = useState(false);
1214
const { view, setView } = useEditorContentStore();
1315

14-
// Cycle views: code -> agents -> auto -> code ...
16+
// Use keymap system for cycling views
1517
const views = ["code", "agents", "auto"];
16-
const handleCycleView = useCallback(() => {
17-
const idx = views.indexOf(view);
18-
const nextView = views[(idx + 1) % views.length];
19-
setView(nextView as typeof view);
20-
}, [view, setView]);
18+
const { registerCommand, unregisterCommand } = useCommandManager();
19+
const { addKeyBinding, removeKeyBinding } = useKeyBindingManager();
2120

21+
// Register the cycle view command and key binding
2222
useEffect(() => {
23-
function handleKeyDown(e) {
24-
const isMac = navigator.platform.toLowerCase().includes("mac");
25-
const cmdOrCtrl = isMac ? e.metaKey : e.ctrlKey;
26-
if (cmdOrCtrl && e.key === "5") {
27-
e.preventDefault();
28-
handleCycleView();
29-
}
30-
}
31-
window.addEventListener("keydown", handleKeyDown);
32-
return () => window.removeEventListener("keydown", handleKeyDown);
33-
}, [handleCycleView]);
23+
// Register command
24+
registerCommand("view.cycleView", {
25+
execute: () => {
26+
console.log("registered keymap, view.cycleView")
27+
const idx = views.indexOf(view);
28+
const nextView = views[(idx + 1) % views.length];
29+
setView(nextView as typeof view);
30+
},
31+
canExecute: () => true,
32+
});
33+
34+
// Register key binding for Cmd/Ctrl+5 (global context)
35+
addKeyBinding({
36+
id: "view.cycleView.binding",
37+
description: "Cycle editor views",
38+
key: "cmd+5",
39+
altKeys: ["ctrl+5"],
40+
command: "view.cycleView",
41+
enabled: true,
42+
category: "view",
43+
context: "global",
44+
});
45+
46+
// Cleanup on unmount
47+
return () => {
48+
unregisterCommand("view.cycleView");
49+
removeKeyBinding("view.cycleView.binding");
50+
};
51+
// eslint-disable-next-line react-hooks/exhaustive-deps
52+
}, [view, setView]);
3453

3554
return (
3655
<>
56+
{/* Keymap handles Cmd/Ctrl+5 for cycling views */}
3757
<div className="draglayer relative z-950 flex w-screen items-stretch border-b py-1">
3858
<div className="flex flex-1 items-center px-4">
3959
<div className="no-drag">

src/pages/workspace/index.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { AgentsView } from './components/agents-view';
99
import { useTerminalStore } from '@/stores/terminal';
1010
import WorkspaceHeader from '@/components/WorkspaceHeader';
1111
import { Toaster } from "@/components/ui/sonner";
12+
import { GlobalKeymapProvider } from '@/services/keymaps/main';
1213

1314
export default function WorkspacePage() {
1415
const { currentProject, fileTree } = useProjectStore();
@@ -34,8 +35,9 @@ export default function WorkspacePage() {
3435
}, [currentProject]);
3536

3637
return (
37-
<div className="flex h-screen flex-col">
38-
<WorkspaceHeader />
38+
<GlobalKeymapProvider>
39+
<div className="flex h-screen flex-col">
40+
<WorkspaceHeader />
3941
<main className="h-full grow flex flex-col overflow-hidden">
4042
<div className="flex-1 overflow-hidden">
4143
<div className="w-full bg-background h-full max-h-full relative flex flex-col workspace-layout">
@@ -102,5 +104,6 @@ export default function WorkspacePage() {
102104
</main>
103105
<Toaster />
104106
</div>
107+
</GlobalKeymapProvider>
105108
);
106109
}

src/services/keymaps/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import { create } from 'zustand';
22
import { immer } from 'zustand/middleware/immer';
3+
import { enableMapSet } from 'immer';
34
import { KeyBinding, KeymapProfile, KeymapState, KeyCommand, KeyEventInfo } from './types';
45
import { getDefaultProfiles } from './profiles';
56
import { registerDefaultCommands } from './commands';
67
import { keyEventToString, matchesKeyCombination, isValidKeyCombination } from './utils';
78
import { useBufferStore } from '@/stores/buffers';
89

10+
// Enable Map support in Immer for the commands Map
11+
enableMapSet();
12+
913
export const useKeymapStore = create<KeymapState>()(
1014
immer((set, get) => ({
1115
profiles: getDefaultProfiles(),

0 commit comments

Comments
 (0)