38 lines
1.2 KiB
TypeScript
38 lines
1.2 KiB
TypeScript
import { findCommand, visibleCommandNames } from './commands';
|
|
|
|
export interface CompletionResult {
|
|
input: string;
|
|
options: string[];
|
|
}
|
|
|
|
function sharedPrefix(words: string[]): string {
|
|
return words.reduce((prefix, word) => {
|
|
let length = 0;
|
|
while (length < prefix.length && prefix[length] === word[length]) length++;
|
|
return prefix.slice(0, length);
|
|
});
|
|
}
|
|
|
|
function candidatesFor(words: string[]): string[] {
|
|
if (words.length <= 1) return visibleCommandNames();
|
|
if (words.length > 2) return [];
|
|
return findCommand(words[0])?.argumentOptions?.() ?? [];
|
|
}
|
|
|
|
export function complete(input: string): CompletionResult {
|
|
const words = input.trimStart().split(/\s+/);
|
|
const partial = words.at(-1) ?? '';
|
|
const matches = [...new Set(candidatesFor(words))].filter((candidate) =>
|
|
candidate.toLowerCase().startsWith(partial.toLowerCase())
|
|
);
|
|
|
|
if (matches.length === 0) return { input, options: [] };
|
|
|
|
const before = input.slice(0, input.length - partial.length);
|
|
if (matches.length === 1) return { input: `${before}${matches[0]} `, options: [] };
|
|
|
|
const prefix = sharedPrefix(matches);
|
|
const madeProgress = prefix.length > partial.length;
|
|
return { input: `${before}${madeProgress ? prefix : partial}`, options: madeProgress ? [] : matches.sort() };
|
|
}
|