Files
qwen-code/packages/cli/src/ui/hooks/useThemeCommand.ts

113 lines
3.5 KiB
TypeScript

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { useState, useCallback } from 'react';
import { themeManager } from '../themes/theme-manager.js';
import type { LoadedSettings, SettingScope } from '../../config/settings.js'; // Import LoadedSettings, AppSettings, MergedSetting
import { type HistoryItem, MessageType } from '../types.js';
import process from 'node:process';
import { t } from '../../i18n/index.js';
interface UseThemeCommandReturn {
isThemeDialogOpen: boolean;
openThemeDialog: () => void;
handleThemeSelect: (
themeName: string | undefined,
scope: SettingScope,
) => void; // Added scope
handleThemeHighlight: (themeName: string | undefined) => void;
}
export const useThemeCommand = (
loadedSettings: LoadedSettings,
setThemeError: (error: string | null) => void,
addItem: (item: Omit<HistoryItem, 'id'>, timestamp: number) => void,
initialThemeError: string | null,
): UseThemeCommandReturn => {
const [isThemeDialogOpen, setIsThemeDialogOpen] =
useState(!!initialThemeError);
const openThemeDialog = useCallback(() => {
if (process.env['NO_COLOR']) {
addItem(
{
type: MessageType.INFO,
text: t(
'Theme configuration unavailable due to NO_COLOR env variable.',
),
},
Date.now(),
);
return;
}
setIsThemeDialogOpen(true);
}, [addItem]);
const applyTheme = useCallback(
(themeName: string | undefined) => {
if (!themeManager.setActiveTheme(themeName)) {
// If theme is not found, open the theme selection dialog and set error message
setIsThemeDialogOpen(true);
setThemeError(
t('Theme "{{themeName}}" not found.', {
themeName: themeName ?? '',
}),
);
} else {
setThemeError(null); // Clear any previous theme error on success
}
},
[setThemeError],
);
const handleThemeHighlight = useCallback(
(themeName: string | undefined) => {
applyTheme(themeName);
},
[applyTheme],
);
const handleThemeSelect = useCallback(
(themeName: string | undefined, scope: SettingScope) => {
try {
// Merge user and workspace custom themes (workspace takes precedence)
const mergedCustomThemes = {
...(loadedSettings.user.settings.ui?.customThemes || {}),
...(loadedSettings.workspace.settings.ui?.customThemes || {}),
};
// Only allow selecting themes available in the merged custom themes or built-in themes
const isBuiltIn = themeManager.findThemeByName(themeName);
const isCustom = themeName && mergedCustomThemes[themeName];
if (!isBuiltIn && !isCustom) {
setThemeError(
t('Theme "{{themeName}}" not found in selected scope.', {
themeName: themeName ?? '',
}),
);
setIsThemeDialogOpen(true);
return;
}
loadedSettings.setValue(scope, 'ui.theme', themeName); // Update the merged settings
if (loadedSettings.merged.ui?.customThemes) {
themeManager.loadCustomThemes(loadedSettings.merged.ui?.customThemes);
}
applyTheme(loadedSettings.merged.ui?.theme); // Apply the current theme
setThemeError(null);
} finally {
setIsThemeDialogOpen(false); // Close the dialog
}
},
[applyTheme, loadedSettings, setThemeError],
);
return {
isThemeDialogOpen,
openThemeDialog,
handleThemeSelect,
handleThemeHighlight,
};
};