Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API (urgent): Rename BashCompDirectives to ShellCompDirectives #1082

Merged
merged 1 commit into from
Apr 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bash_completions.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ __%[1]s_handle_word()
__%[1]s_handle_word
}

`, name, CompRequestCmd, BashCompDirectiveError, BashCompDirectiveNoSpace, BashCompDirectiveNoFileComp))
`, name, ShellCompRequestCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp))
}

func writePostscript(buf *bytes.Buffer, name string) {
Expand Down
28 changes: 14 additions & 14 deletions bash_completions.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,11 @@ cmd := &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) {
RunGet(args[0])
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.BashCompDirective) {
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.BashCompDirectiveNoFileComp
return nil, cobra.ShellCompDirectiveNoFileComp
}
return getReleasesFromCluster(toComplete), cobra.BashCompDirectiveNoFileComp
return getReleasesFromCluster(toComplete), cobra.ShellCompDirectiveNoFileComp
},
}
```
Expand All @@ -143,20 +143,20 @@ Notice we put the `ValidArgsFunction` on the `status` subcommand. Let's assume t
# helm status [tab][tab]
harbor notary rook thanos
```
You may have noticed the use of `cobra.BashCompDirective`. 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.BashCompDirectiveNoSpace | cobra.BashCompDirectiveNoFileComp`
You 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`
```go
// Indicates an error occurred and completions should be ignored.
BashCompDirectiveError
ShellCompDirectiveError
// Indicates that the shell should not add a space after the completion,
// even if there is a single completion provided.
BashCompDirectiveNoSpace
ShellCompDirectiveNoSpace
// Indicates that the shell should not provide file completion even when
// no completion is provided.
// This currently does not work for zsh or bash < 4
BashCompDirectiveNoFileComp
ShellCompDirectiveNoFileComp
// Indicates that the shell will perform its default behavior after completions
// have been provided (this implies !BashCompDirectiveNoSpace && !BashCompDirectiveNoFileComp).
BashCompDirectiveDefault
// have been provided (this implies !ShellCompDirectiveNoSpace && !ShellCompDirectiveNoFileComp).
ShellCompDirectiveDefault
```

When 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.
Expand All @@ -168,7 +168,7 @@ Cobra achieves dynamic completions written in Go through the use of a hidden com
# helm __complete status har<ENTER>
harbor
:4
Completion ended with directive: BashCompDirectiveNoFileComp # This is on stderr
Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr
```
***Important:*** If the noun to complete is empty, you must pass an empty parameter to the `__complete` command:
```bash
Expand All @@ -178,7 +178,7 @@ notary
rook
thanos
:4
Completion ended with directive: BashCompDirectiveNoFileComp # This is on stderr
Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr
```
Calling 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:
```go
Expand Down Expand Up @@ -307,8 +307,8 @@ To provide a Go function that Cobra will execute when it needs the list of compl

```go
flagName := "output"
cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.BashCompDirective) {
return []string{"json", "table", "yaml"}, cobra.BashCompDirectiveDefault
cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"json", "table", "yaml"}, cobra.ShellCompDirectiveDefault
})
```
Notice 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:
Expand All @@ -327,7 +327,7 @@ json
table
yaml
:4
Completion ended with directive: BashCompDirectiveNoFileComp # This is on stderr
Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr
```
***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.

Expand Down
2 changes: 1 addition & 1 deletion command.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ type Command struct {
// ValidArgsFunction is an optional function that provides valid non-flag arguments for bash completion.
// It is a dynamic version of using ValidArgs.
// Only one of ValidArgs and ValidArgsFunction can be used for a command.
ValidArgsFunction func(cmd *Command, args []string, toComplete string) ([]string, BashCompDirective)
ValidArgsFunction func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)

// Expected arguments
Args PositionalArgs
Expand Down
70 changes: 35 additions & 35 deletions custom_completions.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,37 @@ import (
"github.com/spf13/pflag"
)

// CompRequestCmd is the name of the hidden command that is used to request
// ShellCompRequestCmd is the name of the hidden command that is used to request
// completion results from the program. It is used by the shell completion script.
const CompRequestCmd = "__complete"
const ShellCompRequestCmd = "__complete"

// Global map of flag completion functions.
var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, BashCompDirective){}
var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){}

// BashCompDirective is a bit map representing the different behaviors the shell
// ShellCompDirective is a bit map representing the different behaviors the shell
// can be instructed to have once completions have been provided.
type BashCompDirective int
type ShellCompDirective int

const (
// BashCompDirectiveError indicates an error occurred and completions should be ignored.
BashCompDirectiveError BashCompDirective = 1 << iota
// ShellCompDirectiveError indicates an error occurred and completions should be ignored.
ShellCompDirectiveError ShellCompDirective = 1 << iota

// BashCompDirectiveNoSpace indicates that the shell should not add a space
// ShellCompDirectiveNoSpace indicates that the shell should not add a space
// after the completion even if there is a single completion provided.
BashCompDirectiveNoSpace
ShellCompDirectiveNoSpace

// BashCompDirectiveNoFileComp indicates that the shell should not provide
// ShellCompDirectiveNoFileComp indicates that the shell should not provide
// file completion even when no completion is provided.
// This currently does not work for zsh or bash < 4
BashCompDirectiveNoFileComp
ShellCompDirectiveNoFileComp

// BashCompDirectiveDefault indicates to let the shell perform its default
// ShellCompDirectiveDefault indicates to let the shell perform its default
// behavior after completions have been provided.
BashCompDirectiveDefault BashCompDirective = 0
ShellCompDirectiveDefault ShellCompDirective = 0
)

// RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag.
func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, BashCompDirective)) error {
func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)) error {
flag := c.Flag(flagName)
if flag == nil {
return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' does not exist", flagName)
Expand All @@ -52,38 +52,38 @@ func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Comman
}

// Returns a string listing the different directive enabled in the specified parameter
func (d BashCompDirective) string() string {
func (d ShellCompDirective) string() string {
var directives []string
if d&BashCompDirectiveError != 0 {
directives = append(directives, "BashCompDirectiveError")
if d&ShellCompDirectiveError != 0 {
directives = append(directives, "ShellCompDirectiveError")
}
if d&BashCompDirectiveNoSpace != 0 {
directives = append(directives, "BashCompDirectiveNoSpace")
if d&ShellCompDirectiveNoSpace != 0 {
directives = append(directives, "ShellCompDirectiveNoSpace")
}
if d&BashCompDirectiveNoFileComp != 0 {
directives = append(directives, "BashCompDirectiveNoFileComp")
if d&ShellCompDirectiveNoFileComp != 0 {
directives = append(directives, "ShellCompDirectiveNoFileComp")
}
if len(directives) == 0 {
directives = append(directives, "BashCompDirectiveDefault")
directives = append(directives, "ShellCompDirectiveDefault")
}

if d > BashCompDirectiveError+BashCompDirectiveNoSpace+BashCompDirectiveNoFileComp {
return fmt.Sprintf("ERROR: unexpected BashCompDirective value: %d", d)
if d > ShellCompDirectiveError+ShellCompDirectiveNoSpace+ShellCompDirectiveNoFileComp {
return fmt.Sprintf("ERROR: unexpected ShellCompDirective value: %d", d)
}
return strings.Join(directives, ", ")
}

// Adds a special hidden command that can be used to request custom completions.
func (c *Command) initCompleteCmd(args []string) {
completeCmd := &Command{
Use: fmt.Sprintf("%s [command-line]", CompRequestCmd),
Use: fmt.Sprintf("%s [command-line]", ShellCompRequestCmd),
DisableFlagsInUseLine: true,
Hidden: true,
DisableFlagParsing: true,
Args: MinimumNArgs(1),
Short: "Request shell completion choices for the specified command-line",
Long: fmt.Sprintf("%[2]s is a special command that is used by the shell completion logic\n%[1]s",
"to request completion choices for the specified command-line.", CompRequestCmd),
"to request completion choices for the specified command-line.", ShellCompRequestCmd),
Run: func(cmd *Command, args []string) {
finalCmd, completions, directive, err := cmd.getCompletions(args)
if err != nil {
Expand All @@ -98,8 +98,8 @@ func (c *Command) initCompleteCmd(args []string) {
fmt.Fprintln(finalCmd.OutOrStdout(), comp)
}

if directive > BashCompDirectiveError+BashCompDirectiveNoSpace+BashCompDirectiveNoFileComp {
directive = BashCompDirectiveDefault
if directive > ShellCompDirectiveError+ShellCompDirectiveNoSpace+ShellCompDirectiveNoFileComp {
directive = ShellCompDirectiveDefault
}

// As the last printout, print the completion directive for the completion script to parse.
Expand All @@ -114,7 +114,7 @@ func (c *Command) initCompleteCmd(args []string) {
}
c.AddCommand(completeCmd)
subCmd, _, err := c.Find(args)
if err != nil || subCmd.Name() != CompRequestCmd {
if err != nil || subCmd.Name() != ShellCompRequestCmd {
// Only create this special command if it is actually being called.
// This reduces possible side-effects of creating such a command;
// for example, having this command would cause problems to a
Expand All @@ -124,7 +124,7 @@ func (c *Command) initCompleteCmd(args []string) {
}
}

func (c *Command) getCompletions(args []string) (*Command, []string, BashCompDirective, error) {
func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDirective, error) {
var completions []string

// The last argument, which is not completely typed by the user,
Expand All @@ -136,7 +136,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, BashCompDir
finalCmd, finalArgs, err := c.Root().Find(trimmedArgs)
if err != nil {
// Unable to find the real command. E.g., <program> someInvalidCmd <TAB>
return c, completions, BashCompDirectiveDefault, fmt.Errorf("Unable to find a command for arguments: %v", trimmedArgs)
return c, completions, ShellCompDirectiveDefault, fmt.Errorf("Unable to find a command for arguments: %v", trimmedArgs)
}

var flag *pflag.Flag
Expand All @@ -146,13 +146,13 @@ func (c *Command) getCompletions(args []string) (*Command, []string, BashCompDir
flag, finalArgs, toComplete, err = checkIfFlagCompletion(finalCmd, finalArgs, toComplete)
if err != nil {
// Error while attempting to parse flags
return finalCmd, completions, BashCompDirectiveDefault, err
return finalCmd, completions, ShellCompDirectiveDefault, err
}
}

// Parse the flags and extract the arguments to prepare for calling the completion function
if err = finalCmd.ParseFlags(finalArgs); err != nil {
return finalCmd, completions, BashCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error())
return finalCmd, completions, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error())
}

// We only remove the flags from the arguments if DisableFlagParsing is not set.
Expand All @@ -162,15 +162,15 @@ func (c *Command) getCompletions(args []string) (*Command, []string, BashCompDir
}

// Find the completion function for the flag or command
var completionFn func(cmd *Command, args []string, toComplete string) ([]string, BashCompDirective)
var completionFn func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)
if flag != nil {
completionFn = flagCompletionFunctions[flag]
} else {
completionFn = finalCmd.ValidArgsFunction
}
if completionFn == nil {
// Go custom completion not supported/needed for this flag or command
return finalCmd, completions, BashCompDirectiveDefault, nil
return finalCmd, completions, ShellCompDirectiveDefault, nil
}

// Call the registered completion function to get the completions
Expand Down
Loading