From a083c4a12ee69e0e61bfcbce310032404a9e7c87 Mon Sep 17 00:00:00 2001 From: Marcus Hultman Date: Sat, 3 Jul 2021 10:57:41 -0400 Subject: [PATCH 1/3] add token argument to ICompleteHandler Sometimes you want to provide completion alternatives based on the commandline buffer. This adds `token` (string) to both option- and argument completion, containing the partially written word to complete. --- command/command.ts | 3 ++- .../completions/_fish_completions_generator.ts | 18 +++++++++++++++--- command/completions/complete.ts | 7 ++++--- command/type.ts | 1 + command/types.ts | 2 +- command/types/child_command.ts | 2 +- command/types/command.ts | 2 +- 7 files changed, 25 insertions(+), 10 deletions(-) diff --git a/command/command.ts b/command/command.ts index cca6cd61..1a6c5089 100644 --- a/command/command.ts +++ b/command/command.ts @@ -587,9 +587,10 @@ export class Command< typeof handler.values !== "undefined") ) { const completeHandler: ICompleteHandler = ( + token: string, cmd: Command, parent?: Command, - ) => handler.complete?.(cmd, parent) || []; + ) => handler.complete?.(token, cmd, parent) || []; this.complete(name, completeHandler, options); } diff --git a/command/completions/_fish_completions_generator.ts b/command/completions/_fish_completions_generator.ts index 9ae9fe6a..7af43af6 100644 --- a/command/completions/_fish_completions_generator.ts +++ b/command/completions/_fish_completions_generator.ts @@ -108,8 +108,10 @@ ${this.generateCompletions(this.cmd).trim()} required: true, standalone: option.standalone, arguments: option.args.length - ? this.getCompletionCommand( + ? this.getOptionCompletionCommand( option.args[0].action + " " + getCompletionsPath(command), + shortOption, + longOption ) : undefined, }); @@ -137,8 +139,18 @@ ${this.generateCompletions(this.cmd).trim()} return cmd.join(" "); } - private getCompletionCommand(cmd: string): string { - return `'(${this.cmd.getName()} completions complete ${cmd.trim()})'`; + private getOptionCompletionCommand(cmd: string, shortOption: string | undefined, longOption: string | undefined): string { + const makeFilter = (s: string) => `string replace -- ${s} ""`; + const filters = []; + shortOption && filters.push(makeFilter(`-${shortOption}`)); + longOption && filters.push(makeFilter(`--${longOption}`)); + return this.getCompletionCommand(cmd, filters); + } + + private getCompletionCommand(cmd: string, filters: string[] = []): string { + const cmds = ['commandline -tc', ...filters, `string replace -r -- "^\-*" ""`]; + const token = cmds.join(' | '); + return `'(${this.cmd.getName()} completions complete -t (${token}) ${cmd.trim()})'`; } } diff --git a/command/completions/complete.ts b/command/completions/complete.ts index 5c54f94e..b995ffed 100644 --- a/command/completions/complete.ts +++ b/command/completions/complete.ts @@ -4,12 +4,13 @@ import type { ICompletion } from "../types.ts"; /** Execute auto completion method of command and action. */ export class CompleteCommand - extends Command]> { + extends Command<{ token: string }, [action: string, commandNames?: Array]> { public constructor(cmd?: Command) { super(); this.description("Get completions for given action from given command.") + .option("-t, --token [t:string]", "the current cmd token.") .arguments(" [command...:string]") - .action(async (_, action: string, commandNames?: Array) => { + .action(async ({ token = '' }, action: string, commandNames?: Array) => { let parent: Command | undefined; const completeCommand: Command = commandNames ?.reduce((cmd: Command, name: string): Command => { @@ -24,7 +25,7 @@ export class CompleteCommand const completion: ICompletion | undefined = completeCommand .getCompletion(action); const result: Array = - await completion?.complete(completeCommand, parent) ?? []; + await completion?.complete(token, completeCommand, parent) ?? []; if (result?.length) { Deno.stdout.writeSync(new TextEncoder().encode(result.join("\n"))); diff --git a/command/type.ts b/command/type.ts index 77c8433e..8e7457d2 100644 --- a/command/type.ts +++ b/command/type.ts @@ -46,6 +46,7 @@ export abstract class Type { * values from the values method are used. */ public complete?( + token: string, // deno-lint-ignore no-explicit-any cmd: Command, // deno-lint-ignore no-explicit-any diff --git a/command/types.ts b/command/types.ts index 57010b1f..c0a8f30e 100644 --- a/command/types.ts +++ b/command/types.ts @@ -208,7 +208,7 @@ export type ICompleteHandler< PG extends Record | void = any, // deno-lint-ignore no-explicit-any P extends Command | undefined = any, -> = (cmd: Command, parent?: Command) => CompleteHandlerResult; +> = (token: string, cmd: Command, parent?: Command) => CompleteHandlerResult; /** Help callback method to print the help. Invoked by the `--help` option and `help` command and the `.getHelp()` and `.showHelp()` method's. */ export type IHelpHandler< diff --git a/command/types/child_command.ts b/command/types/child_command.ts index 542e841f..1d148748 100644 --- a/command/types/child_command.ts +++ b/command/types/child_command.ts @@ -11,7 +11,7 @@ export class ChildCommandType extends StringType { } /** Complete child command names. */ - public complete(cmd: Command): string[] { + public complete(_token: string, cmd: Command): string[] { return (this.#cmd ?? cmd)?.getCommands(false) .map((cmd: Command) => cmd.getName()) || []; } diff --git a/command/types/command.ts b/command/types/command.ts index 4722782b..3df78ee8 100644 --- a/command/types/command.ts +++ b/command/types/command.ts @@ -4,7 +4,7 @@ import { StringType } from "./string.ts"; /** String type with auto completion of sibling command names. */ export class CommandType extends StringType { /** Complete sub-command names of global parent command. */ - public complete(_cmd: Command, parent?: Command): string[] { + public complete(_token: string, _cmd: Command, parent?: Command): string[] { return parent?.getCommands(false) .map((cmd: Command) => cmd.getName()) || []; } From c65f3280dd992ae6bd0377df4b43a3c16d3d0016 Mon Sep 17 00:00:00 2001 From: Marcus Hultman Date: Sat, 3 Jul 2021 11:04:29 -0400 Subject: [PATCH 2/3] deno fmt --- .../_fish_completions_generator.ts | 16 ++++-- command/completions/complete.ts | 50 +++++++++++-------- command/types.ts | 6 ++- 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/command/completions/_fish_completions_generator.ts b/command/completions/_fish_completions_generator.ts index 7af43af6..dfa831a7 100644 --- a/command/completions/_fish_completions_generator.ts +++ b/command/completions/_fish_completions_generator.ts @@ -111,7 +111,7 @@ ${this.generateCompletions(this.cmd).trim()} ? this.getOptionCompletionCommand( option.args[0].action + " " + getCompletionsPath(command), shortOption, - longOption + longOption, ) : undefined, }); @@ -139,7 +139,11 @@ ${this.generateCompletions(this.cmd).trim()} return cmd.join(" "); } - private getOptionCompletionCommand(cmd: string, shortOption: string | undefined, longOption: string | undefined): string { + private getOptionCompletionCommand( + cmd: string, + shortOption: string | undefined, + longOption: string | undefined, + ): string { const makeFilter = (s: string) => `string replace -- ${s} ""`; const filters = []; shortOption && filters.push(makeFilter(`-${shortOption}`)); @@ -148,8 +152,12 @@ ${this.generateCompletions(this.cmd).trim()} } private getCompletionCommand(cmd: string, filters: string[] = []): string { - const cmds = ['commandline -tc', ...filters, `string replace -r -- "^\-*" ""`]; - const token = cmds.join(' | '); + const cmds = [ + "commandline -tc", + ...filters, + `string replace -r -- "^\-*" ""`, + ]; + const token = cmds.join(" | "); return `'(${this.cmd.getName()} completions complete -t (${token}) ${cmd.trim()})'`; } } diff --git a/command/completions/complete.ts b/command/completions/complete.ts index b995ffed..b231b386 100644 --- a/command/completions/complete.ts +++ b/command/completions/complete.ts @@ -3,34 +3,42 @@ import { UnknownCompletionCommand } from "../_errors.ts"; import type { ICompletion } from "../types.ts"; /** Execute auto completion method of command and action. */ -export class CompleteCommand - extends Command<{ token: string }, [action: string, commandNames?: Array]> { +export class CompleteCommand extends Command< + { token: string }, + [action: string, commandNames?: Array] +> { public constructor(cmd?: Command) { super(); this.description("Get completions for given action from given command.") .option("-t, --token [t:string]", "the current cmd token.") .arguments(" [command...:string]") - .action(async ({ token = '' }, action: string, commandNames?: Array) => { - let parent: Command | undefined; - const completeCommand: Command = commandNames - ?.reduce((cmd: Command, name: string): Command => { - parent = cmd; - const childCmd: Command | undefined = cmd.getCommand(name, false); - if (!childCmd) { - throw new UnknownCompletionCommand(name, cmd.getCommands()); - } - return childCmd; - }, cmd || this.getMainCommand()) ?? (cmd || this.getMainCommand()); + .action( + async ( + { token = "" }, + action: string, + commandNames?: Array, + ) => { + let parent: Command | undefined; + const completeCommand: Command = commandNames + ?.reduce((cmd: Command, name: string): Command => { + parent = cmd; + const childCmd: Command | undefined = cmd.getCommand(name, false); + if (!childCmd) { + throw new UnknownCompletionCommand(name, cmd.getCommands()); + } + return childCmd; + }, cmd || this.getMainCommand()) ?? (cmd || this.getMainCommand()); - const completion: ICompletion | undefined = completeCommand - .getCompletion(action); - const result: Array = - await completion?.complete(token, completeCommand, parent) ?? []; + const completion: ICompletion | undefined = completeCommand + .getCompletion(action); + const result: Array = + await completion?.complete(token, completeCommand, parent) ?? []; - if (result?.length) { - Deno.stdout.writeSync(new TextEncoder().encode(result.join("\n"))); - } - }) + if (result?.length) { + Deno.stdout.writeSync(new TextEncoder().encode(result.join("\n"))); + } + }, + ) .reset(); } } diff --git a/command/types.ts b/command/types.ts index c0a8f30e..d46de1de 100644 --- a/command/types.ts +++ b/command/types.ts @@ -208,7 +208,11 @@ export type ICompleteHandler< PG extends Record | void = any, // deno-lint-ignore no-explicit-any P extends Command | undefined = any, -> = (token: string, cmd: Command, parent?: Command) => CompleteHandlerResult; +> = ( + token: string, + cmd: Command, + parent?: Command, +) => CompleteHandlerResult; /** Help callback method to print the help. Invoked by the `--help` option and `help` command and the `.getHelp()` and `.showHelp()` method's. */ export type IHelpHandler< From 280ceca8e429498efd60c64495982cd30c862bee Mon Sep 17 00:00:00 2001 From: Marcus Hultman Date: Sat, 3 Jul 2021 11:16:20 -0400 Subject: [PATCH 3/3] regenerate completions_generate_fish.out --- .../fixtures/completions_generate_fish.out | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/command/test/integration/fixtures/completions_generate_fish.out b/command/test/integration/fixtures/completions_generate_fish.out index cfde4a7e..7c7097df 100644 --- a/command/test/integration/fixtures/completions_generate_fish.out +++ b/command/test/integration/fixtures/completions_generate_fish.out @@ -25,54 +25,54 @@ end complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -s h -l help -x -k -f -d 'Show this help.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -s V -l version -x -k -f -d 'Show the version number for this program.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -s g -l global -k -f -r -a '(completions-test completions complete boolean)' -d 'Foo option.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -s m -l main -k -f -r -a '(completions-test completions complete boolean)' -d 'Bar option.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -s c -l color -k -f -r -a '(completions-test completions complete color)' -d 'Color option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -s m -l main -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -m "" | string replace -- --main "" | string replace -r -- "^-*" "") boolean)' -d 'Bar option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -s c -l color -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -c "" | string replace -- --color "" | string replace -r -- "^-*" "") color)' -d 'Color option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -k -f -a foo -d 'Foo command.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_foo' -s h -l help -x -k -f -d 'Show this help.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_foo' -s g -l global -k -f -r -a '(completions-test completions complete boolean foo)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_foo' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean foo)' -d 'Foo option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_foo' -s f -l foo -k -f -d 'Foo option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -k -f -a help -d 'Show this help or the help of a sub-command.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete command help)' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete -t (commandline -tc | string replace -r -- "^-*" "") command help)' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s h -l help -x -k -f -d 'Show this help.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete boolean help)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean help)' -d 'Foo option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_foo' -k -f -a bar -d 'Bar command.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_foo_bar' -s h -l help -x -k -f -d 'Show this help.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_foo_bar' -s g -l global -k -f -r -a '(completions-test completions complete boolean foo bar)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_foo_bar' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean foo bar)' -d 'Foo option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_foo_bar' -s b -l bar -k -f -d 'Bar option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -k -f -a help -d 'Show this help or the help of a sub-command.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete command help)' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete -t (commandline -tc | string replace -r -- "^-*" "") command help)' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s h -l help -x -k -f -d 'Show this help.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete boolean help)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean help)' -d 'Foo option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -k -f -a help -d 'Show this help or the help of a sub-command.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete command help)' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete -t (commandline -tc | string replace -r -- "^-*" "") command help)' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s h -l help -x -k -f -d 'Show this help.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete boolean help)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean help)' -d 'Foo option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -k -f -a completions -d 'Generate shell completions.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions' -s h -l help -x -k -f -d 'Show this help.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions' -s g -l global -k -f -r -a '(completions-test completions complete boolean completions)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean completions)' -d 'Foo option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -k -f -a help -d 'Show this help or the help of a sub-command.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete command help)' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete -t (commandline -tc | string replace -r -- "^-*" "") command help)' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s h -l help -x -k -f -d 'Show this help.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete boolean help)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean help)' -d 'Foo option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions' -k -f -a bash -d 'Generate shell completions for bash.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions_bash' -s h -l help -x -k -f -d 'Show this help.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions_bash' -s g -l global -k -f -r -a '(completions-test completions complete boolean completions bash)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions_bash' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean completions bash)' -d 'Foo option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -k -f -a help -d 'Show this help or the help of a sub-command.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete command help)' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete -t (commandline -tc | string replace -r -- "^-*" "") command help)' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s h -l help -x -k -f -d 'Show this help.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete boolean help)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean help)' -d 'Foo option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions' -k -f -a fish -d 'Generate shell completions for fish.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions_fish' -s h -l help -x -k -f -d 'Show this help.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions_fish' -s g -l global -k -f -r -a '(completions-test completions complete boolean completions fish)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions_fish' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean completions fish)' -d 'Foo option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -k -f -a help -d 'Show this help or the help of a sub-command.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete command help)' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete -t (commandline -tc | string replace -r -- "^-*" "") command help)' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s h -l help -x -k -f -d 'Show this help.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete boolean help)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean help)' -d 'Foo option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions' -k -f -a zsh -d 'Generate shell completions for zsh.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions_zsh' -s h -l help -x -k -f -d 'Show this help.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions_zsh' -s g -l global -k -f -r -a '(completions-test completions complete boolean completions zsh)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_completions_zsh' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean completions zsh)' -d 'Foo option.' complete -c completions-test -n '__fish_completions_test_using_command __completions_test' -k -f -a help -d 'Show this help or the help of a sub-command.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete command help)' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -k -f -a '(completions-test completions complete -t (commandline -tc | string replace -r -- "^-*" "") command help)' complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s h -l help -x -k -f -d 'Show this help.' -complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete boolean help)' -d 'Foo option.' +complete -c completions-test -n '__fish_completions_test_using_command __completions_test_help' -s g -l global -k -f -r -a '(completions-test completions complete -t (commandline -tc | string replace -- -g "" | string replace -- --global "" | string replace -r -- "^-*" "") boolean help)' -d 'Foo option.'