mirror of
https://github.com/spf13/cobra
synced 2024-11-24 14:47:12 +00:00
complete aliases for subcommands
When completing a subcommand, also take its aliases into consideration instead of only its name. fixes #1852
This commit is contained in:
parent
ad6db7f8f6
commit
ce30e98be2
2 changed files with 74 additions and 1 deletions
|
@ -424,10 +424,20 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
|
||||||
// - there are no local, non-persistent flags on the command-line or TraverseChildren is true
|
// - there are no local, non-persistent flags on the command-line or TraverseChildren is true
|
||||||
for _, subCmd := range finalCmd.Commands() {
|
for _, subCmd := range finalCmd.Commands() {
|
||||||
if subCmd.IsAvailableCommand() || subCmd == finalCmd.helpCommand {
|
if subCmd.IsAvailableCommand() || subCmd == finalCmd.helpCommand {
|
||||||
|
directive = ShellCompDirectiveNoFileComp
|
||||||
|
|
||||||
|
// Only ever complete the name OR one of the aliases, no need to offer multiple matching ones
|
||||||
|
// for the same command.
|
||||||
if strings.HasPrefix(subCmd.Name(), toComplete) {
|
if strings.HasPrefix(subCmd.Name(), toComplete) {
|
||||||
completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
|
completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
|
||||||
|
} else {
|
||||||
|
for _, alias := range subCmd.Aliases {
|
||||||
|
if strings.HasPrefix(alias, toComplete) {
|
||||||
|
completions = append(completions, fmt.Sprintf("%s\t%s", alias, subCmd.Short))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
directive = ShellCompDirectiveNoFileComp
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2176,6 +2176,69 @@ func TestValidArgsNotValidArgsFunc(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCommandAliasesCompletionInGo(t *testing.T) {
|
||||||
|
rootCmd := &Command{
|
||||||
|
Use: "root",
|
||||||
|
Run: emptyRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
subCmd := &Command{
|
||||||
|
Use: "sandstone",
|
||||||
|
Aliases: []string{"slate", "pumice", "pegmatite"},
|
||||||
|
Run: emptyRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
rootCmd.AddCommand(subCmd)
|
||||||
|
|
||||||
|
testcases := []struct {
|
||||||
|
desc string
|
||||||
|
toComplete string
|
||||||
|
expectedCompletion string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "command name",
|
||||||
|
toComplete: "sand",
|
||||||
|
expectedCompletion: "sandstone",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "command name if an alias also matches",
|
||||||
|
toComplete: "s",
|
||||||
|
expectedCompletion: "sandstone",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "alias if command name does not match",
|
||||||
|
toComplete: "sla",
|
||||||
|
expectedCompletion: "slate",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "only one alias if multiple match",
|
||||||
|
toComplete: "p",
|
||||||
|
expectedCompletion: "pumice",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testcases {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
args := append([]string{ShellCompRequestCmd}, tc.toComplete)
|
||||||
|
output, err := executeCommand(rootCmd, args...)
|
||||||
|
|
||||||
|
expectedCompletion := strings.Join([]string{
|
||||||
|
tc.expectedCompletion,
|
||||||
|
":4",
|
||||||
|
"Completion ended with directive: ShellCompDirectiveNoFileComp",
|
||||||
|
"",
|
||||||
|
}, "\n")
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case err == nil && output != expectedCompletion:
|
||||||
|
t.Errorf("expected: %q, got: %q", expectedCompletion, output)
|
||||||
|
case err != nil:
|
||||||
|
t.Errorf("Unexpected error %q", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestArgAliasesCompletionInGo(t *testing.T) {
|
func TestArgAliasesCompletionInGo(t *testing.T) {
|
||||||
rootCmd := &Command{
|
rootCmd := &Command{
|
||||||
Use: "root",
|
Use: "root",
|
||||||
|
|
Loading…
Reference in a new issue