/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import type React from 'react'; import { useState } from 'react'; import { Box, Text } from 'ink'; import { theme } from '../semantic-colors.js'; import { EDITOR_DISPLAY_NAMES, editorSettingsManager, type EditorDisplay, } from '../editors/editorSettingsManager.js'; import { RadioButtonSelect } from './shared/RadioButtonSelect.js'; import type { LoadedSettings } from '../../config/settings.js'; import { SettingScope } from '../../config/settings.js'; import type { EditorType } from '@qwen-code/qwen-code-core'; import { isEditorAvailable } from '@qwen-code/qwen-code-core'; import { useKeypress } from '../hooks/useKeypress.js'; import { t } from '../../i18n/index.js'; interface EditorDialogProps { onSelect: (editorType: EditorType | undefined, scope: SettingScope) => void; settings: LoadedSettings; onExit: () => void; } export function EditorSettingsDialog({ onSelect, settings, onExit, }: EditorDialogProps): React.JSX.Element { const [selectedScope, setSelectedScope] = useState( SettingScope.User, ); const [focusedSection, setFocusedSection] = useState<'editor' | 'scope'>( 'editor', ); useKeypress( (key) => { if (key.name === 'tab') { setFocusedSection((prev) => (prev === 'editor' ? 'scope' : 'editor')); } if (key.name === 'escape') { onExit(); } }, { isActive: true }, ); const editorItems: EditorDisplay[] = editorSettingsManager.getAvailableEditorDisplays(); const currentPreference = settings.forScope(selectedScope).settings.general?.preferredEditor; let editorIndex = currentPreference ? editorItems.findIndex( (item: EditorDisplay) => item.type === currentPreference, ) : 0; if (editorIndex === -1) { console.error(`Editor is not supported: ${currentPreference}`); editorIndex = 0; } const scopeItems = [ { get label() { return t('User Settings'); }, value: SettingScope.User, key: SettingScope.User, }, { get label() { return t('Workspace Settings'); }, value: SettingScope.Workspace, key: SettingScope.Workspace, }, ]; const handleEditorSelect = (editorType: EditorType | 'not_set') => { if (editorType === 'not_set') { onSelect(undefined, selectedScope); return; } onSelect(editorType, selectedScope); }; const handleScopeSelect = (scope: SettingScope) => { setSelectedScope(scope); setFocusedSection('editor'); }; let otherScopeModifiedMessage = ''; const otherScope = selectedScope === SettingScope.User ? SettingScope.Workspace : SettingScope.User; if ( settings.forScope(otherScope).settings.general?.preferredEditor !== undefined ) { otherScopeModifiedMessage = settings.forScope(selectedScope).settings.general?.preferredEditor !== undefined ? `(Also modified in ${otherScope})` : `(Modified in ${otherScope})`; } let mergedEditorName = 'None'; if ( settings.merged.general?.preferredEditor && isEditorAvailable(settings.merged.general?.preferredEditor) ) { mergedEditorName = EDITOR_DISPLAY_NAMES[ settings.merged.general?.preferredEditor as EditorType ]; } return ( {focusedSection === 'editor' ? '> ' : ' '}Select Editor{' '} {otherScopeModifiedMessage} ({ label: item.name, value: item.type, disabled: item.disabled, key: item.type, }))} initialIndex={editorIndex} onSelect={handleEditorSelect} isFocused={focusedSection === 'editor'} key={selectedScope} /> {focusedSection === 'scope' ? '> ' : ' '} {t('Apply To')} (Use Enter to select, Tab to change focus) Editor Preference These editors are currently supported. Please note that some editors cannot be used in sandbox mode. Your preferred editor is:{' '} {mergedEditorName} . ); }