/** * @license * Copyright 2025 Vybestack LLC * SPDX-License-Identifier: Apache-2.0 */ import type React from 'react'; import { useState, useCallback } from 'react'; import { Box, Text } from 'ink'; import { Colors } from '../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 '@vybestack/llxprt-code-core'; import { isEditorAvailable } from '@vybestack/llxprt-code-core'; import { debugLogger } from '@vybestack/llxprt-code-telemetry'; import { useKeypress } from '../hooks/useKeypress.js'; import { getBorderStyle } from '../contexts/UnicodeRenderingContext.js'; interface EditorDialogProps { onSelect: (editorType: EditorType | undefined, scope: SettingScope) => void; settings: LoadedSettings; onExit: () => void; } const SCOPE_ITEMS = [ { label: 'User Settings', value: SettingScope.User, key: SettingScope.User, }, { label: 'Workspace Settings', value: SettingScope.Workspace, key: SettingScope.Workspace, }, ]; function getEditorIndex( editorItems: EditorDisplay[], currentPreference: string | undefined, ): number { if (!currentPreference) return 0; const index = editorItems.findIndex( (item: EditorDisplay) => item.type === currentPreference, ); if (index === -1) { debugLogger.error(`Editor is not supported: ${currentPreference}`); return 0; } return index; } function getOtherScopeMessage( settings: LoadedSettings, selectedScope: SettingScope, ): string { const otherScope = selectedScope === SettingScope.User ? SettingScope.Workspace : SettingScope.User; if ( settings.forScope(otherScope).settings.ui?.preferredEditor !== undefined ) { return settings.forScope(selectedScope).settings.ui?.preferredEditor !== undefined ? `(Also modified in ${otherScope})` : `(Modified in ${otherScope})`; } return ''; } function getMergedEditorName(settings: LoadedSettings): string { if ( settings.merged.ui.preferredEditor && isEditorAvailable(settings.merged.ui.preferredEditor) ) { return EDITOR_DISPLAY_NAMES[ settings.merged.ui.preferredEditor as EditorType ]; } return 'None'; } interface EditorLeftPanelProps { focusedSection: 'editor' | 'scope'; selectedScope: SettingScope; otherScopeModifiedMessage: string; editorItems: EditorDisplay[]; editorIndex: number; onEditorSelect: (editorType: EditorType | 'not_set') => void; onScopeSelect: (scope: SettingScope) => void; } const EditorLeftPanel: React.FC = ({ focusedSection, selectedScope, otherScopeModifiedMessage, editorItems, editorIndex, onEditorSelect, onScopeSelect, }) => ( {focusedSection === 'editor' ? '> ' : ' '}Select Editor{' '} {otherScopeModifiedMessage} ({ label: item.name, value: item.type, disabled: item.disabled, key: item.type, }))} initialIndex={editorIndex} onSelect={onEditorSelect} isFocused={focusedSection === 'editor'} key={selectedScope} /> {focusedSection === 'scope' ? '> ' : ' '}Apply To (Use Enter to select, Tab to change focus, Esc to close) ); interface EditorRightPanelProps { mergedEditorName: string; } const EditorRightPanel: React.FC = ({ mergedEditorName, }) => ( Editor Preference These editors are currently supported. Please note that some editors cannot be used in sandbox mode. Your preferred editor is:{' '} {mergedEditorName} . ); 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.ui?.preferredEditor; const editorIndex = getEditorIndex(editorItems, currentPreference); const handleEditorSelect = useCallback( (editorType: EditorType | 'not_set') => { if (editorType === 'not_set') { onSelect(undefined, selectedScope); return; } onSelect(editorType, selectedScope); }, [onSelect, selectedScope], ); const handleScopeSelect = useCallback((scope: SettingScope) => { setSelectedScope(scope); setFocusedSection('editor'); }, []); const otherScopeModifiedMessage = getOtherScopeMessage( settings, selectedScope, ); const mergedEditorName = getMergedEditorName(settings); return ( ); }