mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-02 09:20:42 -07:00
fix(cli): ensure Shift+Tab unfocuses interactive shell
- Update Command.UNFOCUS_SHELL_INPUT to explicitly require shift: true. - Allow UNFOCUS_SHELL_INPUT to bubble up from ShellInputPrompt. - Update AppContainer to handle UNFOCUS_SHELL_INPUT for unfocusing the shell. - Add unit tests for ShellInputPrompt and AppContainer.
This commit is contained in:
@@ -288,7 +288,7 @@ export const defaultKeyBindings: KeyBindingConfig = {
|
||||
{ key: 's', ctrl: true },
|
||||
],
|
||||
[Command.FOCUS_SHELL_INPUT]: [{ key: 'tab', shift: false }],
|
||||
[Command.UNFOCUS_SHELL_INPUT]: [{ key: 'tab' }],
|
||||
[Command.UNFOCUS_SHELL_INPUT]: [{ key: 'tab', shift: true }],
|
||||
[Command.CLEAR_SCREEN]: [{ key: 'l', ctrl: true }],
|
||||
[Command.RESTART_APP]: [{ key: 'r' }],
|
||||
[Command.SUSPEND_APP]: [{ key: 'z', ctrl: true }],
|
||||
|
||||
@@ -1940,6 +1940,28 @@ describe('AppContainer State Management', () => {
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Shell Focus', () => {
|
||||
it('should unfocus shell when Shift+Tab is pressed', async () => {
|
||||
mockedUseGeminiStream.mockReturnValue({
|
||||
...DEFAULT_GEMINI_STREAM_MOCK,
|
||||
activePtyId: 1,
|
||||
});
|
||||
|
||||
await setupKeypressTest();
|
||||
|
||||
act(() => {
|
||||
capturedUIActions.setEmbeddedShellFocused(true);
|
||||
});
|
||||
rerender();
|
||||
expect(capturedUIState.embeddedShellFocused).toBe(true);
|
||||
|
||||
pressKey({ name: 'tab', shift: true });
|
||||
|
||||
expect(capturedUIState.embeddedShellFocused).toBe(false);
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Copy Mode (CTRL+S)', () => {
|
||||
|
||||
@@ -1500,10 +1500,11 @@ Logging in with Google... Restarting Gemini CLI to continue.
|
||||
setConstrainHeight(false);
|
||||
return true;
|
||||
} else if (
|
||||
keyMatchers[Command.FOCUS_SHELL_INPUT](key) &&
|
||||
(keyMatchers[Command.FOCUS_SHELL_INPUT](key) ||
|
||||
keyMatchers[Command.UNFOCUS_SHELL_INPUT](key)) &&
|
||||
(activePtyId || (isBackgroundShellVisible && backgroundShells.size > 0))
|
||||
) {
|
||||
if (key.name === 'tab' && key.shift) {
|
||||
if (keyMatchers[Command.UNFOCUS_SHELL_INPUT](key)) {
|
||||
// Always change focus
|
||||
setEmbeddedShellFocused(false);
|
||||
return true;
|
||||
|
||||
@@ -111,4 +111,22 @@ describe('ShellInputPrompt', () => {
|
||||
|
||||
expect(mockWriteToPty).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('bubbles up Shift+Tab for unfocusing', () => {
|
||||
render(<ShellInputPrompt activeShellPtyId={1} focus={true} />);
|
||||
|
||||
const handler = mockUseKeypress.mock.calls[0][0];
|
||||
|
||||
const result = handler({
|
||||
name: 'tab',
|
||||
shift: true,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
sequence: '\x1b[Z',
|
||||
});
|
||||
|
||||
expect(result).toBe(false);
|
||||
expect(mockWriteToPty).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -40,6 +40,11 @@ export const ShellInputPrompt: React.FC<ShellInputPromptProps> = ({
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow unfocus to bubble up
|
||||
if (keyMatchers[Command.UNFOCUS_SHELL_INPUT](key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key.ctrl && key.shift && key.name === 'up') {
|
||||
ShellExecutionService.scrollPty(activeShellPtyId, -1);
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user