mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-28 23:11:19 -07:00
feat(cli): unify /chat and /resume command UX (#20256)
This commit is contained in:
@@ -990,6 +990,12 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||
}
|
||||
|
||||
if (isEnterKey && buffer.text.startsWith('/')) {
|
||||
if (suggestion.submitValue) {
|
||||
setExpandedSuggestionIndex(-1);
|
||||
handleSubmit(suggestion.submitValue.trim());
|
||||
return true;
|
||||
}
|
||||
|
||||
const { isArgumentCompletion, leafCommand } =
|
||||
completion.slashCompletionRange;
|
||||
|
||||
|
||||
@@ -127,4 +127,44 @@ describe('SuggestionsDisplay', () => {
|
||||
await waitUntilReady();
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders command section separators for slash mode', async () => {
|
||||
const groupedSuggestions = [
|
||||
{
|
||||
label: 'list',
|
||||
value: 'list',
|
||||
description: 'Browse auto-saved chats',
|
||||
sectionTitle: 'auto',
|
||||
},
|
||||
{
|
||||
label: 'list',
|
||||
value: 'list',
|
||||
description: 'List checkpoints',
|
||||
sectionTitle: 'checkpoints',
|
||||
},
|
||||
{
|
||||
label: 'save',
|
||||
value: 'save',
|
||||
description: 'Save checkpoint',
|
||||
sectionTitle: 'checkpoints',
|
||||
},
|
||||
];
|
||||
|
||||
const { lastFrame, waitUntilReady } = render(
|
||||
<SuggestionsDisplay
|
||||
suggestions={groupedSuggestions}
|
||||
activeIndex={0}
|
||||
isLoading={false}
|
||||
width={100}
|
||||
scrollOffset={0}
|
||||
userInput="/resume"
|
||||
mode="slash"
|
||||
/>,
|
||||
);
|
||||
|
||||
await waitUntilReady();
|
||||
const frame = lastFrame();
|
||||
expect(frame).toContain('-- auto --');
|
||||
expect(frame).toContain('-- checkpoints --');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,9 +14,12 @@ import { sanitizeForDisplay } from '../utils/textUtils.js';
|
||||
export interface Suggestion {
|
||||
label: string;
|
||||
value: string;
|
||||
insertValue?: string;
|
||||
description?: string;
|
||||
matchedIndex?: number;
|
||||
commandKind?: CommandKind;
|
||||
sectionTitle?: string;
|
||||
submitValue?: string;
|
||||
}
|
||||
interface SuggestionsDisplayProps {
|
||||
suggestions: Suggestion[];
|
||||
@@ -86,6 +89,12 @@ export function SuggestionsDisplay({
|
||||
const isExpanded = originalIndex === expandedIndex;
|
||||
const textColor = isActive ? theme.ui.focus : theme.text.secondary;
|
||||
const isLong = suggestion.value.length >= MAX_WIDTH;
|
||||
const previousSectionTitle =
|
||||
suggestions[originalIndex - 1]?.sectionTitle;
|
||||
const shouldRenderSectionHeader =
|
||||
mode === 'slash' &&
|
||||
!!suggestion.sectionTitle &&
|
||||
suggestion.sectionTitle !== previousSectionTitle;
|
||||
const labelElement = (
|
||||
<ExpandableText
|
||||
label={suggestion.value}
|
||||
@@ -99,37 +108,48 @@ export function SuggestionsDisplay({
|
||||
return (
|
||||
<Box
|
||||
key={`${suggestion.value}-${originalIndex}`}
|
||||
flexDirection="row"
|
||||
backgroundColor={isActive ? theme.background.focus : undefined}
|
||||
flexDirection="column"
|
||||
>
|
||||
<Box
|
||||
{...(mode === 'slash'
|
||||
? { width: commandColumnWidth, flexShrink: 0 as const }
|
||||
: { flexShrink: 1 as const })}
|
||||
>
|
||||
<Box>
|
||||
{labelElement}
|
||||
{suggestion.commandKind &&
|
||||
COMMAND_KIND_SUFFIX[suggestion.commandKind] && (
|
||||
<Text color={textColor}>
|
||||
{COMMAND_KIND_SUFFIX[suggestion.commandKind]}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
{shouldRenderSectionHeader && (
|
||||
<Text color={theme.text.secondary}>
|
||||
-- {suggestion.sectionTitle} --
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{suggestion.description && (
|
||||
<Box flexGrow={1} paddingLeft={3}>
|
||||
<Text color={textColor} wrap="truncate">
|
||||
{sanitizeForDisplay(suggestion.description, 100)}
|
||||
</Text>
|
||||
<Box
|
||||
flexDirection="row"
|
||||
backgroundColor={isActive ? theme.background.focus : undefined}
|
||||
>
|
||||
<Box
|
||||
{...(mode === 'slash'
|
||||
? { width: commandColumnWidth, flexShrink: 0 as const }
|
||||
: { flexShrink: 1 as const })}
|
||||
>
|
||||
<Box>
|
||||
{labelElement}
|
||||
{suggestion.commandKind &&
|
||||
COMMAND_KIND_SUFFIX[suggestion.commandKind] && (
|
||||
<Text color={textColor}>
|
||||
{COMMAND_KIND_SUFFIX[suggestion.commandKind]}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
{isActive && isLong && (
|
||||
<Box width={3} flexShrink={0}>
|
||||
<Text color={Colors.Gray}>{isExpanded ? ' ← ' : ' → '}</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{suggestion.description && (
|
||||
<Box flexGrow={1} paddingLeft={3}>
|
||||
<Text color={textColor} wrap="truncate">
|
||||
{sanitizeForDisplay(suggestion.description, 100)}
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{isActive && isLong && (
|
||||
<Box width={3} flexShrink={0}>
|
||||
<Text color={Colors.Gray}>{isExpanded ? ' ← ' : ' → '}</Text>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user