2025-09-11 13:27:27 -07:00
|
|
|
/**
|
|
|
|
|
* @license
|
|
|
|
|
* Copyright 2025 Google LLC
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { useCallback } from 'react';
|
|
|
|
|
import type React from 'react';
|
|
|
|
|
import { useKeypress } from '../hooks/useKeypress.js';
|
|
|
|
|
import { ShellExecutionService } from '@google/gemini-cli-core';
|
|
|
|
|
import { keyToAnsi, type Key } from '../hooks/keyToAnsi.js';
|
2026-02-08 00:09:48 -08:00
|
|
|
import { ACTIVE_SHELL_MAX_LINES } from '../constants.js';
|
2026-01-30 09:53:09 -08:00
|
|
|
import { Command, keyMatchers } from '../keyMatchers.js';
|
2025-09-11 13:27:27 -07:00
|
|
|
|
|
|
|
|
export interface ShellInputPromptProps {
|
|
|
|
|
activeShellPtyId: number | null;
|
|
|
|
|
focus?: boolean;
|
2026-02-08 00:09:48 -08:00
|
|
|
scrollPageSize?: number;
|
2025-09-11 13:27:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const ShellInputPrompt: React.FC<ShellInputPromptProps> = ({
|
|
|
|
|
activeShellPtyId,
|
|
|
|
|
focus = true,
|
2026-02-08 00:09:48 -08:00
|
|
|
scrollPageSize = ACTIVE_SHELL_MAX_LINES,
|
2025-09-11 13:27:27 -07:00
|
|
|
}) => {
|
|
|
|
|
const handleShellInputSubmit = useCallback(
|
|
|
|
|
(input: string) => {
|
|
|
|
|
if (activeShellPtyId) {
|
|
|
|
|
ShellExecutionService.writeToPty(activeShellPtyId, input);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
[activeShellPtyId],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const handleInput = useCallback(
|
|
|
|
|
(key: Key) => {
|
|
|
|
|
if (!focus || !activeShellPtyId) {
|
2026-01-30 09:53:09 -08:00
|
|
|
return false;
|
2025-09-11 13:27:27 -07:00
|
|
|
}
|
2026-01-30 09:53:09 -08:00
|
|
|
// Allow background shell toggle to bubble up
|
|
|
|
|
if (keyMatchers[Command.TOGGLE_BACKGROUND_SHELL](key)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-08 00:09:48 -08:00
|
|
|
// Allow Shift+Tab to bubble up for focus navigation
|
2026-02-06 10:36:14 -08:00
|
|
|
if (keyMatchers[Command.UNFOCUS_SHELL_INPUT](key)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-08 00:09:48 -08:00
|
|
|
if (keyMatchers[Command.SCROLL_UP](key)) {
|
2025-09-11 13:27:27 -07:00
|
|
|
ShellExecutionService.scrollPty(activeShellPtyId, -1);
|
2026-01-30 09:53:09 -08:00
|
|
|
return true;
|
2025-09-11 13:27:27 -07:00
|
|
|
}
|
2026-02-08 00:09:48 -08:00
|
|
|
if (keyMatchers[Command.SCROLL_DOWN](key)) {
|
2025-09-11 13:27:27 -07:00
|
|
|
ShellExecutionService.scrollPty(activeShellPtyId, 1);
|
2026-01-30 09:53:09 -08:00
|
|
|
return true;
|
2025-09-11 13:27:27 -07:00
|
|
|
}
|
2026-02-08 00:09:48 -08:00
|
|
|
// TODO: Check pty service actually scrolls (request)[https://github.com/google-gemini/gemini-cli/pull/17438/changes/c9fdaf8967da0036bfef43592fcab5a69537df35#r2776479023].
|
|
|
|
|
if (keyMatchers[Command.PAGE_UP](key)) {
|
|
|
|
|
ShellExecutionService.scrollPty(activeShellPtyId, -scrollPageSize);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (keyMatchers[Command.PAGE_DOWN](key)) {
|
|
|
|
|
ShellExecutionService.scrollPty(activeShellPtyId, scrollPageSize);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2025-09-11 13:27:27 -07:00
|
|
|
|
|
|
|
|
const ansiSequence = keyToAnsi(key);
|
|
|
|
|
if (ansiSequence) {
|
|
|
|
|
handleShellInputSubmit(ansiSequence);
|
2026-01-30 09:53:09 -08:00
|
|
|
return true;
|
2025-09-11 13:27:27 -07:00
|
|
|
}
|
2026-01-30 09:53:09 -08:00
|
|
|
|
|
|
|
|
return false;
|
2025-09-11 13:27:27 -07:00
|
|
|
},
|
2026-02-08 00:09:48 -08:00
|
|
|
[focus, handleShellInputSubmit, activeShellPtyId, scrollPageSize],
|
2025-09-11 13:27:27 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
useKeypress(handleInput, { isActive: focus });
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
};
|