Add autocomplete for slash commands
This commit is contained in:
parent
f237082c37
commit
cc838fad44
|
@ -26,7 +26,7 @@ import { ConsoleOutput } from './components/ConsolePatcher.js';
|
||||||
import { HistoryItemDisplay } from './components/HistoryItemDisplay.js';
|
import { HistoryItemDisplay } from './components/HistoryItemDisplay.js';
|
||||||
import { useCompletion } from './hooks/useCompletion.js';
|
import { useCompletion } from './hooks/useCompletion.js';
|
||||||
import { SuggestionsDisplay } from './components/SuggestionsDisplay.js';
|
import { SuggestionsDisplay } from './components/SuggestionsDisplay.js';
|
||||||
import { isAtCommand } from './utils/commandUtils.js';
|
import { isAtCommand, isSlashCommand } from './utils/commandUtils.js';
|
||||||
|
|
||||||
interface AppProps {
|
interface AppProps {
|
||||||
config: Config;
|
config: Config;
|
||||||
|
@ -96,7 +96,8 @@ export const App = ({ config, settings, cliVersion }: AppProps) => {
|
||||||
const completion = useCompletion(
|
const completion = useCompletion(
|
||||||
query,
|
query,
|
||||||
config.getTargetDir(),
|
config.getTargetDir(),
|
||||||
isInputActive && isAtCommand(query),
|
isInputActive && (isAtCommand(query) || isSlashCommand(query)),
|
||||||
|
slashCommands,
|
||||||
);
|
);
|
||||||
|
|
||||||
// --- Render Logic ---
|
// --- Render Logic ---
|
||||||
|
|
|
@ -47,6 +47,16 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const selectedSuggestion = suggestions[activeSuggestionIndex];
|
const selectedSuggestion = suggestions[activeSuggestionIndex];
|
||||||
|
const trimmedQuery = query.trimStart();
|
||||||
|
|
||||||
|
if (trimmedQuery.startsWith('/')) {
|
||||||
|
// Handle / command completion
|
||||||
|
const slashIndex = query.indexOf('/');
|
||||||
|
const base = query.substring(0, slashIndex + 1);
|
||||||
|
const newValue = base + selectedSuggestion.value;
|
||||||
|
setQuery(newValue);
|
||||||
|
} else {
|
||||||
|
// Handle @ command completion
|
||||||
const atIndex = query.lastIndexOf('@');
|
const atIndex = query.lastIndexOf('@');
|
||||||
if (atIndex === -1) return;
|
if (atIndex === -1) return;
|
||||||
|
|
||||||
|
@ -66,6 +76,8 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||||
|
|
||||||
const newValue = base + selectedSuggestion.value;
|
const newValue = base + selectedSuggestion.value;
|
||||||
setQuery(newValue);
|
setQuery(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
resetCompletion(); // Hide suggestions after selection
|
resetCompletion(); // Hide suggestions after selection
|
||||||
setInputKey((k) => k + 1); // Increment key to force re-render and cursor reset
|
setInputKey((k) => k + 1); // Increment key to force re-render and cursor reset
|
||||||
}, [
|
}, [
|
||||||
|
|
|
@ -12,6 +12,8 @@ import {
|
||||||
MAX_SUGGESTIONS_TO_SHOW,
|
MAX_SUGGESTIONS_TO_SHOW,
|
||||||
Suggestion,
|
Suggestion,
|
||||||
} from '../components/SuggestionsDisplay.js';
|
} from '../components/SuggestionsDisplay.js';
|
||||||
|
import { SlashCommand } from './slashCommandProcessor.js';
|
||||||
|
|
||||||
export interface UseCompletionReturn {
|
export interface UseCompletionReturn {
|
||||||
suggestions: Suggestion[];
|
suggestions: Suggestion[];
|
||||||
activeSuggestionIndex: number;
|
activeSuggestionIndex: number;
|
||||||
|
@ -29,6 +31,7 @@ export function useCompletion(
|
||||||
query: string,
|
query: string,
|
||||||
cwd: string,
|
cwd: string,
|
||||||
isActive: boolean,
|
isActive: boolean,
|
||||||
|
slashCommands: SlashCommand[],
|
||||||
): UseCompletionReturn {
|
): UseCompletionReturn {
|
||||||
const [suggestions, setSuggestions] = useState<Suggestion[]>([]);
|
const [suggestions, setSuggestions] = useState<Suggestion[]>([]);
|
||||||
const [activeSuggestionIndex, setActiveSuggestionIndex] =
|
const [activeSuggestionIndex, setActiveSuggestionIndex] =
|
||||||
|
@ -111,6 +114,26 @@ export function useCompletion(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const trimmedQuery = query.trimStart(); // Trim leading whitespace
|
||||||
|
|
||||||
|
// --- Handle Slash Command Completion ---
|
||||||
|
if (trimmedQuery.startsWith('/')) {
|
||||||
|
const partialCommand = trimmedQuery.substring(1);
|
||||||
|
const filteredSuggestions = slashCommands
|
||||||
|
.map((cmd) => cmd.name)
|
||||||
|
.filter((name) => name.startsWith(partialCommand))
|
||||||
|
.map((name) => ({ label: name, value: name }))
|
||||||
|
.sort();
|
||||||
|
|
||||||
|
setSuggestions(filteredSuggestions);
|
||||||
|
setShowSuggestions(filteredSuggestions.length > 0);
|
||||||
|
setActiveSuggestionIndex(-1);
|
||||||
|
setVisibleStartIndex(0);
|
||||||
|
setIsLoadingSuggestions(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Handle At Command Completion ---
|
||||||
const atIndex = query.lastIndexOf('@');
|
const atIndex = query.lastIndexOf('@');
|
||||||
if (atIndex === -1) {
|
if (atIndex === -1) {
|
||||||
resetCompletionState();
|
resetCompletionState();
|
||||||
|
|
|
@ -16,6 +16,15 @@ export const isAtCommand = (query: string): boolean =>
|
||||||
// Check if starts with @ OR has a space, then @, then a non-space character.
|
// Check if starts with @ OR has a space, then @, then a non-space character.
|
||||||
query.startsWith('@') || /\s@\S/.test(query);
|
query.startsWith('@') || /\s@\S/.test(query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a query string potentially represents an '/' command.
|
||||||
|
* It triggers if the query starts with '/'
|
||||||
|
*
|
||||||
|
* @param query The input query string.
|
||||||
|
* @returns True if the query looks like an '/' command, false otherwise.
|
||||||
|
*/
|
||||||
|
export const isSlashCommand = (query: string): boolean => query.startsWith('/');
|
||||||
|
|
||||||
const control_symbols: string[] = ['/', '@', '!', '?', '$'];
|
const control_symbols: string[] = ['/', '@', '!', '?', '$'];
|
||||||
/**
|
/**
|
||||||
* Returns the first word of query with optional leading slash, ampersand, bang.
|
* Returns the first word of query with optional leading slash, ampersand, bang.
|
||||||
|
|
Loading…
Reference in New Issue