feat(cli): prompt completion (#4691)

Co-authored-by: Jacob Richman <jacob314@gmail.com>
This commit is contained in:
官余棚
2025-08-21 16:04:04 +08:00
committed by GitHub
parent ba5309c405
commit 589f5e6823
11 changed files with 540 additions and 43 deletions

View File

@@ -15,6 +15,11 @@ import { isSlashCommand } from '../utils/commandUtils.js';
import { toCodePoints } from '../utils/textUtils.js';
import { useAtCompletion } from './useAtCompletion.js';
import { useSlashCompletion } from './useSlashCompletion.js';
import {
usePromptCompletion,
PromptCompletion,
PROMPT_COMPLETION_MIN_LENGTH,
} from './usePromptCompletion.js';
import { Config } from '@google/gemini-cli-core';
import { useCompletion } from './useCompletion.js';
@@ -22,6 +27,7 @@ export enum CompletionMode {
IDLE = 'IDLE',
AT = 'AT',
SLASH = 'SLASH',
PROMPT = 'PROMPT',
}
export interface UseCommandCompletionReturn {
@@ -37,6 +43,7 @@ export interface UseCommandCompletionReturn {
navigateUp: () => void;
navigateDown: () => void;
handleAutocomplete: (indexToUse: number) => void;
promptCompletion: PromptCompletion;
}
export function useCommandCompletion(
@@ -93,12 +100,7 @@ export function useCommandCompletion(
backslashCount++;
}
if (backslashCount % 2 === 0) {
return {
completionMode: CompletionMode.IDLE,
query: null,
completionStart: -1,
completionEnd: -1,
};
break;
}
} else if (char === '@') {
let end = codePoints.length;
@@ -125,13 +127,33 @@ export function useCommandCompletion(
};
}
}
// Check for prompt completion - only if enabled
const trimmedText = buffer.text.trim();
const isPromptCompletionEnabled =
config?.getEnablePromptCompletion() ?? false;
if (
isPromptCompletionEnabled &&
trimmedText.length >= PROMPT_COMPLETION_MIN_LENGTH &&
!trimmedText.startsWith('/') &&
!trimmedText.includes('@')
) {
return {
completionMode: CompletionMode.PROMPT,
query: trimmedText,
completionStart: 0,
completionEnd: trimmedText.length,
};
}
return {
completionMode: CompletionMode.IDLE,
query: null,
completionStart: -1,
completionEnd: -1,
};
}, [cursorRow, cursorCol, buffer.lines]);
}, [cursorRow, cursorCol, buffer.lines, buffer.text, config]);
useAtCompletion({
enabled: completionMode === CompletionMode.AT,
@@ -152,6 +174,12 @@ export function useCommandCompletion(
setIsPerfectMatch,
});
const promptCompletion = usePromptCompletion({
buffer,
config,
enabled: completionMode === CompletionMode.PROMPT,
});
useEffect(() => {
setActiveSuggestionIndex(suggestions.length > 0 ? 0 : -1);
setVisibleStartIndex(0);
@@ -202,7 +230,11 @@ export function useCommandCompletion(
}
}
suggestionText += ' ';
const lineCodePoints = toCodePoints(buffer.lines[cursorRow] || '');
const charAfterCompletion = lineCodePoints[end];
if (charAfterCompletion !== ' ') {
suggestionText += ' ';
}
buffer.replaceRangeByOffset(
logicalPosToOffset(buffer.lines, cursorRow, start),
@@ -234,5 +266,6 @@ export function useCommandCompletion(
navigateUp,
navigateDown,
handleAutocomplete,
promptCompletion,
};
}