/** * Type definitions for script completion functions * * Scripts can export a `getCompletions` function to provide intelligent * shell completion suggestions for their arguments. * * @example * ```typescript * export function getCompletions(ctx: CompletionContext): string[] { * const { current, args } = ctx; * * // Suggest values for --key flag * if (current.startsWith("--key=")) { * return ["--key=~/.ssh/id_rsa", "--key=~/.ssh/id_ed25519"]; * } * * // Check what's already provided * const hasForce = args.includes("--force"); * * // Return available flags * return ["--force", "--dry-run", "--help"].filter( * flag => flag !== "--force" || !hasForce * ); * } * ``` */ /** * Context provided to the completion function */ export interface CompletionContext { /** * All arguments provided so far (excluding the script name) * * @example * If user typed: `scripts my-script --flag1 value1 --flag2` * Then args would be: ["--flag1", "value1", "--flag2"] */ args: string[]; /** * The current word being completed * * @example * - User typed `--k` and pressed TAB → current = "--k" * - User typed `--key=` and pressed TAB → current = "--key=" * - User typed `--port=22` and pressed TAB → current = "--port=22" */ current: string; /** * Position of the current word in the args array (0-indexed) * * @example * If user typed: `scripts my-script arg1 arg2 ` * Then position would be 2 (0=arg1, 1=arg2, 2=current) */ position: number; } /** * Completion function that scripts should export * * This function is called by the loader daemon when the user requests * shell completions. It should return an array of completion suggestions * based on the provided context. * * Can be synchronous or asynchronous (return Promise). * * @param ctx - Completion context with current state * @returns Array of completion suggestions (can be empty), or Promise resolving to array * * @remarks * - Return empty array if no completions are available * - Suggestions are filtered by the shell, so return all matches * - Can include partial matches (e.g., "--key=" to prompt for value) * - Keep execution fast (< 50ms recommended) for responsive UX * - Use Deno APIs to discover filesystem, environment, etc. * - Async functions enable API calls, but keep them fast * * @example Simple flag completions * ```typescript * export function getCompletions(ctx: CompletionContext): string[] { * return ["--verbose", "--quiet", "--help"]; * } * ``` * * @example Async completions with API call * ```typescript * export async function getCompletions(ctx: CompletionContext): Promise { * const { current } = ctx; * * if (current.startsWith("--branch=")) { * try { * const response = await fetch("https://api.github.com/repos/user/repo/branches"); * const branches = await response.json(); * return branches.map(b => `--branch=${b.name}`); * } catch { * return ["--branch=main"]; * } * } * * return ["--branch=", "--help"]; * } * ``` * * @example Context-aware completions * ```typescript * export function getCompletions(ctx: CompletionContext): string[] { * const { current, args } = ctx; * * // Complete values for flags * if (current.startsWith("--output=")) { * return ["--output=json", "--output=yaml", "--output=text"]; * } * * // Avoid duplicate flags * const usedFlags = new Set(args.map(a => a.split("=")[0])); * * const allFlags = ["--output=", "--verbose", "--format="]; * return allFlags.filter(f => !usedFlags.has(f.replace("=", ""))); * } * ``` * * @example Dynamic completions with filesystem * ```typescript * export function getCompletions(ctx: CompletionContext): string[] { * const { current } = ctx; * * if (current.startsWith("--config=")) { * try { * // Find config files in current directory * const files: string[] = []; * for (const entry of Deno.readDirSync(".")) { * if (entry.isFile && entry.name.endsWith(".json")) { * files.push(`--config=${entry.name}`); * } * } * return files; * } catch { * return ["--config=config.json"]; * } * } * * return ["--config=", "--help"]; * } * ``` */ export type CompletionFunction = (ctx: CompletionContext) => string[] | Promise;