From 7640bef0eb856d050706a55148bedd7529b8b5b6 Mon Sep 17 00:00:00 2001 From: Antoine Eiche Date: Thu, 21 Jul 2016 21:01:59 +0200 Subject: [PATCH 1/4] Add --init-completion flag to print completion code This flag takes as input 'bash' or 'zsh' and generates the completion code for the specified shell. --- app.go | 6 ++++++ flag.go | 6 ++++++ help.go | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/app.go b/app.go index 290d3bb..6087d9e 100644 --- a/app.go +++ b/app.go @@ -138,6 +138,7 @@ func (a *App) Setup() { if a.EnableBashCompletion { a.appendFlag(BashCompletionFlag) + a.appendFlag(InitCompletionFlag) } if !a.HideVersion { @@ -176,6 +177,11 @@ func (a *App) Run(arguments []string) (err error) { return nil } + var done bool + if done, err = checkInitCompletion(context); done { + return nil + } + if err != nil { if a.OnUsageError != nil { err := a.OnUsageError(context, err, false) diff --git a/flag.go b/flag.go index 807c95f..ee7629e 100644 --- a/flag.go +++ b/flag.go @@ -27,6 +27,12 @@ var BashCompletionFlag = &BoolFlag{ Hidden: true, } +// InitCompletionFlag generates completion code +var InitCompletionFlag = &StringFlag{ + Name: "init-completion", + Usage: "generate completion code. Value must be 'bash' or 'zsh'", +} + // VersionFlag prints the version for the application var VersionFlag = &BoolFlag{ Name: "version", diff --git a/help.go b/help.go index 1dca46f..9a4c334 100644 --- a/help.go +++ b/help.go @@ -286,3 +286,41 @@ func checkCommandCompletions(c *Context, name string) bool { return false } + +func checkInitCompletion(c *Context) (bool, error) { + if c.IsSet(InitCompletionFlag.Name) { + shell := c.String(InitCompletionFlag.Name) + progName := os.Args[0] + switch shell { + case "bash": + fmt.Print(bashCompletionCode(progName)) + return true, nil + case "zsh": + fmt.Print(zshCompletionCode(progName)) + return true, nil + default: + return false, fmt.Errorf("--init-completion value cannot be '%s'", shell) + } + } + return false, nil +} + +func bashCompletionCode(progName string) string { + var template = `_cli_bash_autocomplete() { + local cur opts base; + COMPREPLY=(); + cur="${COMP_WORDS[COMP_CWORD]}"; + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion ); + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ); + return 0; +}; +complete -F _cli_bash_autocomplete %s` + return fmt.Sprintf(template, progName) +} + +func zshCompletionCode(progName string) string { + var template = `autoload -U compinit && compinit; +autoload -U bashcompinit && bashcompinit;` + + return template + "\n" + bashCompletionCode(progName) +} From 34a8b004d2b73ac94b7ed2ac2a9b1d5d8d93675b Mon Sep 17 00:00:00 2001 From: Antoine Eiche Date: Thu, 21 Jul 2016 21:11:47 +0200 Subject: [PATCH 2/4] Documentation regarding the init-completion flag --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1b29c86..a564c22 100644 --- a/README.md +++ b/README.md @@ -794,10 +794,18 @@ func main() { #### Enabling -Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while -setting the `PROG` variable to the name of your program: +You can generate bash or zsh completion code by using the flag `--init-completion bash` or `--init-completion bash`. -`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete` +To setup for bash: + +``` +eval "`myprogram --init-completion bash`" +``` + +Alternatively, you can put the completion code in your `.bashrc` file: +``` +myprogram --init-completion bash >> ~/.bashrc +``` #### Distribution From 94bc26fd1cd5684da524420fa3db3c4e68aa193a Mon Sep 17 00:00:00 2001 From: Antoine Eiche Date: Fri, 22 Jul 2016 10:19:29 +0200 Subject: [PATCH 3/4] Refactoring names from bash to shell The refactoring is required since completion is also supported for zsh shell. Refactoring details: - flag generate-bash-completion -> generate-completion - var EnableBashCompletion -> EnableShellCompletion - var BashComplete -> ShellComplete - var BashCompletionFlag -> GenerateCompletionFlag - type BashCompleteFunc -> ShellCompleteFunc --- README.md | 30 +++++++++++++++--------------- app.go | 29 ++++++++++++++++------------- app_test.go | 20 ++++++++++---------- command.go | 14 +++++++------- flag.go | 6 +++--- funcs.go | 4 ++-- help.go | 14 +++++++------- 7 files changed, 60 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index a564c22..e63b9f5 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ applications in an expressive way. * [Subcommands](#subcommands) * [Subcommands categories](#subcommands-categories) * [Exit code](#exit-code) - * [Bash Completion](#bash-completion) + * [Shell Completion](#shell-completion) + [Enabling](#enabling) + [Distribution](#distribution) + [Customization](#customization) @@ -740,15 +740,15 @@ func main() { } ``` -### Bash Completion +### Shell Completion -You can enable completion commands by setting the `EnableBashCompletion` +You can enable completion commands by setting the `EnableShellCompletion` flag on the `App` object. By default, this setting will only auto-complete to show an app's subcommands, but you can write your own completion methods for the App or its subcommands. ``` go @@ -765,7 +765,7 @@ func main() { tasks := []string{"cook", "clean", "laundry", "eat", "sleep", "code"} app := &cli.App{ - EnableBashCompletion: true, + EnableShellCompletion: true, Commands: []*cli.Command{ { Name: "complete", @@ -775,7 +775,7 @@ func main() { fmt.Println("completed task: ", c.Args().First()) return nil }, - BashComplete: func(c *cli.Context) { + ShellComplete: func(c *cli.Context) { // This will complete if no args are passed if c.NArg() > 0 { return @@ -794,7 +794,7 @@ func main() { #### Enabling -You can generate bash or zsh completion code by using the flag `--init-completion bash` or `--init-completion bash`. +You can generate bash or zsh completion code by using the flag `--init-completion bash` or `--init-completion zsh`. To setup for bash: @@ -825,8 +825,8 @@ to the name of their program (as above). #### Customization -The default bash completion flag (`--generate-bash-completion`) is defined as -`cli.BashCompletionFlag`, and may be redefined if desired, e.g.: +The default shell completion flag (`--generate-completion`) is defined as +`cli.GenerateCompletionFlag`, and may be redefined if desired, e.g.: