diff options
| -rw-r--r-- | packages/cli/src/gemini.ts | 19 | ||||
| -rw-r--r-- | packages/cli/src/ui/App.tsx | 20 | ||||
| -rw-r--r-- | packages/cli/src/ui/hooks/useThemeCommand.ts | 73 |
3 files changed, 92 insertions, 20 deletions
diff --git a/packages/cli/src/gemini.ts b/packages/cli/src/gemini.ts index 420f3242..32e34c20 100644 --- a/packages/cli/src/gemini.ts +++ b/packages/cli/src/gemini.ts @@ -24,7 +24,24 @@ async function main() { const settings = loadSettings(process.cwd()); const config = await loadCliConfig(settings.merged); if (settings.merged.theme) { - themeManager.setActiveTheme(settings.merged.theme); + try { + themeManager.setActiveTheme(settings.merged.theme); + } catch (error: unknown) { + // If the theme is not found during initial load, log a warning and continue. + // The useThemeCommand hook in App.tsx will handle opening the dialog. + if ( + error instanceof Error && + error.message.includes('Theme') && + error.message.includes('not found') + ) { + console.warn( + `Warning: ${error instanceof Error ? error.message : String(error)}`, + ); + } else { + // Re-throw other errors to be caught by the main catch block + throw error; + } + } } // hop into sandbox if we are outside and sandboxing is enabled diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index 9fe651b5..725a2012 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -39,12 +39,13 @@ export const App = ({ config, settings, cliVersion }: AppProps) => { const { history, addItem, clearItems } = useHistory(); const [startupWarnings, setStartupWarnings] = useState<string[]>([]); const [showHelp, setShowHelp] = useState<boolean>(false); + const [themeError, setThemeError] = useState<string | null>(null); const { isThemeDialogOpen, openThemeDialog, handleThemeSelect, handleThemeHighlight, - } = useThemeCommand(settings); + } = useThemeCommand(settings, setThemeError); const [staticKey, setStaticKey] = useState(0); const refreshStatic = useCallback(() => { @@ -191,11 +192,18 @@ export const App = ({ config, settings, cliVersion }: AppProps) => { )} {isThemeDialogOpen ? ( - <ThemeDialog - onSelect={handleThemeSelect} - onHighlight={handleThemeHighlight} - settings={settings} - /> + <Box flexDirection="column"> + {themeError && ( + <Box marginBottom={1}> + <Text color={Colors.AccentRed}>{themeError}</Text> + </Box> + )} + <ThemeDialog + onSelect={handleThemeSelect} + onHighlight={handleThemeHighlight} + settings={settings} + /> + </Box> ) : ( <> <LoadingIndicator diff --git a/packages/cli/src/ui/hooks/useThemeCommand.ts b/packages/cli/src/ui/hooks/useThemeCommand.ts index c32a7c2e..b1ae170f 100644 --- a/packages/cli/src/ui/hooks/useThemeCommand.ts +++ b/packages/cli/src/ui/hooks/useThemeCommand.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { useState, useCallback } from 'react'; +import { useState, useCallback, useEffect } from 'react'; import { themeManager } from '../themes/theme-manager.js'; import { LoadedSettings, SettingScope } from '../../config/settings.js'; // Import LoadedSettings, AppSettings, MergedSetting @@ -20,36 +20,83 @@ interface UseThemeCommandReturn { export const useThemeCommand = ( loadedSettings: LoadedSettings, + setThemeError: (error: string | null) => void, ): UseThemeCommandReturn => { // Determine the effective theme const effectiveTheme = loadedSettings.merged.theme; // Initial state: Open dialog if no theme is set in either user or workspace settings - const [isThemeDialogOpen, setIsThemeDialogOpen] = useState( - effectiveTheme === undefined, - ); + const [isThemeDialogOpen, setIsThemeDialogOpen] = useState(false); // TODO: refactor how theme's are accessed to avoid requiring a forced render. const [, setForceRender] = useState(0); + // Apply initial theme on component mount + useEffect(() => { + try { + themeManager.setActiveTheme(effectiveTheme); + setThemeError(null); // Clear any previous theme error on success + } catch (error: unknown) { + // If theme is not found during initial load, open the theme selection dialog and set error message + if ( + error instanceof Error && + error.message.includes('Theme') && + error.message.includes('not found') + ) { + setIsThemeDialogOpen(true); + setThemeError( + `Error: ${error instanceof Error ? error.message : String(error)}`, + ); + } else { + console.error( + `Error setting initial theme: ${error instanceof Error ? error.message : String(error)}`, + ); + setThemeError( + `Error setting initial theme: ${error instanceof Error ? error.message : String(error)}`, + ); + } + } + }, [effectiveTheme, setThemeError]); // Re-run if effectiveTheme or setThemeError changes + const openThemeDialog = useCallback(() => { setIsThemeDialogOpen(true); }, []); - const applyTheme = useCallback((themeName: string | undefined) => { - try { - themeManager.setActiveTheme(themeName); - setForceRender((v) => v + 1); // Trigger potential re-render - } catch (error) { - console.error(`Error setting theme: ${error}`); - } - }, []); + const applyTheme = useCallback( + (themeName: string | undefined) => { + try { + themeManager.setActiveTheme(themeName); + setForceRender((v) => v + 1); // Trigger potential re-render + setThemeError(null); // Clear any previous theme error on success + } catch (error: unknown) { + // If theme is not found, open the theme selection dialog and set error message + if ( + error instanceof Error && + error.message.includes('Theme') && + error.message.includes('not found') + ) { + setIsThemeDialogOpen(true); + setThemeError( + `Error: ${error instanceof Error ? error.message : String(error)}`, + ); + } else { + console.error( + `Error setting theme: ${error instanceof Error ? error.message : String(error)}`, + ); + setThemeError( + `Error setting theme: ${error instanceof Error ? error.message : String(error)}`, + ); + } + } + }, + [setForceRender, setThemeError], + ); const handleThemeHighlight = useCallback( (themeName: string | undefined) => { applyTheme(themeName); }, [applyTheme], - ); // Added applyTheme to dependencies + ); const handleThemeSelect = useCallback( (themeName: string | undefined, scope: SettingScope) => { |
