/** * Component that registers keybinding handlers for command bindings. * * Must be rendered inside KeybindingSetup to have access to the keybinding context. * Reads "command:*" actions from the current keybinding configuration and registers * handlers that invoke the corresponding slash command via onSubmit. * * Commands triggered via keybinding are treated as "immediate" - they execute right * away and preserve the user's existing input text (the prompt is not cleared). */ import { useMemo } from 'react'; import { useIsModalOverlayActive } from '../context/overlayContext.js'; import { useOptionalKeybindingContext } from '../keybindings/KeybindingContext.js'; import { useKeybindings } from '../keybindings/useKeybinding.js'; import type { PromptInputHelpers } from '../utils/handlePromptSubmit.js'; type Props = { // onSubmit accepts additional parameters beyond what we pass here, // so we use a rest parameter to allow any additional args onSubmit: ( input: string, helpers: PromptInputHelpers, ...rest: [speculationAccept?: undefined, options?: { fromKeybinding?: boolean }] ) => void; /** Set to false to disable command keybindings (e.g., when a dialog is open) */ isActive?: boolean; }; const NOOP_HELPERS: PromptInputHelpers = { setCursorOffset: () => {}, clearBuffer: () => {}, resetHistory: () => {}, }; /** * Registers keybinding handlers for all "command:*" actions found in the * user's keybinding configuration. When triggered, each handler submits * the corresponding slash command (e.g., "command:commit" submits "/commit"). */ export function CommandKeybindingHandlers({ onSubmit, isActive = true }: Props): null { const keybindingContext = useOptionalKeybindingContext(); const isModalOverlayActive = useIsModalOverlayActive(); // Extract command actions from parsed bindings const commandActions = useMemo(() => { if (!keybindingContext) return new Set(); const actions = new Set(); for (const binding of keybindingContext.bindings) { if (binding.action?.startsWith('command:')) { actions.add(binding.action); } } return actions; }, [keybindingContext]); // Build handler map for all command actions const handlers = useMemo(() => { const map: Record void> = {}; for (const action of commandActions) { const commandName = action.slice('command:'.length); map[action] = () => { onSubmit(`/${commandName}`, NOOP_HELPERS, undefined, { fromKeybinding: true, }); }; } return map; }, [commandActions, onSubmit]); useKeybindings(handlers, { context: 'Chat', isActive: isActive && !isModalOverlayActive, }); return null; }