import type { KeybindingCommand, ScopedThreadRef } from "@t3tools/contracts";import { useCallback, useMemo } from "react"; import { useCommandPaletteStore } from "../commandPaletteStore";import { useFocusedWorkspaceSurface, useWorkspaceDocument, useWorkspaceStore,} from "../workspace/store";import type { WorkspaceSurfaceInstance } from "../workspace/types"; export const WORKSPACE_COMMAND_IDS = [ "workspace.terminal.splitRight", "workspace.terminal.splitDown", "workspace.terminal.newTab", "workspace.pane.splitRight", "workspace.pane.splitDown", "workspace.focus.left", "workspace.focus.right", "workspace.focus.up", "workspace.focus.down", "workspace.pane.close", "workspace.pane.moveLeft", "workspace.pane.moveRight", "workspace.pane.moveUp", "workspace.pane.moveDown", "workspace.tab.moveLeft", "workspace.tab.moveRight", "workspace.tab.moveUp", "workspace.tab.moveDown",] as const satisfies readonly KeybindingCommand[]; export type WorkspaceCommandId = (typeof WORKSPACE_COMMAND_IDS)[number]; export const WORKSPACE_COMMAND_METADATA: Record< WorkspaceCommandId, { searchTerms: readonly string[]; title: string; }> = { "workspace.terminal.splitRight": { title: "Open terminal in split right", searchTerms: ["terminal", "split", "right", "pane", "workspace"], }, "workspace.terminal.splitDown": { title: "Open terminal in split down", searchTerms: ["terminal", "split", "down", "bottom", "pane", "workspace"], }, "workspace.terminal.newTab": { title: "Open terminal as tab", searchTerms: ["terminal", "tab", "pane", "workspace"], }, "workspace.pane.splitRight": { title: "Open in split right", searchTerms: ["split", "pane", "right", "open", "workspace"], }, "workspace.pane.splitDown": { title: "Open in split down", searchTerms: ["split", "pane", "down", "open", "workspace"], }, "workspace.focus.left": { title: "Focus pane left", searchTerms: ["focus", "pane", "left", "workspace"], }, "workspace.focus.right": { title: "Focus pane right", searchTerms: ["focus", "pane", "right", "workspace"], }, "workspace.focus.up": { title: "Focus pane up", searchTerms: ["focus", "pane", "up", "workspace"], }, "workspace.focus.down": { title: "Focus pane down", searchTerms: ["focus", "pane", "down", "workspace"], }, "workspace.pane.close": { title: "Close current pane", searchTerms: ["close", "pane", "window", "workspace"], }, "workspace.pane.moveLeft": { title: "Move pane left", searchTerms: ["move", "pane", "left", "workspace"], }, "workspace.pane.moveRight": { title: "Move pane right", searchTerms: ["move", "pane", "right", "workspace"], }, "workspace.pane.moveUp": { title: "Move pane up", searchTerms: ["move", "pane", "up", "workspace"], }, "workspace.pane.moveDown": { title: "Move pane down", searchTerms: ["move", "pane", "down", "workspace"], }, "workspace.tab.moveLeft": { title: "Move tab left", searchTerms: ["move", "tab", "left", "workspace"], }, "workspace.tab.moveRight": { title: "Move tab right", searchTerms: ["move", "tab", "right", "workspace"], }, "workspace.tab.moveUp": { title: "Move tab up", searchTerms: ["move", "tab", "up", "workspace"], }, "workspace.tab.moveDown": { title: "Move tab down", searchTerms: ["move", "tab", "down", "workspace"], },}; function threadRefForWorkspaceSurface( surface: WorkspaceSurfaceInstance | null | undefined,): ScopedThreadRef | null { if (!surface) { return null; } if (surface.kind === "terminal") { return surface.input.threadRef; } if (surface.input.scope === "server") { return surface.input.threadRef; } return null;} export function isWorkspaceCommandId( command: string | null | undefined,): command is WorkspaceCommandId { return WORKSPACE_COMMAND_IDS.includes(command as WorkspaceCommandId);} export function useWorkspaceCommandExecutor() { const document = useWorkspaceDocument(); const focusedSurface = useFocusedWorkspaceSurface(); const openWorkspaceTarget = useCommandPaletteStore((state) => state.openWorkspaceTarget); const closeFocusedWindow = useWorkspaceStore((state) => state.closeFocusedWindow); const focusAdjacentWindow = useWorkspaceStore((state) => state.focusAdjacentWindow); const moveActiveTabToAdjacentWindow = useWorkspaceStore( (state) => state.moveActiveTabToAdjacentWindow, ); const moveFocusedWindow = useWorkspaceStore((state) => state.moveFocusedWindow); const openTerminalSurfaceForThread = useWorkspaceStore( (state) => state.openTerminalSurfaceForThread, ); const focusedWindowId = useMemo(() => { if (document.focusedWindowId && document.windowsById[document.focusedWindowId]) { return document.focusedWindowId; } return Object.keys(document.windowsById)[0] ?? null; }, [document]); const focusedThreadRef = useMemo( () => threadRefForWorkspaceSurface(focusedSurface), [focusedSurface], ); const executeWorkspaceCommand = useCallback( async (command: WorkspaceCommandId): Promise<boolean> => { switch (command) { case "workspace.terminal.splitRight": if (!focusedThreadRef) { return false; } openTerminalSurfaceForThread(focusedThreadRef, "split-right"); return true; case "workspace.terminal.splitDown": if (!focusedThreadRef) { return false; } openTerminalSurfaceForThread(focusedThreadRef, "split-down"); return true; case "workspace.terminal.newTab": if (!focusedThreadRef) { return false; } openTerminalSurfaceForThread(focusedThreadRef, "new-tab"); return true; case "workspace.pane.splitRight": if (!focusedWindowId) { return false; } openWorkspaceTarget({ disposition: "split-right" }); return true; case "workspace.pane.splitDown": if (!focusedWindowId) { return false; } openWorkspaceTarget({ disposition: "split-down" }); return true; case "workspace.focus.left": focusAdjacentWindow("left"); return true; case "workspace.focus.right": focusAdjacentWindow("right"); return true; case "workspace.focus.up": focusAdjacentWindow("up"); return true; case "workspace.focus.down": focusAdjacentWindow("down"); return true; case "workspace.pane.close": closeFocusedWindow(); return true; case "workspace.pane.moveLeft": moveFocusedWindow("left"); return true; case "workspace.pane.moveRight": moveFocusedWindow("right"); return true; case "workspace.pane.moveUp": moveFocusedWindow("up"); return true; case "workspace.pane.moveDown": moveFocusedWindow("down"); return true; case "workspace.tab.moveLeft": moveActiveTabToAdjacentWindow("left"); return true; case "workspace.tab.moveRight": moveActiveTabToAdjacentWindow("right"); return true; case "workspace.tab.moveUp": moveActiveTabToAdjacentWindow("up"); return true; case "workspace.tab.moveDown": moveActiveTabToAdjacentWindow("down"); return true; } }, [ closeFocusedWindow, focusAdjacentWindow, focusedThreadRef, focusedWindowId, moveActiveTabToAdjacentWindow, moveFocusedWindow, openTerminalSurfaceForThread, openWorkspaceTarget, ], ); return { canOpenTerminalSurface: focusedThreadRef !== null, canSplitFocusedPane: focusedWindowId !== null, executeWorkspaceCommand, focusedSurface, focusedThreadRef, focusedWindowId, };}
import type { KeybindingCommand, ScopedThreadRef } from "@t3tools/contracts";
import { useCallback, useMemo } from "react";
import { useCommandPaletteStore } from "../commandPaletteStore";
import {
useFocusedWorkspaceSurface,
useWorkspaceDocument,
useWorkspaceStore,
} from "../workspace/store";
import type { WorkspaceSurfaceInstance } from "../workspace/types";
export const WORKSPACE_COMMAND_IDS = [
"workspace.terminal.splitRight",
"workspace.terminal.splitDown",
"workspace.terminal.newTab",
"workspace.pane.splitRight",
"workspace.pane.splitDown",
"workspace.focus.left",
"workspace.focus.right",
"workspace.focus.up",
"workspace.focus.down",
"workspace.pane.close",
"workspace.pane.moveLeft",
"workspace.pane.moveRight",
"workspace.pane.moveUp",
"workspace.pane.moveDown",
"workspace.tab.moveLeft",
"workspace.tab.moveRight",
"workspace.tab.moveUp",
"workspace.tab.moveDown",
] as const satisfies readonly KeybindingCommand[];
export type WorkspaceCommandId = (typeof WORKSPACE_COMMAND_IDS)[number];
export const WORKSPACE_COMMAND_METADATA: Record<
WorkspaceCommandId,
{
searchTerms: readonly string[];
title: string;
}
> = {
"workspace.terminal.splitRight": {
title: "Open terminal in split right",
searchTerms: ["terminal", "split", "right", "pane", "workspace"],
},
"workspace.terminal.splitDown": {
title: "Open terminal in split down",
searchTerms: ["terminal", "split", "down", "bottom", "pane", "workspace"],
},
"workspace.terminal.newTab": {
title: "Open terminal as tab",
searchTerms: ["terminal", "tab", "pane", "workspace"],
},
"workspace.pane.splitRight": {
title: "Open in split right",
searchTerms: ["split", "pane", "right", "open", "workspace"],
},
"workspace.pane.splitDown": {
title: "Open in split down",
searchTerms: ["split", "pane", "down", "open", "workspace"],
},
"workspace.focus.left": {
title: "Focus pane left",
searchTerms: ["focus", "pane", "left", "workspace"],
},
"workspace.focus.right": {
title: "Focus pane right",
searchTerms: ["focus", "pane", "right", "workspace"],
},
"workspace.focus.up": {
title: "Focus pane up",
searchTerms: ["focus", "pane", "up", "workspace"],
},
"workspace.focus.down": {
title: "Focus pane down",
searchTerms: ["focus", "pane", "down", "workspace"],
},
"workspace.pane.close": {
title: "Close current pane",
searchTerms: ["close", "pane", "window", "workspace"],
},
"workspace.pane.moveLeft": {
title: "Move pane left",
searchTerms: ["move", "pane", "left", "workspace"],
},
"workspace.pane.moveRight": {
title: "Move pane right",
searchTerms: ["move", "pane", "right", "workspace"],
},
"workspace.pane.moveUp": {
title: "Move pane up",
searchTerms: ["move", "pane", "up", "workspace"],
},
"workspace.pane.moveDown": {
title: "Move pane down",
searchTerms: ["move", "pane", "down", "workspace"],
},
"workspace.tab.moveLeft": {
title: "Move tab left",
searchTerms: ["move", "tab", "left", "workspace"],
},
"workspace.tab.moveRight": {
title: "Move tab right",
searchTerms: ["move", "tab", "right", "workspace"],
},
"workspace.tab.moveUp": {
title: "Move tab up",
searchTerms: ["move", "tab", "up", "workspace"],
},
"workspace.tab.moveDown": {
title: "Move tab down",
searchTerms: ["move", "tab", "down", "workspace"],
},
};
function threadRefForWorkspaceSurface(
surface: WorkspaceSurfaceInstance | null | undefined,
): ScopedThreadRef | null {
if (!surface) {
return null;
}
if (surface.kind === "terminal") {
return surface.input.threadRef;
}
if (surface.input.scope === "server") {
return surface.input.threadRef;
}
return null;
}
export function isWorkspaceCommandId(
command: string | null | undefined,
): command is WorkspaceCommandId {
return WORKSPACE_COMMAND_IDS.includes(command as WorkspaceCommandId);
}
export function useWorkspaceCommandExecutor() {
const document = useWorkspaceDocument();
const focusedSurface = useFocusedWorkspaceSurface();
const openWorkspaceTarget = useCommandPaletteStore((state) => state.openWorkspaceTarget);
const closeFocusedWindow = useWorkspaceStore((state) => state.closeFocusedWindow);
const focusAdjacentWindow = useWorkspaceStore((state) => state.focusAdjacentWindow);
const moveActiveTabToAdjacentWindow = useWorkspaceStore(
(state) => state.moveActiveTabToAdjacentWindow,
);
const moveFocusedWindow = useWorkspaceStore((state) => state.moveFocusedWindow);
const openTerminalSurfaceForThread = useWorkspaceStore(
(state) => state.openTerminalSurfaceForThread,
);
const focusedWindowId = useMemo(() => {
if (document.focusedWindowId && document.windowsById[document.focusedWindowId]) {
return document.focusedWindowId;
}
return Object.keys(document.windowsById)[0] ?? null;
}, [document]);
const focusedThreadRef = useMemo(
() => threadRefForWorkspaceSurface(focusedSurface),
[focusedSurface],
);
const executeWorkspaceCommand = useCallback(
async (command: WorkspaceCommandId): Promise<boolean> => {
switch (command) {
case "workspace.terminal.splitRight":
if (!focusedThreadRef) {
return false;
}
openTerminalSurfaceForThread(focusedThreadRef, "split-right");
return true;
case "workspace.terminal.splitDown":
if (!focusedThreadRef) {
return false;
}
openTerminalSurfaceForThread(focusedThreadRef, "split-down");
return true;
case "workspace.terminal.newTab":
if (!focusedThreadRef) {
return false;
}
openTerminalSurfaceForThread(focusedThreadRef, "new-tab");
return true;
case "workspace.pane.splitRight":
if (!focusedWindowId) {
return false;
}
openWorkspaceTarget({ disposition: "split-right" });
return true;
case "workspace.pane.splitDown":
if (!focusedWindowId) {
return false;
}
openWorkspaceTarget({ disposition: "split-down" });
return true;
case "workspace.focus.left":
focusAdjacentWindow("left");
return true;
case "workspace.focus.right":
focusAdjacentWindow("right");
return true;
case "workspace.focus.up":
focusAdjacentWindow("up");
return true;
case "workspace.focus.down":
focusAdjacentWindow("down");
return true;
case "workspace.pane.close":
closeFocusedWindow();
return true;
case "workspace.pane.moveLeft":
moveFocusedWindow("left");
return true;
case "workspace.pane.moveRight":
moveFocusedWindow("right");
return true;
case "workspace.pane.moveUp":
moveFocusedWindow("up");
return true;
case "workspace.pane.moveDown":
moveFocusedWindow("down");
return true;
case "workspace.tab.moveLeft":
moveActiveTabToAdjacentWindow("left");
return true;
case "workspace.tab.moveRight":
moveActiveTabToAdjacentWindow("right");
return true;
case "workspace.tab.moveUp":
moveActiveTabToAdjacentWindow("up");
return true;
case "workspace.tab.moveDown":
moveActiveTabToAdjacentWindow("down");
return true;
}
},
[
closeFocusedWindow,
focusAdjacentWindow,
focusedThreadRef,
focusedWindowId,
moveActiveTabToAdjacentWindow,
moveFocusedWindow,
openTerminalSurfaceForThread,
openWorkspaceTarget,
],
);
return {
canOpenTerminalSurface: focusedThreadRef !== null,
canSplitFocusedPane: focusedWindowId !== null,
executeWorkspaceCommand,
focusedSurface,
focusedThreadRef,
focusedWindowId,
};
}