mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-18 18:11:02 -07:00
feat(plan): Extend Shift+Tab Mode Cycling to include Plan Mode (#17177)
This commit is contained in:
@@ -5,23 +5,32 @@
|
||||
*/
|
||||
|
||||
import { render } from '../../test-utils/render.js';
|
||||
import { AutoAcceptIndicator } from './AutoAcceptIndicator.js';
|
||||
import { ApprovalModeIndicator } from './ApprovalModeIndicator.js';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ApprovalMode } from '@google/gemini-cli-core';
|
||||
|
||||
describe('AutoAcceptIndicator', () => {
|
||||
describe('ApprovalModeIndicator', () => {
|
||||
it('renders correctly for AUTO_EDIT mode', () => {
|
||||
const { lastFrame } = render(
|
||||
<AutoAcceptIndicator approvalMode={ApprovalMode.AUTO_EDIT} />,
|
||||
<ApprovalModeIndicator approvalMode={ApprovalMode.AUTO_EDIT} />,
|
||||
);
|
||||
const output = lastFrame();
|
||||
expect(output).toContain('accepting edits');
|
||||
expect(output).toContain('(shift + tab to toggle)');
|
||||
expect(output).toContain('(shift + tab to cycle)');
|
||||
});
|
||||
|
||||
it('renders correctly for PLAN mode', () => {
|
||||
const { lastFrame } = render(
|
||||
<ApprovalModeIndicator approvalMode={ApprovalMode.PLAN} />,
|
||||
);
|
||||
const output = lastFrame();
|
||||
expect(output).toContain('plan mode');
|
||||
expect(output).toContain('(shift + tab to cycle)');
|
||||
});
|
||||
|
||||
it('renders correctly for YOLO mode', () => {
|
||||
const { lastFrame } = render(
|
||||
<AutoAcceptIndicator approvalMode={ApprovalMode.YOLO} />,
|
||||
<ApprovalModeIndicator approvalMode={ApprovalMode.YOLO} />,
|
||||
);
|
||||
const output = lastFrame();
|
||||
expect(output).toContain('YOLO mode');
|
||||
@@ -30,7 +39,7 @@ describe('AutoAcceptIndicator', () => {
|
||||
|
||||
it('renders nothing for DEFAULT mode', () => {
|
||||
const { lastFrame } = render(
|
||||
<AutoAcceptIndicator approvalMode={ApprovalMode.DEFAULT} />,
|
||||
<ApprovalModeIndicator approvalMode={ApprovalMode.DEFAULT} />,
|
||||
);
|
||||
const output = lastFrame();
|
||||
expect(output).not.toContain('accepting edits');
|
||||
@@ -9,11 +9,11 @@ import { Box, Text } from 'ink';
|
||||
import { theme } from '../semantic-colors.js';
|
||||
import { ApprovalMode } from '@google/gemini-cli-core';
|
||||
|
||||
interface AutoAcceptIndicatorProps {
|
||||
interface ApprovalModeIndicatorProps {
|
||||
approvalMode: ApprovalMode;
|
||||
}
|
||||
|
||||
export const AutoAcceptIndicator: React.FC<AutoAcceptIndicatorProps> = ({
|
||||
export const ApprovalModeIndicator: React.FC<ApprovalModeIndicatorProps> = ({
|
||||
approvalMode,
|
||||
}) => {
|
||||
let textColor = '';
|
||||
@@ -24,7 +24,12 @@ export const AutoAcceptIndicator: React.FC<AutoAcceptIndicatorProps> = ({
|
||||
case ApprovalMode.AUTO_EDIT:
|
||||
textColor = theme.status.warning;
|
||||
textContent = 'accepting edits';
|
||||
subText = ' (shift + tab to toggle)';
|
||||
subText = ' (shift + tab to cycle)';
|
||||
break;
|
||||
case ApprovalMode.PLAN:
|
||||
textColor = theme.status.success;
|
||||
textContent = 'plan mode';
|
||||
subText = ' (shift + tab to cycle)';
|
||||
break;
|
||||
case ApprovalMode.YOLO:
|
||||
textColor = theme.status.error;
|
||||
@@ -41,8 +41,8 @@ vi.mock('./HookStatusDisplay.js', () => ({
|
||||
HookStatusDisplay: () => <Text>HookStatusDisplay</Text>,
|
||||
}));
|
||||
|
||||
vi.mock('./AutoAcceptIndicator.js', () => ({
|
||||
AutoAcceptIndicator: () => <Text>AutoAcceptIndicator</Text>,
|
||||
vi.mock('./ApprovalModeIndicator.js', () => ({
|
||||
ApprovalModeIndicator: () => <Text>ApprovalModeIndicator</Text>,
|
||||
}));
|
||||
|
||||
vi.mock('./ShellModeIndicator.js', () => ({
|
||||
@@ -95,7 +95,7 @@ const createMockUIState = (overrides: Partial<UIState> = {}): UIState =>
|
||||
({
|
||||
streamingState: null,
|
||||
contextFileNames: [],
|
||||
showAutoAcceptIndicator: ApprovalMode.DEFAULT,
|
||||
showApprovalModeIndicator: ApprovalMode.DEFAULT,
|
||||
messageQueue: [],
|
||||
showErrorDetails: false,
|
||||
constrainHeight: false,
|
||||
@@ -419,15 +419,15 @@ describe('Composer', () => {
|
||||
expect(lastFrame()).not.toContain('InputPrompt');
|
||||
});
|
||||
|
||||
it('shows AutoAcceptIndicator when approval mode is not default and shell mode is inactive', () => {
|
||||
it('shows ApprovalModeIndicator when approval mode is not default and shell mode is inactive', () => {
|
||||
const uiState = createMockUIState({
|
||||
showAutoAcceptIndicator: ApprovalMode.YOLO,
|
||||
showApprovalModeIndicator: ApprovalMode.YOLO,
|
||||
shellModeActive: false,
|
||||
});
|
||||
|
||||
const { lastFrame } = renderComposer(uiState);
|
||||
|
||||
expect(lastFrame()).toContain('AutoAcceptIndicator');
|
||||
expect(lastFrame()).toContain('ApprovalModeIndicator');
|
||||
});
|
||||
|
||||
it('shows ShellModeIndicator when shell mode is active', () => {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useState } from 'react';
|
||||
import { Box, useIsScreenReaderEnabled } from 'ink';
|
||||
import { LoadingIndicator } from './LoadingIndicator.js';
|
||||
import { StatusDisplay } from './StatusDisplay.js';
|
||||
import { AutoAcceptIndicator } from './AutoAcceptIndicator.js';
|
||||
import { ApprovalModeIndicator } from './ApprovalModeIndicator.js';
|
||||
import { ShellModeIndicator } from './ShellModeIndicator.js';
|
||||
import { DetailedMessagesDisplay } from './DetailedMessagesDisplay.js';
|
||||
import { RawMarkdownIndicator } from './RawMarkdownIndicator.js';
|
||||
@@ -42,7 +42,7 @@ export const Composer = () => {
|
||||
const [suggestionsVisible, setSuggestionsVisible] = useState(false);
|
||||
|
||||
const isAlternateBuffer = useAlternateBuffer();
|
||||
const { showAutoAcceptIndicator } = uiState;
|
||||
const { showApprovalModeIndicator } = uiState;
|
||||
const suggestionsPosition = isAlternateBuffer ? 'above' : 'below';
|
||||
const hideContextSummary =
|
||||
suggestionsVisible && suggestionsPosition === 'above';
|
||||
@@ -92,9 +92,9 @@ export const Composer = () => {
|
||||
<StatusDisplay hideContextSummary={hideContextSummary} />
|
||||
</Box>
|
||||
<Box paddingTop={isNarrow ? 1 : 0}>
|
||||
{showAutoAcceptIndicator !== ApprovalMode.DEFAULT &&
|
||||
{showApprovalModeIndicator !== ApprovalMode.DEFAULT &&
|
||||
!uiState.shellModeActive && (
|
||||
<AutoAcceptIndicator approvalMode={showAutoAcceptIndicator} />
|
||||
<ApprovalModeIndicator approvalMode={showApprovalModeIndicator} />
|
||||
)}
|
||||
{uiState.shellModeActive && <ShellModeIndicator />}
|
||||
{!uiState.renderMarkdown && <RawMarkdownIndicator />}
|
||||
@@ -131,7 +131,7 @@ export const Composer = () => {
|
||||
commandContext={uiState.commandContext}
|
||||
shellModeActive={uiState.shellModeActive}
|
||||
setShellModeActive={uiActions.setShellModeActive}
|
||||
approvalMode={showAutoAcceptIndicator}
|
||||
approvalMode={showApprovalModeIndicator}
|
||||
onEscapePromptChange={uiActions.onEscapePromptChange}
|
||||
focus={true}
|
||||
vimHandleInput={uiActions.vimHandleInput}
|
||||
|
||||
Reference in New Issue
Block a user