diff --git a/packages/cli/src/ui/components/EditorSettingsDialog.test.tsx b/packages/cli/src/ui/components/EditorSettingsDialog.test.tsx index 18b47def7b..7646ac4817 100644 --- a/packages/cli/src/ui/components/EditorSettingsDialog.test.tsx +++ b/packages/cli/src/ui/components/EditorSettingsDialog.test.tsx @@ -175,4 +175,45 @@ describe('EditorSettingsDialog', () => { } expect(frame).toContain('(Also modified'); }); + + it('emits error feedback only once when preferredEditor is invalid', async () => { + const mockEmitFeedback = vi.fn(); + vi.spyOn( + await import('@google/gemini-cli-core').then((m) => m.coreEvents), + 'emitFeedback', + ).mockImplementation(mockEmitFeedback); + + const invalidSettings = { + forScope: (_scope: string) => ({ + settings: { + general: { + preferredEditor: 'invalideditor', + }, + }, + }), + merged: { + general: { + preferredEditor: 'invalideditor', + }, + }, + } as unknown as LoadedSettings; + + const { unmount } = await renderWithProvider( + , + ); + + await waitFor(() => { + expect(mockEmitFeedback).toHaveBeenCalledWith( + 'error', + 'Editor is not supported: invalideditor', + ); + }); + + expect(mockEmitFeedback).toHaveBeenCalledTimes(1); + unmount(); + }); }); diff --git a/packages/cli/src/ui/components/EditorSettingsDialog.tsx b/packages/cli/src/ui/components/EditorSettingsDialog.tsx index 7fa0d2a2cf..41d27c4bfb 100644 --- a/packages/cli/src/ui/components/EditorSettingsDialog.tsx +++ b/packages/cli/src/ui/components/EditorSettingsDialog.tsx @@ -5,7 +5,7 @@ */ import type React from 'react'; -import { useState } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { Box, Text } from 'ink'; import { theme } from '../semantic-colors.js'; import { @@ -71,14 +71,26 @@ export function EditorSettingsDialog({ (item: EditorDisplay) => item.type === currentPreference, ) : 0; - if (editorIndex === -1) { - coreEvents.emitFeedback( - 'error', - `Editor is not supported: ${currentPreference}`, - ); + const isUnsupportedEditor = editorIndex === -1; + if (isUnsupportedEditor) { editorIndex = 0; } + const reportedInvalidEditors = useRef(new Set()); + useEffect(() => { + if ( + isUnsupportedEditor && + currentPreference && + !reportedInvalidEditors.current.has(currentPreference) + ) { + coreEvents.emitFeedback( + 'error', + `Editor is not supported: ${currentPreference}`, + ); + reportedInvalidEditors.current.add(currentPreference); + } + }, [isUnsupportedEditor, currentPreference]); + const scopeItems: Array<{ label: string; value: LoadableSettingScope;