mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-07-15 20:40:35 -07:00
feat(cli): support @-mentioning files in AskUser custom input
This commit is contained in:
@@ -22,7 +22,7 @@ import type { SelectionListItem } from '../hooks/useSelectionList.js';
|
||||
import { TabHeader, type Tab } from './shared/TabHeader.js';
|
||||
import { useKeypress, type Key } from '../hooks/useKeypress.js';
|
||||
import { Command } from '../key/keyMatchers.js';
|
||||
import { TextInput } from './shared/TextInput.js';
|
||||
import { AutocompleteTextInput } from './shared/AutocompleteTextInput.js';
|
||||
import { formatCommand } from '../key/keybindingUtils.js';
|
||||
import {
|
||||
useTextBuffer,
|
||||
@@ -396,10 +396,12 @@ const TextQuestionView: React.FC<TextQuestionViewProps> = ({
|
||||
|
||||
<Box flexDirection="row" marginBottom={1}>
|
||||
<Text color={theme.status.success}>{'> '}</Text>
|
||||
<TextInput
|
||||
<AutocompleteTextInput
|
||||
buffer={buffer}
|
||||
placeholder={placeholder}
|
||||
onSubmit={handleSubmit}
|
||||
availableWidth={availableWidth}
|
||||
suggestionsPosition="below"
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -948,10 +950,12 @@ const ChoiceQuestionView: React.FC<ChoiceQuestionViewProps> = ({
|
||||
/>
|
||||
)}
|
||||
<Text color={theme.text.primary}> </Text>
|
||||
<TextInput
|
||||
<AutocompleteTextInput
|
||||
buffer={customBuffer}
|
||||
placeholder={placeholder}
|
||||
focus={context.isSelected}
|
||||
availableWidth={availableWidth}
|
||||
suggestionsPosition="below"
|
||||
onSubmit={(val) => {
|
||||
if (question.multiSelect) {
|
||||
const fullAnswer = buildAnswerString(
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import type React from 'react';
|
||||
import { Box } from 'ink';
|
||||
import { TextInput, type TextInputProps } from './TextInput.js';
|
||||
import { useCommandCompletion } from '../../hooks/useCommandCompletion.js';
|
||||
import { SuggestionsDisplay } from '../SuggestionsDisplay.js';
|
||||
import { useConfig } from '../../contexts/ConfigContext.js';
|
||||
import { useKeypress, type Key } from '../../hooks/useKeypress.js';
|
||||
import { useKeyMatchers } from '../../hooks/useKeyMatchers.js';
|
||||
import { Command } from '../../key/keyMatchers.js';
|
||||
import type { CommandContext } from '../../commands/types.js';
|
||||
|
||||
export interface AutocompleteTextInputProps extends TextInputProps {
|
||||
suggestionsPosition?: 'above' | 'below';
|
||||
availableWidth?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper around TextInput that provides @-mention autocomplete for files.
|
||||
*/
|
||||
export function AutocompleteTextInput(
|
||||
props: AutocompleteTextInputProps,
|
||||
): React.JSX.Element {
|
||||
const {
|
||||
suggestionsPosition = 'above',
|
||||
availableWidth = 80,
|
||||
...textInputProps
|
||||
} = props;
|
||||
const config = useConfig();
|
||||
const keyMatchers = useKeyMatchers();
|
||||
|
||||
const completion = useCommandCompletion({
|
||||
buffer: props.buffer,
|
||||
cwd: process.cwd(),
|
||||
slashCommands: [],
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
commandContext: {} as unknown as CommandContext,
|
||||
shellModeActive: false,
|
||||
config,
|
||||
active: props.focus ?? true,
|
||||
});
|
||||
|
||||
const handleKeypress = (key: Key) => {
|
||||
if (!completion.showSuggestions) return false;
|
||||
|
||||
if (key.name === 'tab') {
|
||||
completion.handleAutocomplete(completion.activeSuggestionIndex);
|
||||
return true;
|
||||
}
|
||||
if (keyMatchers[Command.MOVE_UP](key)) {
|
||||
completion.navigateUp();
|
||||
return true;
|
||||
}
|
||||
if (keyMatchers[Command.MOVE_DOWN](key)) {
|
||||
completion.navigateDown();
|
||||
return true;
|
||||
}
|
||||
if (keyMatchers[Command.SUBMIT](key) && !completion.isPerfectMatch) {
|
||||
completion.handleAutocomplete(completion.activeSuggestionIndex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
useKeypress(handleKeypress, {
|
||||
isActive: props.focus ?? true,
|
||||
priority: true,
|
||||
});
|
||||
|
||||
const suggestionsNode = completion.showSuggestions ? (
|
||||
<Box paddingRight={2}>
|
||||
<SuggestionsDisplay
|
||||
suggestions={completion.suggestions}
|
||||
activeIndex={completion.activeSuggestionIndex}
|
||||
isLoading={completion.isLoadingSuggestions}
|
||||
width={availableWidth}
|
||||
scrollOffset={completion.visibleStartIndex}
|
||||
userInput={props.buffer.text}
|
||||
mode="reverse"
|
||||
/>
|
||||
</Box>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<Box flexDirection="column">
|
||||
{suggestionsPosition === 'above' && suggestionsNode}
|
||||
<TextInput {...textInputProps} />
|
||||
{suggestionsPosition === 'below' && suggestionsNode}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user