diff options
| author | Allen Hutchison <[email protected]> | 2025-04-29 13:29:57 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-04-29 13:29:57 -0700 |
| commit | 28767b369f6d59ef822954f22667bdf87507e756 (patch) | |
| tree | 34a38bd646ac650588ad59b5b9166df27dbf9eb3 /packages/cli/src/ui/hooks/slashCommandProcessor.ts | |
| parent | 4793e86f04d84b8fe8887e3db08b8694315d38a1 (diff) | |
Refactor useGeminiStream to pull slash commands and passthrough comma… (#215)
* Refactor useGeminiStream to pull slash commands and passthrough commands into their own processors.
* whitespace lint errors.
* Add sugestions from code review.
Diffstat (limited to 'packages/cli/src/ui/hooks/slashCommandProcessor.ts')
| -rw-r--r-- | packages/cli/src/ui/hooks/slashCommandProcessor.ts | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/packages/cli/src/ui/hooks/slashCommandProcessor.ts b/packages/cli/src/ui/hooks/slashCommandProcessor.ts new file mode 100644 index 00000000..852f64ce --- /dev/null +++ b/packages/cli/src/ui/hooks/slashCommandProcessor.ts @@ -0,0 +1,110 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { useCallback } from 'react'; +import { type PartListUnion } from '@google/genai'; +import { HistoryItem } from '../types.js'; +import { isSlashCommand } from '../utils/commandUtils.js'; + +interface SlashCommand { + name: string; // slash command + description: string; // flavor text in UI + action: (value: PartListUnion) => void; +} + +const addHistoryItem = ( + setHistory: React.Dispatch<React.SetStateAction<HistoryItem[]>>, + itemData: Omit<HistoryItem, 'id'>, + id: number, +) => { + setHistory((prevHistory) => [ + ...prevHistory, + { ...itemData, id } as HistoryItem, + ]); +}; + +export const useSlashCommandProcessor = ( + setHistory: React.Dispatch<React.SetStateAction<HistoryItem[]>>, + setDebugMessage: React.Dispatch<React.SetStateAction<string>>, + getNextMessageId: (baseTimestamp: number) => number, +) => { + const slashCommands: SlashCommand[] = [ + { + name: 'clear', + description: 'clear the screen', + action: (_value: PartListUnion) => { + // This just clears the *UI* history, not the model history. + setDebugMessage('Clearing terminal.'); + setHistory((_) => []); + }, + }, + { + name: 'exit', + description: 'Exit gemini-code', + action: (_value: PartListUnion) => { + setDebugMessage('Exiting. Good-bye.'); + const timestamp = getNextMessageId(Date.now()); + addHistoryItem( + setHistory, + { type: 'info', text: 'good-bye!' }, + timestamp, + ); + process.exit(0); + }, + }, + { + // TODO: dedup with exit by adding altName or cmdRegex. + name: 'quit', + description: 'Quit gemini-code', + action: (_value: PartListUnion) => { + setDebugMessage('Quitting. Good-bye.'); + const timestamp = getNextMessageId(Date.now()); + addHistoryItem( + setHistory, + { type: 'info', text: 'good-bye!' }, + timestamp, + ); + process.exit(0); + }, + }, + // Removed /theme command, handled in App.tsx + ]; + + // Checks if the query is a slash command and executes it if it is. + const handleSlashCommand = useCallback( + (rawQuery: PartListUnion): boolean => { + if (typeof rawQuery !== 'string') { + return false; + } + + const trimmedQuery = rawQuery.trim(); + if (!isSlashCommand(trimmedQuery)) { + return false; // Not a slash command + } + + const commandName = trimmedQuery.slice(1).split(/\s+/)[0]; // Get command name after '/' + + for (const cmd of slashCommands) { + if (commandName === cmd.name) { + // Add user message *before* execution + const userMessageTimestamp = Date.now(); + addHistoryItem( + setHistory, + { type: 'user', text: trimmedQuery }, + userMessageTimestamp, + ); + cmd.action(trimmedQuery); + return true; // Command was handled + } + } + + return false; // Not a recognized slash command + }, + [setDebugMessage, setHistory, getNextMessageId, slashCommands], + ); + + return { handleSlashCommand }; +}; |
