scripts/completions.d.ts
Karolis2011 df5df0ea92 Add remote script loader with intelligent completions
Features:
- Remote script execution with version control (name@ref)
- Background daemon for fast completions (< 15ms)
- HTTP caching with ETag/Last-Modified support
- Context-aware completions with async support
- Comprehensive documentation and type definitions

Changes:
- Add loader.ts with daemon mode
- Add completions.d.ts type definitions
- Add COMPLETIONS.md guide for developers
- Add README.md with usage examples
- Update configure_ssh_key.ts with async completions
- Use JSR imports for remote execution compatibility
2025-11-29 23:22:35 +02:00

149 lines
4.4 KiB
TypeScript

/**
* 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 <TAB>`
* 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<string[]>).
*
* @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<string[]> {
* 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<string[]>;