/** * @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 ? ( ) : null; return ( {suggestionsPosition === 'above' && suggestionsNode} {suggestionsPosition === 'below' && suggestionsNode} ); }