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