mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-24 13:01:29 -07:00
feat(cli): support Ctrl-Z suspension (#18931)
Co-authored-by: Bharat Kunwar <brtkwr@gmail.com>
This commit is contained in:
committed by
GitHub
parent
868f43927e
commit
375ebca2da
@@ -135,6 +135,7 @@ vi.mock('./hooks/vim.js');
|
||||
vi.mock('./hooks/useFocus.js');
|
||||
vi.mock('./hooks/useBracketedPaste.js');
|
||||
vi.mock('./hooks/useLoadingIndicator.js');
|
||||
vi.mock('./hooks/useSuspend.js');
|
||||
vi.mock('./hooks/useFolderTrust.js');
|
||||
vi.mock('./hooks/useIdeTrustListener.js');
|
||||
vi.mock('./hooks/useMessageQueue.js');
|
||||
@@ -199,6 +200,7 @@ import { useLoadingIndicator } from './hooks/useLoadingIndicator.js';
|
||||
import { useInputHistoryStore } from './hooks/useInputHistoryStore.js';
|
||||
import { useKeypress, type Key } from './hooks/useKeypress.js';
|
||||
import * as useKeypressModule from './hooks/useKeypress.js';
|
||||
import { useSuspend } from './hooks/useSuspend.js';
|
||||
import { measureElement } from 'ink';
|
||||
import { useTerminalSize } from './hooks/useTerminalSize.js';
|
||||
import {
|
||||
@@ -271,6 +273,7 @@ describe('AppContainer State Management', () => {
|
||||
const mockedUseTextBuffer = useTextBuffer as Mock;
|
||||
const mockedUseLogger = useLogger as Mock;
|
||||
const mockedUseLoadingIndicator = useLoadingIndicator as Mock;
|
||||
const mockedUseSuspend = useSuspend as Mock;
|
||||
const mockedUseInputHistoryStore = useInputHistoryStore as Mock;
|
||||
const mockedUseHookDisplayState = useHookDisplayState as Mock;
|
||||
const mockedUseTerminalTheme = useTerminalTheme as Mock;
|
||||
@@ -402,6 +405,9 @@ describe('AppContainer State Management', () => {
|
||||
elapsedTime: '0.0s',
|
||||
currentLoadingPhrase: '',
|
||||
});
|
||||
mockedUseSuspend.mockReturnValue({
|
||||
handleSuspend: vi.fn(),
|
||||
});
|
||||
mockedUseHookDisplayState.mockReturnValue([]);
|
||||
mockedUseTerminalTheme.mockReturnValue(undefined);
|
||||
mockedUseShellInactivityStatus.mockReturnValue({
|
||||
@@ -441,8 +447,8 @@ describe('AppContainer State Management', () => {
|
||||
...defaultMergedSettings.ui,
|
||||
showStatusInTitle: false,
|
||||
hideWindowTitle: false,
|
||||
useAlternateBuffer: false,
|
||||
},
|
||||
useAlternateBuffer: false,
|
||||
},
|
||||
} as unknown as LoadedSettings;
|
||||
|
||||
@@ -728,10 +734,10 @@ describe('AppContainer State Management', () => {
|
||||
getChatRecordingService: vi.fn(() => mockChatRecordingService),
|
||||
};
|
||||
|
||||
const configWithRecording = {
|
||||
...mockConfig,
|
||||
getGeminiClient: vi.fn(() => mockGeminiClient),
|
||||
} as unknown as Config;
|
||||
const configWithRecording = makeFakeConfig();
|
||||
vi.spyOn(configWithRecording, 'getGeminiClient').mockReturnValue(
|
||||
mockGeminiClient as unknown as ReturnType<Config['getGeminiClient']>,
|
||||
);
|
||||
|
||||
expect(() => {
|
||||
renderAppContainer({
|
||||
@@ -762,11 +768,13 @@ describe('AppContainer State Management', () => {
|
||||
setHistory: vi.fn(),
|
||||
};
|
||||
|
||||
const configWithRecording = {
|
||||
...mockConfig,
|
||||
getGeminiClient: vi.fn(() => mockGeminiClient),
|
||||
getSessionId: vi.fn(() => 'test-session-123'),
|
||||
} as unknown as Config;
|
||||
const configWithRecording = makeFakeConfig();
|
||||
vi.spyOn(configWithRecording, 'getGeminiClient').mockReturnValue(
|
||||
mockGeminiClient as unknown as ReturnType<Config['getGeminiClient']>,
|
||||
);
|
||||
vi.spyOn(configWithRecording, 'getSessionId').mockReturnValue(
|
||||
'test-session-123',
|
||||
);
|
||||
|
||||
expect(() => {
|
||||
renderAppContainer({
|
||||
@@ -802,10 +810,10 @@ describe('AppContainer State Management', () => {
|
||||
getUserTier: vi.fn(),
|
||||
};
|
||||
|
||||
const configWithRecording = {
|
||||
...mockConfig,
|
||||
getGeminiClient: vi.fn(() => mockGeminiClient),
|
||||
} as unknown as Config;
|
||||
const configWithRecording = makeFakeConfig();
|
||||
vi.spyOn(configWithRecording, 'getGeminiClient').mockReturnValue(
|
||||
mockGeminiClient as unknown as ReturnType<Config['getGeminiClient']>,
|
||||
);
|
||||
|
||||
renderAppContainer({
|
||||
config: configWithRecording,
|
||||
@@ -836,10 +844,10 @@ describe('AppContainer State Management', () => {
|
||||
})),
|
||||
};
|
||||
|
||||
const configWithClient = {
|
||||
...mockConfig,
|
||||
getGeminiClient: vi.fn(() => mockGeminiClient),
|
||||
} as unknown as Config;
|
||||
const configWithClient = makeFakeConfig();
|
||||
vi.spyOn(configWithClient, 'getGeminiClient').mockReturnValue(
|
||||
mockGeminiClient as unknown as ReturnType<Config['getGeminiClient']>,
|
||||
);
|
||||
|
||||
const resumedData = {
|
||||
conversation: {
|
||||
@@ -892,10 +900,10 @@ describe('AppContainer State Management', () => {
|
||||
getChatRecordingService: vi.fn(),
|
||||
};
|
||||
|
||||
const configWithClient = {
|
||||
...mockConfig,
|
||||
getGeminiClient: vi.fn(() => mockGeminiClient),
|
||||
} as unknown as Config;
|
||||
const configWithClient = makeFakeConfig();
|
||||
vi.spyOn(configWithClient, 'getGeminiClient').mockReturnValue(
|
||||
mockGeminiClient as unknown as ReturnType<Config['getGeminiClient']>,
|
||||
);
|
||||
|
||||
const resumedData = {
|
||||
conversation: {
|
||||
@@ -945,10 +953,10 @@ describe('AppContainer State Management', () => {
|
||||
getUserTier: vi.fn(),
|
||||
};
|
||||
|
||||
const configWithRecording = {
|
||||
...mockConfig,
|
||||
getGeminiClient: vi.fn(() => mockGeminiClient),
|
||||
} as unknown as Config;
|
||||
const configWithRecording = makeFakeConfig();
|
||||
vi.spyOn(configWithRecording, 'getGeminiClient').mockReturnValue(
|
||||
mockGeminiClient as unknown as ReturnType<Config['getGeminiClient']>,
|
||||
);
|
||||
|
||||
renderAppContainer({
|
||||
config: configWithRecording,
|
||||
@@ -1943,6 +1951,19 @@ describe('AppContainer State Management', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('CTRL+Z', () => {
|
||||
it('should call handleSuspend', async () => {
|
||||
const handleSuspend = vi.fn();
|
||||
mockedUseSuspend.mockReturnValue({ handleSuspend });
|
||||
await setupKeypressTest();
|
||||
|
||||
pressKey('\x1A'); // Ctrl+Z
|
||||
|
||||
expect(handleSuspend).toHaveBeenCalledTimes(1);
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Focus Handling (Tab / Shift+Tab)', () => {
|
||||
beforeEach(() => {
|
||||
// Mock activePtyId to enable focus
|
||||
|
||||
Reference in New Issue
Block a user