@ -123,6 +123,10 @@ __handle_reply()
 | 
				
			|||||||
    fi
 | 
					    fi
 | 
				
			||||||
    COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") )
 | 
					    COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then
 | 
				
			||||||
 | 
					        COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") )
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if [[ ${#COMPREPLY[@]} -eq 0 ]]; then
 | 
					    if [[ ${#COMPREPLY[@]} -eq 0 ]]; then
 | 
				
			||||||
        declare -F __custom_func >/dev/null && __custom_func
 | 
					        declare -F __custom_func >/dev/null && __custom_func
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
@ -189,7 +193,7 @@ __handle_noun()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then
 | 
					    if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then
 | 
				
			||||||
        must_have_one_noun=()
 | 
					        must_have_one_noun=()
 | 
				
			||||||
    elif __contains_word "${words[c]%s}" "${must_have_one_noun[@]}"; then
 | 
					    elif __contains_word "${words[c]}" "${noun_aliases[@]}"; then
 | 
				
			||||||
        must_have_one_noun=()
 | 
					        must_have_one_noun=()
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -460,7 +464,7 @@ func writeRequiredFlag(cmd *Command, w io.Writer) error {
 | 
				
			|||||||
	return visitErr
 | 
						return visitErr
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func writeRequiredNoun(cmd *Command, w io.Writer) error {
 | 
					func writeRequiredNouns(cmd *Command, w io.Writer) error {
 | 
				
			||||||
	if _, err := fmt.Fprintf(w, "    must_have_one_noun=()\n"); err != nil {
 | 
						if _, err := fmt.Fprintf(w, "    must_have_one_noun=()\n"); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -473,6 +477,19 @@ func writeRequiredNoun(cmd *Command, w io.Writer) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func writeArgAliases(cmd *Command, w io.Writer) error {
 | 
				
			||||||
 | 
						if _, err := fmt.Fprintf(w, "    noun_aliases=()\n"); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sort.Sort(sort.StringSlice(cmd.ArgAliases))
 | 
				
			||||||
 | 
						for _, value := range cmd.ArgAliases {
 | 
				
			||||||
 | 
							if _, err := fmt.Fprintf(w, "    noun_aliases+=(%q)\n", value); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func gen(cmd *Command, w io.Writer) error {
 | 
					func gen(cmd *Command, w io.Writer) error {
 | 
				
			||||||
	for _, c := range cmd.Commands() {
 | 
						for _, c := range cmd.Commands() {
 | 
				
			||||||
		if !c.IsAvailableCommand() || c == cmd.helpCommand {
 | 
							if !c.IsAvailableCommand() || c == cmd.helpCommand {
 | 
				
			||||||
@ -500,7 +517,10 @@ func gen(cmd *Command, w io.Writer) error {
 | 
				
			|||||||
	if err := writeRequiredFlag(cmd, w); err != nil {
 | 
						if err := writeRequiredFlag(cmd, w); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := writeRequiredNoun(cmd, w); err != nil {
 | 
						if err := writeRequiredNouns(cmd, w); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := writeArgAliases(cmd, w); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if _, err := fmt.Fprintf(w, "}\n\n"); err != nil {
 | 
						if _, err := fmt.Fprintf(w, "}\n\n"); err != nil {
 | 
				
			||||||
 | 
				
			|||||||
@ -80,7 +80,7 @@ The `BashCompletionFunction` option is really only valid/useful on the root comm
 | 
				
			|||||||
In the above example "pod" was assumed to already be typed. But 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:
 | 
					In the above example "pod" was assumed to already be typed. But 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:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```go
 | 
					```go
 | 
				
			||||||
validArgs []string = { "pods", "nodes", "services", "replicationControllers" }
 | 
					validArgs []string = { "pod", "node", "service", "replicationcontroller" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cmd := &cobra.Command{
 | 
					cmd := &cobra.Command{
 | 
				
			||||||
	Use:     "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)",
 | 
						Use:     "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)",
 | 
				
			||||||
@ -99,9 +99,34 @@ Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give result
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
# kubectl get [tab][tab]
 | 
					# kubectl get [tab][tab]
 | 
				
			||||||
nodes                 pods                    replicationControllers  services
 | 
					node                 pod                    replicationcontroller  service
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Plural form and shortcuts for nouns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go`
 | 
				
			||||||
 | 
					argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cmd := &cobra.Command{
 | 
				
			||||||
 | 
					    ...
 | 
				
			||||||
 | 
						ValidArgs:  validArgs,
 | 
				
			||||||
 | 
						ArgAliases: argAliases
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by
 | 
				
			||||||
 | 
					the completion aglorithm if entered manually, e.g. in:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					# kubectl get rc [tab][tab]
 | 
				
			||||||
 | 
					backend        frontend       database 
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns
 | 
				
			||||||
 | 
					in this example again instead of the replication controllers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Mark flags as required
 | 
					## Mark flags as required
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Most 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.
 | 
					Most 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.
 | 
				
			||||||
 | 
				
			|||||||
@ -43,9 +43,13 @@ func TestBashCompletions(t *testing.T) {
 | 
				
			|||||||
	c.MarkFlagRequired("introot")
 | 
						c.MarkFlagRequired("introot")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// valid nouns
 | 
						// valid nouns
 | 
				
			||||||
	validArgs := []string{"pods", "nodes", "services", "replicationControllers"}
 | 
						validArgs := []string{"pod", "node", "service", "replicationcontroller"}
 | 
				
			||||||
	c.ValidArgs = validArgs
 | 
						c.ValidArgs = validArgs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// noun aliases
 | 
				
			||||||
 | 
						argAliases := []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"}
 | 
				
			||||||
 | 
						c.ArgAliases = argAliases
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// filename
 | 
						// filename
 | 
				
			||||||
	var flagval string
 | 
						var flagval string
 | 
				
			||||||
	c.Flags().StringVar(&flagval, "filename", "", "Enter a filename")
 | 
						c.Flags().StringVar(&flagval, "filename", "", "Enter a filename")
 | 
				
			||||||
@ -88,7 +92,11 @@ func TestBashCompletions(t *testing.T) {
 | 
				
			|||||||
	// check for custom completion function
 | 
						// check for custom completion function
 | 
				
			||||||
	check(t, str, `COMPREPLY=( "hello" )`)
 | 
						check(t, str, `COMPREPLY=( "hello" )`)
 | 
				
			||||||
	// check for required nouns
 | 
						// check for required nouns
 | 
				
			||||||
	check(t, str, `must_have_one_noun+=("pods")`)
 | 
						check(t, str, `must_have_one_noun+=("pod")`)
 | 
				
			||||||
 | 
						// check for noun aliases
 | 
				
			||||||
 | 
						check(t, str, `noun_aliases+=("pods")`)
 | 
				
			||||||
 | 
						check(t, str, `noun_aliases+=("rc")`)
 | 
				
			||||||
 | 
						checkOmit(t, str, `must_have_one_noun+=("pods")`)
 | 
				
			||||||
	// check for filename extension flags
 | 
						// check for filename extension flags
 | 
				
			||||||
	check(t, str, `flags_completion+=("_filedir")`)
 | 
						check(t, str, `flags_completion+=("_filedir")`)
 | 
				
			||||||
	// check for filename extension flags
 | 
						// check for filename extension flags
 | 
				
			||||||
 | 
				
			|||||||
@ -45,8 +45,11 @@ type Command struct {
 | 
				
			|||||||
	Long string
 | 
						Long string
 | 
				
			||||||
	// Examples of how to use the command
 | 
						// Examples of how to use the command
 | 
				
			||||||
	Example string
 | 
						Example string
 | 
				
			||||||
	// List of all valid non-flag arguments, used for bash completions *TODO* actually validate these
 | 
						// List of all valid non-flag arguments that are accepted in bash completions
 | 
				
			||||||
	ValidArgs []string
 | 
						ValidArgs []string
 | 
				
			||||||
 | 
						// List of aliases for ValidArgs. These are not suggested to the user in the bash
 | 
				
			||||||
 | 
						// completion, but accepted if entered manually.
 | 
				
			||||||
 | 
						ArgAliases []string
 | 
				
			||||||
	// Custom functions used by the bash autocompletion generator
 | 
						// Custom functions used by the bash autocompletion generator
 | 
				
			||||||
	BashCompletionFunction string
 | 
						BashCompletionFunction string
 | 
				
			||||||
	// Is this command deprecated and should print this string when used?
 | 
						// Is this command deprecated and should print this string when used?
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user