summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/components
diff options
context:
space:
mode:
authorTaylor Mullen <[email protected]>2025-05-18 01:18:32 -0700
committerN. Taylor Mullen <[email protected]>2025-05-18 01:25:50 -0700
commite4d978da7ce5422cd4d2a92d369985df6387ad79 (patch)
treea1be044381a5c34b97cb1be8b790c4dd0ae01c3e /packages/cli/src/ui/components
parent0d4e0fe6477712f4781438b84096690d2e3c208e (diff)
feat(cli): Introduce toggleable shell mode with enhanced UI
- Implements a toggleable shell mode, removing the need to prefix every command with `!`. - Users can now enter and exit shell mode by typing `!` as the first character in an empty input prompt. - The input prompt visually indicates active shell mode with a distinct color and `! ` prefix. - Shell command history items (`user_shell`) are now visually differentiated from regular user messages. - This provides a cleaner and more streamlined user experience for frequent shell interactions. Fixes https://b.corp.google.com/issues/418509745
Diffstat (limited to 'packages/cli/src/ui/components')
-rw-r--r--packages/cli/src/ui/components/HistoryItemDisplay.tsx2
-rw-r--r--packages/cli/src/ui/components/InputPrompt.tsx22
-rw-r--r--packages/cli/src/ui/components/messages/UserShellMessage.tsx25
3 files changed, 47 insertions, 2 deletions
diff --git a/packages/cli/src/ui/components/HistoryItemDisplay.tsx b/packages/cli/src/ui/components/HistoryItemDisplay.tsx
index 0a5ba7d1..0b61fc04 100644
--- a/packages/cli/src/ui/components/HistoryItemDisplay.tsx
+++ b/packages/cli/src/ui/components/HistoryItemDisplay.tsx
@@ -7,6 +7,7 @@
import React from 'react';
import type { HistoryItem } from '../types.js';
import { UserMessage } from './messages/UserMessage.js';
+import { UserShellMessage } from './messages/UserShellMessage.js';
import { GeminiMessage } from './messages/GeminiMessage.js';
import { InfoMessage } from './messages/InfoMessage.js';
import { ErrorMessage } from './messages/ErrorMessage.js';
@@ -28,6 +29,7 @@ export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({
<Box flexDirection="column" key={item.id}>
{/* Render standard message types */}
{item.type === 'user' && <UserMessage text={item.text} />}
+ {item.type === 'user_shell' && <UserShellMessage text={item.text} />}
{item.type === 'gemini' && (
<GeminiMessage
text={item.text}
diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx
index b1e05554..c9ebaf14 100644
--- a/packages/cli/src/ui/components/InputPrompt.tsx
+++ b/packages/cli/src/ui/components/InputPrompt.tsx
@@ -26,6 +26,8 @@ interface InputPromptProps {
navigateSuggestionDown: () => void;
setEditorState: (updater: (prevState: EditorState) => EditorState) => void;
onClearScreen: () => void;
+ shellModeActive: boolean;
+ setShellModeActive: (value: boolean) => void;
}
export interface EditorState {
@@ -48,6 +50,8 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
resetCompletion,
setEditorState,
onClearScreen,
+ shellModeActive,
+ setShellModeActive,
}) => {
const handleSubmit = useCallback(
(submittedValue: string) => {
@@ -116,6 +120,11 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
_currentText?: string,
_cursorOffset?: number,
) => {
+ if (input === '!' && query === '' && !showSuggestions) {
+ setShellModeActive(!shellModeActive);
+ onChangeAndMoveCursor(''); // Clear the '!' from input
+ return true;
+ }
if (showSuggestions) {
if (key.upArrow) {
navigateSuggestionUp();
@@ -186,12 +195,21 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
inputHistory,
setEditorState,
onClearScreen,
+ shellModeActive,
+ setShellModeActive,
+ onChangeAndMoveCursor,
],
);
return (
- <Box borderStyle="round" borderColor={Colors.AccentBlue} paddingX={1}>
- <Text color={Colors.AccentPurple}>&gt; </Text>
+ <Box
+ borderStyle="round"
+ borderColor={shellModeActive ? Colors.AccentYellow : Colors.AccentBlue}
+ paddingX={1}
+ >
+ <Text color={shellModeActive ? Colors.AccentYellow : Colors.AccentPurple}>
+ {shellModeActive ? '! ' : '> '}
+ </Text>
<Box flexGrow={1}>
<MultilineTextEditor
key={editorState.key.toString()}
diff --git a/packages/cli/src/ui/components/messages/UserShellMessage.tsx b/packages/cli/src/ui/components/messages/UserShellMessage.tsx
new file mode 100644
index 00000000..946ca7e7
--- /dev/null
+++ b/packages/cli/src/ui/components/messages/UserShellMessage.tsx
@@ -0,0 +1,25 @@
+/**
+ * @license
+ * Copyright 2025 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { Box, Text } from 'ink';
+import { Colors } from '../../colors.js';
+
+interface UserShellMessageProps {
+ text: string;
+}
+
+export const UserShellMessage: React.FC<UserShellMessageProps> = ({ text }) => {
+ // Remove leading '!' if present, as App.tsx adds it for the processor.
+ const commandToDisplay = text.startsWith('!') ? text.substring(1) : text;
+
+ return (
+ <Box>
+ <Text color={Colors.AccentCyan}>$ </Text>
+ <Text>{commandToDisplay}</Text>
+ </Box>
+ );
+};