mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-17 09:30:58 -07:00
Fix: add back fastreturn support (#16440)
This commit is contained in:
committed by
GitHub
parent
8437ce940a
commit
e049d5e4e8
@@ -38,6 +38,7 @@ import { createMockCommandContext } from '../../test-utils/mockCommandContext.js
|
||||
import stripAnsi from 'strip-ansi';
|
||||
import chalk from 'chalk';
|
||||
import { StreamingState } from '../types.js';
|
||||
import { terminalCapabilityManager } from '../utils/terminalCapabilityManager.js';
|
||||
|
||||
vi.mock('../hooks/useShellHistory.js');
|
||||
vi.mock('../hooks/useCommandCompletion.js');
|
||||
@@ -124,6 +125,10 @@ describe('InputPrompt', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
vi.spyOn(
|
||||
terminalCapabilityManager,
|
||||
'isKittyProtocolEnabled',
|
||||
).mockReturnValue(true);
|
||||
|
||||
mockCommandContext = createMockCommandContext();
|
||||
|
||||
|
||||
@@ -35,9 +35,10 @@ import {
|
||||
type SettingDefinition,
|
||||
type SettingsSchemaType,
|
||||
} from '../../config/settingsSchema.js';
|
||||
import { terminalCapabilityManager } from '../utils/terminalCapabilityManager.js';
|
||||
|
||||
// Mock the VimModeContext
|
||||
const mockToggleVimEnabled = vi.fn();
|
||||
const mockToggleVimEnabled = vi.fn().mockResolvedValue(undefined);
|
||||
const mockSetVimMode = vi.fn();
|
||||
|
||||
vi.mock('../contexts/UIStateContext.js', () => ({
|
||||
@@ -253,7 +254,12 @@ const renderDialog = (
|
||||
|
||||
describe('SettingsDialog', () => {
|
||||
beforeEach(() => {
|
||||
mockToggleVimEnabled.mockResolvedValue(true);
|
||||
vi.clearAllMocks();
|
||||
vi.spyOn(
|
||||
terminalCapabilityManager,
|
||||
'isKittyProtocolEnabled',
|
||||
).mockReturnValue(true);
|
||||
mockToggleVimEnabled.mockRejectedValue(undefined);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -16,7 +16,9 @@ import {
|
||||
KeypressProvider,
|
||||
useKeypressContext,
|
||||
ESC_TIMEOUT,
|
||||
FAST_RETURN_TIMEOUT,
|
||||
} from './KeypressContext.js';
|
||||
import { terminalCapabilityManager } from '../utils/terminalCapabilityManager.js';
|
||||
import { useStdin } from 'ink';
|
||||
import { EventEmitter } from 'node:events';
|
||||
|
||||
@@ -154,6 +156,53 @@ describe('KeypressContext', () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe('Fast return buffering', () => {
|
||||
let kittySpy: ReturnType<typeof vi.spyOn>;
|
||||
|
||||
beforeEach(() => {
|
||||
kittySpy = vi
|
||||
.spyOn(terminalCapabilityManager, 'isKittyProtocolEnabled')
|
||||
.mockReturnValue(false);
|
||||
});
|
||||
|
||||
afterEach(() => kittySpy.mockRestore());
|
||||
|
||||
it('should buffer return key pressed quickly after another key', async () => {
|
||||
const { keyHandler } = setupKeypressTest();
|
||||
|
||||
act(() => stdin.write('a'));
|
||||
expect(keyHandler).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ name: 'a' }),
|
||||
);
|
||||
|
||||
act(() => stdin.write('\r'));
|
||||
|
||||
expect(keyHandler).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
name: '',
|
||||
sequence: '\r',
|
||||
insertable: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should NOT buffer return key if delay is long enough', async () => {
|
||||
const { keyHandler } = setupKeypressTest();
|
||||
|
||||
act(() => stdin.write('a'));
|
||||
|
||||
vi.advanceTimersByTime(FAST_RETURN_TIMEOUT + 1);
|
||||
|
||||
act(() => stdin.write('\r'));
|
||||
|
||||
expect(keyHandler).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
name: 'return',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Escape key handling', () => {
|
||||
it('should recognize escape key (keycode 27) in kitty protocol', async () => {
|
||||
const { keyHandler } = setupKeypressTest();
|
||||
|
||||
@@ -19,6 +19,7 @@ import { ESC } from '../utils/input.js';
|
||||
import { parseMouseEvent } from '../utils/mouse.js';
|
||||
import { FOCUS_IN, FOCUS_OUT } from '../hooks/useFocus.js';
|
||||
import { appEvents, AppEvent } from '../../utils/events.js';
|
||||
import { terminalCapabilityManager } from '../utils/terminalCapabilityManager.js';
|
||||
|
||||
export const BACKSLASH_ENTER_TIMEOUT = 5;
|
||||
export const ESC_TIMEOUT = 50;
|
||||
@@ -143,6 +144,30 @@ function nonKeyboardEventFilter(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts return keys pressed quickly after other keys into plain
|
||||
* insertable return characters.
|
||||
*
|
||||
* This is to accommodate older terminals that paste text without bracketing.
|
||||
*/
|
||||
function bufferFastReturn(keypressHandler: KeypressHandler): KeypressHandler {
|
||||
let lastKeyTime = 0;
|
||||
return (key: Key) => {
|
||||
const now = Date.now();
|
||||
if (key.name === 'return' && now - lastKeyTime <= FAST_RETURN_TIMEOUT) {
|
||||
keypressHandler({
|
||||
...key,
|
||||
name: '',
|
||||
sequence: '\r',
|
||||
insertable: true,
|
||||
});
|
||||
} else {
|
||||
keypressHandler(key);
|
||||
}
|
||||
lastKeyTime = now;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffers "/" keys to see if they are followed return.
|
||||
* Will flush the buffer if no data is received for DRAG_COMPLETION_TIMEOUT_MS
|
||||
@@ -641,6 +666,9 @@ export function KeypressProvider({
|
||||
process.stdin.setEncoding('utf8'); // Make data events emit strings
|
||||
|
||||
let processor = nonKeyboardEventFilter(broadcast);
|
||||
if (!terminalCapabilityManager.isKittyProtocolEnabled()) {
|
||||
processor = bufferFastReturn(processor);
|
||||
}
|
||||
processor = bufferBackslashEnter(processor);
|
||||
processor = bufferPaste(processor);
|
||||
let dataListener = createDataListener(processor);
|
||||
|
||||
Reference in New Issue
Block a user