1# Generating Bash Completions For Your Own cobra.Command
2
3If you are using the generator you can create a completion command by running
4
5```bash
6cobra add completion
7```
8
9Update the help text show how to install the bash_completion Linux show here [Kubectl docs show mac options](https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion)
10
11Writing the shell script to stdout allows the most flexible use.
12
13```go
14// completionCmd represents the completion command
15var completionCmd = &cobra.Command{
16	Use:   "completion",
17	Short: "Generates bash completion scripts",
18	Long: `To load completion run
19
20. <(bitbucket completion)
21
22To configure your bash shell to load completions for each session add to your bashrc
23
24# ~/.bashrc or ~/.profile
25. <(bitbucket completion)
26`,
27	Run: func(cmd *cobra.Command, args []string) {
28		rootCmd.GenBashCompletion(os.Stdout);
29	},
30}
31```
32
33**Note:** The cobra generator may include messages printed to stdout for example if the config file is loaded, this will break the auto complete script
34
35
36## Example from kubectl
37
38Generating bash completions from a cobra command is incredibly easy. An actual program which does so for the kubernetes kubectl binary is as follows:
39
40```go
41package main
42
43import (
44	"io/ioutil"
45	"os"
46
47	"k8s.io/kubernetes/pkg/kubectl/cmd"
48	"k8s.io/kubernetes/pkg/kubectl/cmd/util"
49)
50
51func main() {
52	kubectl := cmd.NewKubectlCommand(util.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
53	kubectl.GenBashCompletionFile("out.sh")
54}
55```
56
57`out.sh` will get you completions of subcommands and flags. Copy it to `/etc/bash_completion.d/` as described [here](https://debian-administration.org/article/316/An_introduction_to_bash_completion_part_1) and reset your terminal to use autocompletion. If you make additional annotations to your code, you can get even more intelligent and flexible behavior.
58
59## Have the completions code complete your 'nouns'
60
61### Static completion of nouns
62
63This method allows you to provide a pre-defined list of completion choices for your nouns using the `validArgs` field.
64For example, if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like:
65
66```go
67validArgs []string = { "pod", "node", "service", "replicationcontroller" }
68
69cmd := &cobra.Command{
70	Use:     "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)",
71	Short:   "Display one or many resources",
72	Long:    get_long,
73	Example: get_example,
74	Run: func(cmd *cobra.Command, args []string) {
75		err := RunGet(f, out, cmd, args)
76		util.CheckErr(err)
77	},
78	ValidArgs: validArgs,
79}
80```
81
82Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like
83
84```bash
85# kubectl get [tab][tab]
86node                 pod                    replicationcontroller  service
87```
88
89### Plural form and shortcuts for nouns
90
91If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`:
92
93```go
94argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" }
95
96cmd := &cobra.Command{
97    ...
98	ValidArgs:  validArgs,
99	ArgAliases: argAliases
100}
101```
102
103The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by
104the completion algorithm if entered manually, e.g. in:
105
106```bash
107# kubectl get rc [tab][tab]
108backend        frontend       database
109```
110
111Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns
112in this example again instead of the replication controllers.
113
114### Dynamic completion of nouns
115
116In some cases it is not possible to provide a list of possible completions in advance.  Instead, the list of completions must be determined at execution-time.  Cobra provides two ways of defining such dynamic completion of nouns. Note that both these methods can be used along-side each other as long as they are not both used for the same command.
117
118**Note**: *Custom Completions written in Go* will automatically work for other shell-completion scripts (e.g., Fish shell), while *Custom Completions written in Bash* will only work for Bash shell-completion.  It is therefore recommended to use *Custom Completions written in Go*.
119
120#### 1. Custom completions of nouns written in Go
121
122In a similar fashion as for static completions, you can use the `ValidArgsFunction` field to provide a Go function that Cobra will execute when it needs the list of completion choices for the nouns of a command.  Note that either `ValidArgs` or `ValidArgsFunction` can be used for a single cobra command, but not both.
123Simplified code from `helm status` looks like:
124
125```go
126cmd := &cobra.Command{
127	Use:   "status RELEASE_NAME",
128	Short: "Display the status of the named release",
129	Long:  status_long,
130	RunE: func(cmd *cobra.Command, args []string) {
131		RunGet(args[0])
132	},
133	ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
134		if len(args) != 0 {
135			return nil, cobra.ShellCompDirectiveNoFileComp
136		}
137		return getReleasesFromCluster(toComplete), cobra.ShellCompDirectiveNoFileComp
138	},
139}
140```
141Where `getReleasesFromCluster()` is a Go function that obtains the list of current Helm releases running on the Kubernetes cluster.
142Notice we put the `ValidArgsFunction` on the `status` subcommand. Let's assume the Helm releases on the cluster are: `harbor`, `notary`, `rook` and `thanos` then this dynamic completion will give results like
143
144```bash
145# helm status [tab][tab]
146harbor notary rook thanos
147```
148You may have noticed the use of `cobra.ShellCompDirective`.  These directives are bit fields allowing to control some shell completion behaviors for your particular completion.  You can combine them with the bit-or operator such as `cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp`
149```go
150// Indicates an error occurred and completions should be ignored.
151ShellCompDirectiveError
152// Indicates that the shell should not add a space after the completion,
153// even if there is a single completion provided.
154ShellCompDirectiveNoSpace
155// Indicates that the shell should not provide file completion even when
156// no completion is provided.
157// This currently does not work for zsh or bash < 4
158ShellCompDirectiveNoFileComp
159// Indicates that the shell will perform its default behavior after completions
160// have been provided (this implies !ShellCompDirectiveNoSpace && !ShellCompDirectiveNoFileComp).
161ShellCompDirectiveDefault
162```
163
164When using the `ValidArgsFunction`, Cobra will call your registered function after having parsed all flags and arguments provided in the command-line.  You therefore don't need to do this parsing yourself.  For example, when a user calls `helm status --namespace my-rook-ns [tab][tab]`, Cobra will call your registered `ValidArgsFunction` after having parsed the `--namespace` flag, as it would have done when calling the `RunE` function.
165
166##### Debugging
167
168Cobra achieves dynamic completions written in Go through the use of a hidden command called by the completion script.  To debug your Go completion code, you can call this hidden command directly:
169```bash
170# helm __complete status har<ENTER>
171harbor
172:4
173Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr
174```
175***Important:*** If the noun to complete is empty, you must pass an empty parameter to the `__complete` command:
176```bash
177# helm __complete status ""<ENTER>
178harbor
179notary
180rook
181thanos
182:4
183Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr
184```
185Calling the `__complete` command directly allows you to run the Go debugger to troubleshoot your code.  You can also add printouts to your code; Cobra provides the following functions to use for printouts in Go completion code:
186```go
187// Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE
188// is set to a file path) and optionally prints to stderr.
189cobra.CompDebug(msg string, printToStdErr bool) {
190cobra.CompDebugln(msg string, printToStdErr bool)
191
192// Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE
193// is set to a file path) and to stderr.
194cobra.CompError(msg string)
195cobra.CompErrorln(msg string)
196```
197***Important:*** You should **not** leave traces that print to stdout in your completion code as they will be interpreted as completion choices by the completion script.  Instead, use the cobra-provided debugging traces functions mentioned above.
198
199#### 2. Custom completions of nouns written in Bash
200
201This method allows you to inject bash functions into the completion script.  Those bash functions are responsible for providing the completion choices for your own completions.
202
203Some more actual code that works in kubernetes:
204
205```bash
206const (
207        bash_completion_func = `__kubectl_parse_get()
208{
209    local kubectl_output out
210    if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then
211        out=($(echo "${kubectl_output}" | awk '{print $1}'))
212        COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
213    fi
214}
215
216__kubectl_get_resource()
217{
218    if [[ ${#nouns[@]} -eq 0 ]]; then
219        return 1
220    fi
221    __kubectl_parse_get ${nouns[${#nouns[@]} -1]}
222    if [[ $? -eq 0 ]]; then
223        return 0
224    fi
225}
226
227__kubectl_custom_func() {
228    case ${last_command} in
229        kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop)
230            __kubectl_get_resource
231            return
232            ;;
233        *)
234            ;;
235    esac
236}
237`)
238```
239
240And then I set that in my command definition:
241
242```go
243cmds := &cobra.Command{
244	Use:   "kubectl",
245	Short: "kubectl controls the Kubernetes cluster manager",
246	Long: `kubectl controls the Kubernetes cluster manager.
247
248Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
249	Run: runHelp,
250	BashCompletionFunction: bash_completion_func,
251}
252```
253
254The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__kubectl_custom_func()` (`__<command-use>_custom_func()`) to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__kubectl_customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__kubectl_custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`.  `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`.  So it will call `__kubectl_parse_get pod`.  `__kubectl_parse_get` will actually call out to kubernetes and get any pods.  It will then set `COMPREPLY` to valid pods!
255
256## Mark flags as required
257
258Most of the time completions will only show subcommands. But if a flag is required to make a subcommand work, you probably want it to show up when the user types [tab][tab].  Marking a flag as 'Required' is incredibly easy.
259
260```go
261cmd.MarkFlagRequired("pod")
262cmd.MarkFlagRequired("container")
263```
264
265and you'll get something like
266
267```bash
268# kubectl exec [tab][tab][tab]
269-c            --container=  -p            --pod=
270```
271
272# Specify valid filename extensions for flags that take a filename
273
274In this example we use --filename= and expect to get a json or yaml file as the argument. To make this easier we annotate the --filename flag with valid filename extensions.
275
276```go
277	annotations := []string{"json", "yaml", "yml"}
278	annotation := make(map[string][]string)
279	annotation[cobra.BashCompFilenameExt] = annotations
280
281	flag := &pflag.Flag{
282		Name:        "filename",
283		Shorthand:   "f",
284		Usage:       usage,
285		Value:       value,
286		DefValue:    value.String(),
287		Annotations: annotation,
288	}
289	cmd.Flags().AddFlag(flag)
290```
291
292Now when you run a command with this filename flag you'll get something like
293
294```bash
295# kubectl create -f
296test/                         example/                      rpmbuild/
297hello.yml                     test.json
298```
299
300So while there are many other files in the CWD it only shows me subdirs and those with valid extensions.
301
302# Specify custom flag completion
303
304As for nouns, Cobra provides two ways of defining dynamic completion of flags.  Note that both these methods can be used along-side each other as long as they are not both used for the same flag.
305
306**Note**: *Custom Completions written in Go* will automatically work for other shell-completion scripts (e.g., Fish shell), while *Custom Completions written in Bash* will only work for Bash shell-completion.  It is therefore recommended to use *Custom Completions written in Go*.
307
308## 1. Custom completions of flags written in Go
309
310To provide a Go function that Cobra will execute when it needs the list of completion choices for a flag, you must register the function in the following manner:
311
312```go
313flagName := "output"
314cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
315	return []string{"json", "table", "yaml"}, cobra.ShellCompDirectiveDefault
316})
317```
318Notice that calling `RegisterFlagCompletionFunc()` is done through the `command` with which the flag is associated.  In our example this dynamic completion will give results like so:
319
320```bash
321# helm status --output [tab][tab]
322json table yaml
323```
324
325### Debugging
326
327You can also easily debug your Go completion code for flags:
328```bash
329# helm __complete status --output ""
330json
331table
332yaml
333:4
334Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr
335```
336***Important:*** You should **not** leave traces that print to stdout in your completion code as they will be interpreted as completion choices by the completion script.  Instead, use the cobra-provided debugging traces functions mentioned in the above section.
337
338## 2. Custom completions of flags written in Bash
339
340Alternatively, you can use bash code for flag custom completion. Similar to the filename
341completion and filtering using `cobra.BashCompFilenameExt`, you can specify
342a custom flag completion bash function with `cobra.BashCompCustom`:
343
344```go
345	annotation := make(map[string][]string)
346	annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"}
347
348	flag := &pflag.Flag{
349		Name:        "namespace",
350		Usage:       usage,
351		Annotations: annotation,
352	}
353	cmd.Flags().AddFlag(flag)
354```
355
356In addition add the `__kubectl_get_namespaces` implementation in the `BashCompletionFunction`
357value, e.g.:
358
359```bash
360__kubectl_get_namespaces()
361{
362    local template
363    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
364    local kubectl_out
365    if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
366        COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) )
367    fi
368}
369```
370# Using bash aliases for commands
371
372You can also configure the `bash aliases` for the commands and they will also support completions.
373
374```bash
375alias aliasname=origcommand
376complete -o default -F __start_origcommand aliasname
377
378# and now when you run `aliasname` completion will make
379# suggestions as it did for `origcommand`.
380
381$) aliasname <tab><tab>
382completion     firstcommand   secondcommand
383```
384