mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-23 11:34:44 -07:00
feat: auto-execute simple slash commands on Enter (#13985)
This commit is contained in:
@@ -42,6 +42,17 @@ export interface UseCommandCompletionReturn {
|
||||
navigateDown: () => void;
|
||||
handleAutocomplete: (indexToUse: number) => void;
|
||||
promptCompletion: PromptCompletion;
|
||||
getCommandFromSuggestion: (
|
||||
suggestion: Suggestion,
|
||||
) => SlashCommand | undefined;
|
||||
slashCompletionRange: {
|
||||
completionStart: number;
|
||||
completionEnd: number;
|
||||
getCommandFromSuggestion: (
|
||||
suggestion: Suggestion,
|
||||
) => SlashCommand | undefined;
|
||||
};
|
||||
getCompletedText: (suggestion: Suggestion) => string | null;
|
||||
}
|
||||
|
||||
export function useCommandCompletion(
|
||||
@@ -200,12 +211,16 @@ export function useCommandCompletion(
|
||||
setShowSuggestions,
|
||||
]);
|
||||
|
||||
const handleAutocomplete = useCallback(
|
||||
(indexToUse: number) => {
|
||||
if (indexToUse < 0 || indexToUse >= suggestions.length) {
|
||||
return;
|
||||
}
|
||||
const suggestion = suggestions[indexToUse].value;
|
||||
/**
|
||||
* Gets the completed text by replacing the completion range with the suggestion value.
|
||||
* This is the core string replacement logic used by both autocomplete and auto-execute.
|
||||
*
|
||||
* @param suggestion The suggestion to apply
|
||||
* @returns The completed text with the suggestion applied, or null if invalid
|
||||
*/
|
||||
const getCompletedText = useCallback(
|
||||
(suggestion: Suggestion): string | null => {
|
||||
const currentLine = buffer.lines[cursorRow] || '';
|
||||
|
||||
let start = completionStart;
|
||||
let end = completionEnd;
|
||||
@@ -215,10 +230,56 @@ export function useCommandCompletion(
|
||||
}
|
||||
|
||||
if (start === -1 || end === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Apply space padding for slash commands (needed for subcommands like "/chat list")
|
||||
let suggestionText = suggestion.value;
|
||||
if (completionMode === CompletionMode.SLASH) {
|
||||
// Add leading space if completing a subcommand (cursor is after parent command with no space)
|
||||
if (start === end && start > 1 && currentLine[start - 1] !== ' ') {
|
||||
suggestionText = ' ' + suggestionText;
|
||||
}
|
||||
}
|
||||
|
||||
// Build the completed text with proper spacing
|
||||
return (
|
||||
currentLine.substring(0, start) +
|
||||
suggestionText +
|
||||
currentLine.substring(end)
|
||||
);
|
||||
},
|
||||
[
|
||||
cursorRow,
|
||||
buffer.lines,
|
||||
completionMode,
|
||||
completionStart,
|
||||
completionEnd,
|
||||
slashCompletionRange,
|
||||
],
|
||||
);
|
||||
|
||||
const handleAutocomplete = useCallback(
|
||||
(indexToUse: number) => {
|
||||
if (indexToUse < 0 || indexToUse >= suggestions.length) {
|
||||
return;
|
||||
}
|
||||
const suggestion = suggestions[indexToUse];
|
||||
const completedText = getCompletedText(suggestion);
|
||||
|
||||
if (completedText === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
let suggestionText = suggestion;
|
||||
let start = completionStart;
|
||||
let end = completionEnd;
|
||||
if (completionMode === CompletionMode.SLASH) {
|
||||
start = slashCompletionRange.completionStart;
|
||||
end = slashCompletionRange.completionEnd;
|
||||
}
|
||||
|
||||
// Add space padding for Tab completion (auto-execute gets padding from getCompletedText)
|
||||
let suggestionText = suggestion.value;
|
||||
if (completionMode === CompletionMode.SLASH) {
|
||||
if (
|
||||
start === end &&
|
||||
@@ -253,6 +314,7 @@ export function useCommandCompletion(
|
||||
completionStart,
|
||||
completionEnd,
|
||||
slashCompletionRange,
|
||||
getCompletedText,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -270,5 +332,8 @@ export function useCommandCompletion(
|
||||
navigateDown,
|
||||
handleAutocomplete,
|
||||
promptCompletion,
|
||||
getCommandFromSuggestion: slashCompletionRange.getCommandFromSuggestion,
|
||||
slashCompletionRange,
|
||||
getCompletedText,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -376,6 +376,32 @@ function usePerfectMatch(
|
||||
}, [parserResult]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SlashCommand object for a given suggestion by navigating the command hierarchy
|
||||
* based on the current parser state.
|
||||
* @param suggestion The suggestion object
|
||||
* @param parserResult The current parser result with hierarchy information
|
||||
* @returns The matching SlashCommand or undefined
|
||||
*/
|
||||
function getCommandFromSuggestion(
|
||||
suggestion: Suggestion,
|
||||
parserResult: CommandParserResult,
|
||||
): SlashCommand | undefined {
|
||||
const { currentLevel } = parserResult;
|
||||
|
||||
if (!currentLevel) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// suggestion.value is just the command name at the current level (e.g., "list")
|
||||
// Find it in the current level's commands
|
||||
const command = currentLevel.find((cmd) =>
|
||||
matchesCommand(cmd, suggestion.value),
|
||||
);
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
export interface UseSlashCompletionProps {
|
||||
enabled: boolean;
|
||||
query: string | null;
|
||||
@@ -389,6 +415,9 @@ export interface UseSlashCompletionProps {
|
||||
export function useSlashCompletion(props: UseSlashCompletionProps): {
|
||||
completionStart: number;
|
||||
completionEnd: number;
|
||||
getCommandFromSuggestion: (
|
||||
suggestion: Suggestion,
|
||||
) => SlashCommand | undefined;
|
||||
} {
|
||||
const {
|
||||
enabled,
|
||||
@@ -536,5 +565,7 @@ export function useSlashCompletion(props: UseSlashCompletionProps): {
|
||||
return {
|
||||
completionStart,
|
||||
completionEnd,
|
||||
getCommandFromSuggestion: (suggestion: Suggestion) =>
|
||||
getCommandFromSuggestion(suggestion, parserResult),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user