feat(cli): remove editor environment fallback and use feedback instead of dialog

This commit is contained in:
A.K.M. Adib
2026-05-05 08:49:24 -04:00
parent d98910b77c
commit 7fbcd0e765
4 changed files with 14 additions and 52 deletions
@@ -60,7 +60,7 @@ describe('useTextBuffer external editor', () => {
vi.clearAllMocks();
});
it('should emit RequestEditorSelection when openFileInEditor throws EditorNotConfiguredError', async () => {
it('should emit feedback when openFileInEditor throws EditorNotConfiguredError', async () => {
vi.mocked(openFileInEditor).mockRejectedValue(
new EditorNotConfiguredError(),
);
@@ -76,7 +76,11 @@ describe('useTextBuffer external editor', () => {
await result.current.openInExternalEditor();
});
expect(coreEvents.emit).toHaveBeenCalledWith(
expect(coreEvents.emitFeedback).toHaveBeenCalledWith(
'warning',
'No external editor configured. Please set your preferred editor in settings.',
);
expect(coreEvents.emit).not.toHaveBeenCalledWith(
CoreEvent.RequestEditorSelection,
);
});
@@ -12,7 +12,6 @@ import { useState, useCallback, useEffect, useMemo, useReducer } from 'react';
import { LRUCache } from 'mnemonist';
import {
coreEvents,
CoreEvent,
debugLogger,
unescapePath,
type EditorType,
@@ -3347,7 +3346,10 @@ export function useTextBuffer({
dispatch({ type: 'set_text', payload: newText, pushToUndo: false });
} catch (err) {
if (err instanceof EditorNotConfiguredError) {
coreEvents.emit(CoreEvent.RequestEditorSelection);
coreEvents.emitFeedback(
'warning',
'No external editor configured. Please set your preferred editor in settings.',
);
return;
}
coreEvents.emitFeedback(
+4 -31
View File
@@ -46,7 +46,7 @@ describe('editorUtils', () => {
vi.unstubAllEnvs();
});
it('should throw EditorNotConfiguredError if no editor is configured and no env vars set', async () => {
it('should throw EditorNotConfiguredError if no editor is configured', async () => {
await expect(openFileInEditor('test.txt', null, undefined)).rejects.toThrow(
EditorNotConfiguredError,
);
@@ -86,40 +86,13 @@ describe('editorUtils', () => {
);
});
it('should use VISUAL env var if set', async () => {
vi.stubEnv('VISUAL', 'nano');
vi.mocked(spawnSync).mockReturnValue({
status: 0,
} as SpawnSyncReturns<Buffer>);
await openFileInEditor('test.txt', null, undefined);
expect(spawnSync).toHaveBeenCalledWith(
'nano',
expect.arrayContaining(['test.txt']),
expect.anything(),
);
});
it('should use EDITOR env var if set', async () => {
vi.stubEnv('EDITOR', 'nano');
vi.mocked(spawnSync).mockReturnValue({
status: 0,
} as SpawnSyncReturns<Buffer>);
await openFileInEditor('test.txt', null, undefined);
expect(spawnSync).toHaveBeenCalledWith(
'nano',
expect.arrayContaining(['test.txt']),
expect.anything(),
);
});
it('should handle editor exit with non-zero status', async () => {
vi.stubEnv('EDITOR', 'vim');
vi.mocked(spawnSync).mockReturnValue({
status: 1,
} as SpawnSyncReturns<Buffer>);
await expect(openFileInEditor('test.txt', null, undefined)).rejects.toThrow(
'External editor exited with status 1',
);
await expect(
openFileInEditor('test.txt', null, undefined, 'vim'),
).rejects.toThrow('External editor exited with status 1');
expect(coreEvents.emitFeedback).toHaveBeenCalledWith(
'error',
expect.any(String),
-17
View File
@@ -47,23 +47,6 @@ export async function openFileInEditor(
}
}
if (!command) {
command = process.env['VISUAL']?.trim() || process.env['EDITOR']?.trim();
if (command) {
const lowerCommand = command.toLowerCase();
const isGui = ['code', 'cursor', 'subl', 'zed', 'atom'].some((gui) =>
lowerCommand.includes(gui),
);
if (
isGui &&
!lowerCommand.includes('--wait') &&
!lowerCommand.includes('-w')
) {
args.unshift(lowerCommand.includes('subl') ? '-w' : '--wait');
}
}
}
if (!command) {
throw new EditorNotConfiguredError();
}