Improvements to suggestions & slash commands (#344)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
This commit is contained in:
parent
89aa1cad41
commit
416813452e
|
@ -314,7 +314,7 @@ export const App = ({
|
||||||
resetCompletion={completion.resetCompletionState}
|
resetCompletion={completion.resetCompletionState}
|
||||||
/>
|
/>
|
||||||
{completion.showSuggestions && (
|
{completion.showSuggestions && (
|
||||||
<Box marginTop={1}>
|
<Box>
|
||||||
<SuggestionsDisplay
|
<SuggestionsDisplay
|
||||||
suggestions={completion.suggestions}
|
suggestions={completion.suggestions}
|
||||||
activeIndex={completion.activeSuggestionIndex}
|
activeIndex={completion.activeSuggestionIndex}
|
||||||
|
|
|
@ -76,6 +76,7 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||||
const newValue = base + selectedSuggestion.value;
|
const newValue = base + selectedSuggestion.value;
|
||||||
onChangeAndMoveCursor(newValue);
|
onChangeAndMoveCursor(newValue);
|
||||||
onSubmit(newValue); // Execute the command
|
onSubmit(newValue); // Execute the command
|
||||||
|
onChangeAndMoveCursor(''); // Clear query after submit
|
||||||
} else {
|
} else {
|
||||||
// Handle @ command completion
|
// Handle @ command completion
|
||||||
const atIndex = query.lastIndexOf('@');
|
const atIndex = query.lastIndexOf('@');
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { Colors } from '../colors.js';
|
||||||
export interface Suggestion {
|
export interface Suggestion {
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
|
description?: string;
|
||||||
}
|
}
|
||||||
interface SuggestionsDisplayProps {
|
interface SuggestionsDisplayProps {
|
||||||
suggestions: Suggestion[];
|
suggestions: Suggestion[];
|
||||||
|
@ -29,7 +30,7 @@ export function SuggestionsDisplay({
|
||||||
}: SuggestionsDisplayProps) {
|
}: SuggestionsDisplayProps) {
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<Box borderStyle="round" paddingX={1} width={width}>
|
<Box paddingX={1} width={width}>
|
||||||
<Text color="gray">Loading suggestions...</Text>
|
<Text color="gray">Loading suggestions...</Text>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -48,20 +49,29 @@ export function SuggestionsDisplay({
|
||||||
const visibleSuggestions = suggestions.slice(startIndex, endIndex);
|
const visibleSuggestions = suggestions.slice(startIndex, endIndex);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box borderStyle="round" flexDirection="column" paddingX={1} width={width}>
|
<Box flexDirection="column" paddingX={1} width={width}>
|
||||||
{scrollOffset > 0 && <Text color={Colors.Foreground}>▲</Text>}
|
{scrollOffset > 0 && <Text color={Colors.Foreground}>▲</Text>}
|
||||||
|
|
||||||
{visibleSuggestions.map((suggestion, index) => {
|
{visibleSuggestions.map((suggestion, index) => {
|
||||||
const originalIndex = startIndex + index;
|
const originalIndex = startIndex + index;
|
||||||
const isActive = originalIndex === activeIndex;
|
const isActive = originalIndex === activeIndex;
|
||||||
|
const textColor = isActive ? Colors.AccentPurple : Colors.SubtleComment;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Text
|
<Box key={`${suggestion}-${originalIndex}`} width={width}>
|
||||||
key={`${suggestion}-${originalIndex}`}
|
<Box flexDirection="row">
|
||||||
color={isActive ? Colors.Background : Colors.Foreground}
|
<Box width={20} flexShrink={0}>
|
||||||
backgroundColor={isActive ? Colors.AccentBlue : undefined}
|
<Text color={textColor}>{suggestion.label}</Text>
|
||||||
>
|
</Box>
|
||||||
{suggestion.label}
|
{suggestion.description ? (
|
||||||
|
<Box flexGrow={1}>
|
||||||
|
<Text color={textColor} wrap="wrap">
|
||||||
|
{suggestion.description}
|
||||||
</Text>
|
</Text>
|
||||||
|
</Box>
|
||||||
|
) : null}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{endIndex < suggestions.length && <Text color="gray">▼</Text>}
|
{endIndex < suggestions.length && <Text color="gray">▼</Text>}
|
||||||
|
|
|
@ -94,7 +94,7 @@ export const useSlashCommandProcessor = (
|
||||||
{
|
{
|
||||||
name: 'quit',
|
name: 'quit',
|
||||||
altName: 'exit',
|
altName: 'exit',
|
||||||
description: '',
|
description: 'exit the cli',
|
||||||
action: (_value: PartListUnion | string) => {
|
action: (_value: PartListUnion | string) => {
|
||||||
onDebugMessage('Quitting. Good-bye.');
|
onDebugMessage('Quitting. Good-bye.');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
|
|
@ -119,20 +119,30 @@ export function useCompletion(
|
||||||
// --- Handle Slash Command Completion ---
|
// --- Handle Slash Command Completion ---
|
||||||
if (trimmedQuery.startsWith('/')) {
|
if (trimmedQuery.startsWith('/')) {
|
||||||
const partialCommand = trimmedQuery.substring(1);
|
const partialCommand = trimmedQuery.substring(1);
|
||||||
const commands = slashCommands
|
const filteredSuggestions = slashCommands
|
||||||
.map((cmd) => cmd.name)
|
.filter(
|
||||||
.concat(
|
(cmd) =>
|
||||||
slashCommands
|
cmd.name.startsWith(partialCommand) ||
|
||||||
.map((cmd) => cmd.altName)
|
cmd.altName?.startsWith(partialCommand),
|
||||||
.filter((cmd) => cmd !== undefined),
|
)
|
||||||
|
// Filter out ? and any other single character commands unless it's the only char
|
||||||
|
.filter((cmd) => {
|
||||||
|
const nameMatch = cmd.name.startsWith(partialCommand);
|
||||||
|
const altNameMatch = cmd.altName?.startsWith(partialCommand);
|
||||||
|
if (partialCommand.length === 1) {
|
||||||
|
return nameMatch || altNameMatch; // Allow single char match if query is single char
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
(nameMatch && cmd.name.length > 1) ||
|
||||||
|
(altNameMatch && cmd.altName && cmd.altName.length > 1)
|
||||||
);
|
);
|
||||||
|
})
|
||||||
const filteredSuggestions = commands
|
.map((cmd) => ({
|
||||||
.filter((name) => name.startsWith(partialCommand))
|
label: cmd.name, // Always show the main name as label
|
||||||
// Filter out ? and any other single character commands
|
value: cmd.name, // Value should be the main command name for execution
|
||||||
.filter((name) => name.length > 1)
|
description: cmd.description,
|
||||||
.map((name) => ({ label: name, value: name }))
|
}))
|
||||||
.sort();
|
.sort((a, b) => a.label.localeCompare(b.label));
|
||||||
|
|
||||||
setSuggestions(filteredSuggestions);
|
setSuggestions(filteredSuggestions);
|
||||||
setShowSuggestions(filteredSuggestions.length > 0);
|
setShowSuggestions(filteredSuggestions.length > 0);
|
||||||
|
|
Loading…
Reference in New Issue