Files
website/src/lib/terminal/completion.ts
T

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() };
}