From 6be054513bcbf87559ca6ac8df99160740292256 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Thu, 11 Sep 2025 10:34:29 -0700 Subject: [PATCH] feat(ui): make accept edits & yolo mode match shell mode styles (#8200) --- .../src/ui/components/AutoAcceptIndicator.tsx | 2 +- packages/cli/src/ui/components/Composer.tsx | 1 + packages/cli/src/ui/components/Footer.tsx | 4 +- .../src/ui/components/InputPrompt.test.tsx | 34 +++++++++++++++++ .../cli/src/ui/components/InputPrompt.tsx | 38 ++++++++++++++----- .../src/ui/components/ShellModeIndicator.tsx | 2 +- .../__snapshots__/InputPrompt.test.tsx.snap | 19 ++++++++++ packages/cli/src/ui/themes/theme.ts | 4 +- 8 files changed, 89 insertions(+), 15 deletions(-) create mode 100644 packages/cli/src/ui/components/__snapshots__/InputPrompt.test.tsx.snap diff --git a/packages/cli/src/ui/components/AutoAcceptIndicator.tsx b/packages/cli/src/ui/components/AutoAcceptIndicator.tsx index 2fbc20bfdd..c72d366bb1 100644 --- a/packages/cli/src/ui/components/AutoAcceptIndicator.tsx +++ b/packages/cli/src/ui/components/AutoAcceptIndicator.tsx @@ -22,7 +22,7 @@ export const AutoAcceptIndicator: React.FC = ({ switch (approvalMode) { case ApprovalMode.AUTO_EDIT: - textColor = theme.status.success; + textColor = theme.status.warning; textContent = 'accepting edits'; subText = ' (shift + tab to toggle)'; break; diff --git a/packages/cli/src/ui/components/Composer.tsx b/packages/cli/src/ui/components/Composer.tsx index 07d9766029..531e3429b5 100644 --- a/packages/cli/src/ui/components/Composer.tsx +++ b/packages/cli/src/ui/components/Composer.tsx @@ -174,6 +174,7 @@ export const Composer = () => { commandContext={uiState.commandContext} shellModeActive={uiState.shellModeActive} setShellModeActive={uiActions.setShellModeActive} + approvalMode={showAutoAcceptIndicator} onEscapePromptChange={uiActions.onEscapePromptChange} focus={uiState.isFocused} vimHandleInput={uiActions.vimHandleInput} diff --git a/packages/cli/src/ui/components/Footer.tsx b/packages/cli/src/ui/components/Footer.tsx index f1cb7445fc..d3bfbf064c 100644 --- a/packages/cli/src/ui/components/Footer.tsx +++ b/packages/cli/src/ui/components/Footer.tsx @@ -138,7 +138,7 @@ export const Footer: React.FC = ({ {corgiMode && ( - | + | @@ -148,7 +148,7 @@ export const Footer: React.FC = ({ )} {!showErrorDetails && errorCount > 0 && ( - | + | )} diff --git a/packages/cli/src/ui/components/InputPrompt.test.tsx b/packages/cli/src/ui/components/InputPrompt.test.tsx index 5c6fddecec..888fff0bca 100644 --- a/packages/cli/src/ui/components/InputPrompt.test.tsx +++ b/packages/cli/src/ui/components/InputPrompt.test.tsx @@ -10,6 +10,7 @@ import type { InputPromptProps } from './InputPrompt.js'; import { InputPrompt } from './InputPrompt.js'; import type { TextBuffer } from './shared/text-buffer.js'; import type { Config } from '@google/gemini-cli-core'; +import { ApprovalMode } from '@google/gemini-cli-core'; import * as path from 'node:path'; import type { CommandContext, SlashCommand } from '../commands/types.js'; import { CommandKind } from '../commands/types.js'; @@ -207,6 +208,7 @@ describe('InputPrompt', () => { commandContext: mockCommandContext, shellModeActive: false, setShellModeActive: vi.fn(), + approvalMode: ApprovalMode.DEFAULT, inputWidth: 80, suggestionsWidth: 80, focus: true, @@ -1786,4 +1788,36 @@ describe('InputPrompt', () => { unmount(); }); }); + + describe('snapshots', () => { + it('should render correctly in shell mode', async () => { + props.shellModeActive = true; + const { stdout, unmount } = renderWithProviders( + , + ); + await wait(); + expect(stdout.lastFrame()).toMatchSnapshot(); + unmount(); + }); + + it('should render correctly when accepting edits', async () => { + props.approvalMode = ApprovalMode.AUTO_EDIT; + const { stdout, unmount } = renderWithProviders( + , + ); + await wait(); + expect(stdout.lastFrame()).toMatchSnapshot(); + unmount(); + }); + + it('should render correctly in yolo mode', async () => { + props.approvalMode = ApprovalMode.YOLO; + const { stdout, unmount } = renderWithProviders( + , + ); + await wait(); + expect(stdout.lastFrame()).toMatchSnapshot(); + unmount(); + }); + }); }); diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx index 10bd2e1812..8fe6fb82f5 100644 --- a/packages/cli/src/ui/components/InputPrompt.tsx +++ b/packages/cli/src/ui/components/InputPrompt.tsx @@ -23,6 +23,7 @@ import { useKeypress } from '../hooks/useKeypress.js'; import { keyMatchers, Command } from '../keyMatchers.js'; import type { CommandContext, SlashCommand } from '../commands/types.js'; import type { Config } from '@google/gemini-cli-core'; +import { ApprovalMode } from '@google/gemini-cli-core'; import { parseInputForHighlighting } from '../utils/highlight.js'; import { clipboardHasImage, @@ -46,6 +47,7 @@ export interface InputPromptProps { suggestionsWidth: number; shellModeActive: boolean; setShellModeActive: (value: boolean) => void; + approvalMode: ApprovalMode; onEscapePromptChange?: (showPrompt: boolean) => void; vimHandleInput?: (key: Key) => boolean; } @@ -64,6 +66,7 @@ export const InputPrompt: React.FC = ({ suggestionsWidth, shellModeActive, setShellModeActive, + approvalMode, onEscapePromptChange, vimHandleInput, }) => { @@ -709,21 +712,36 @@ export const InputPrompt: React.FC = ({ const { inlineGhost, additionalLines } = getGhostTextLines(); + const showAutoAcceptStyling = + !shellModeActive && approvalMode === ApprovalMode.AUTO_EDIT; + const showYoloStyling = + !shellModeActive && approvalMode === ApprovalMode.YOLO; + + let statusColor: string | undefined; + let statusText = ''; + if (shellModeActive) { + statusColor = theme.ui.symbol; + statusText = 'Shell mode'; + } else if (showYoloStyling) { + statusColor = theme.status.error; + statusText = 'YOLO mode'; + } else if (showAutoAcceptStyling) { + statusColor = theme.status.warning; + statusText = 'Accepting edits'; + } + return ( <> {shellModeActive ? ( reverseSearchActive ? ( @@ -734,11 +752,13 @@ export const InputPrompt: React.FC = ({ (r:){' '} ) : ( - '! ' + '!' ) + ) : showYoloStyling ? ( + '*' ) : ( - '> ' - )} + '>' + )}{' '} {buffer.text.length === 0 && placeholder ? ( diff --git a/packages/cli/src/ui/components/ShellModeIndicator.tsx b/packages/cli/src/ui/components/ShellModeIndicator.tsx index 6fbde05c68..10370d2e55 100644 --- a/packages/cli/src/ui/components/ShellModeIndicator.tsx +++ b/packages/cli/src/ui/components/ShellModeIndicator.tsx @@ -10,7 +10,7 @@ import { theme } from '../semantic-colors.js'; export const ShellModeIndicator: React.FC = () => ( - + shell mode enabled (esc to disable) diff --git a/packages/cli/src/ui/components/__snapshots__/InputPrompt.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/InputPrompt.test.tsx.snap new file mode 100644 index 0000000000..b955931d41 --- /dev/null +++ b/packages/cli/src/ui/components/__snapshots__/InputPrompt.test.tsx.snap @@ -0,0 +1,19 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`InputPrompt > snapshots > should render correctly in shell mode 1`] = ` +"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ ! Type your message or @path/to/file │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────╯" +`; + +exports[`InputPrompt > snapshots > should render correctly in yolo mode 1`] = ` +"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ * Type your message or @path/to/file │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────╯" +`; + +exports[`InputPrompt > snapshots > should render correctly when accepting edits 1`] = ` +"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ > Type your message or @path/to/file │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────╯" +`; diff --git a/packages/cli/src/ui/themes/theme.ts b/packages/cli/src/ui/themes/theme.ts index c04893c669..df33a59a10 100644 --- a/packages/cli/src/ui/themes/theme.ts +++ b/packages/cli/src/ui/themes/theme.ts @@ -174,8 +174,8 @@ export class Theme { focused: this.colors.AccentBlue, }, ui: { - comment: this.colors.Comment, - symbol: this.colors.Gray, + comment: this.colors.Gray, + symbol: this.colors.AccentCyan, gradient: this.colors.GradientColors, }, status: {