From e4d978da7ce5422cd4d2a92d369985df6387ad79 Mon Sep 17 00:00:00 2001 From: Taylor Mullen Date: Sun, 18 May 2025 01:18:32 -0700 Subject: 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 --- .../cli/src/ui/components/HistoryItemDisplay.tsx | 2 ++ packages/cli/src/ui/components/InputPrompt.tsx | 22 +++++++++++++++++-- .../ui/components/messages/UserShellMessage.tsx | 25 ++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 packages/cli/src/ui/components/messages/UserShellMessage.tsx (limited to 'packages/cli/src/ui/components') 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 = ({ {/* Render standard message types */} {item.type === 'user' && } + {item.type === 'user_shell' && } {item.type === 'gemini' && ( 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 = ({ resetCompletion, setEditorState, onClearScreen, + shellModeActive, + setShellModeActive, }) => { const handleSubmit = useCallback( (submittedValue: string) => { @@ -116,6 +120,11 @@ export const InputPrompt: React.FC = ({ _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 = ({ inputHistory, setEditorState, onClearScreen, + shellModeActive, + setShellModeActive, + onChangeAndMoveCursor, ], ); return ( - - > + + + {shellModeActive ? '! ' : '> '} + = ({ text }) => { + // Remove leading '!' if present, as App.tsx adds it for the processor. + const commandToDisplay = text.startsWith('!') ? text.substring(1) : text; + + return ( + + $ + {commandToDisplay} + + ); +}; -- cgit v1.2.3