mirror of
https://github.com/spf13/cobra
synced 2025-05-05 12:57:22 +00:00
Support subcommands checking for suggestions
Till now, only the root command is looked for suggestions. Now `findSuggestions` works for nested commands as well. For example ``` Error: unknown command "rewin" for "root times" Did you mean this? rewind Run 'root times --help' for usage. ``` Signed-off-by: Yuval Goldberg <yuvigoldi@gmail.com>
This commit is contained in:
parent
4fd30b69ee
commit
bbadd15b86
2 changed files with 98 additions and 26 deletions
8
args.go
8
args.go
|
@ -8,8 +8,8 @@ import (
|
||||||
type PositionalArgs func(cmd *Command, args []string) error
|
type PositionalArgs func(cmd *Command, args []string) error
|
||||||
|
|
||||||
// Legacy arg validation has the following behaviour:
|
// Legacy arg validation has the following behaviour:
|
||||||
// - root commands with no subcommands can take arbitrary arguments
|
// - commands with no subcommands can take arbitrary arguments
|
||||||
// - root commands with subcommands will do subcommand validity checking
|
// - commands with subcommands will do subcommand validity checking
|
||||||
// - subcommands will always accept arbitrary arguments
|
// - subcommands will always accept arbitrary arguments
|
||||||
func legacyArgs(cmd *Command, args []string) error {
|
func legacyArgs(cmd *Command, args []string) error {
|
||||||
// no subcommand, always take args
|
// no subcommand, always take args
|
||||||
|
@ -17,8 +17,8 @@ func legacyArgs(cmd *Command, args []string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// root command with subcommands, do subcommand checking.
|
// do subcommand checking
|
||||||
if !cmd.HasParent() && len(args) > 0 {
|
if len(args) > 0 {
|
||||||
return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0]))
|
return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0]))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
116
command_test.go
116
command_test.go
|
@ -1194,39 +1194,111 @@ func TestSuggestions(t *testing.T) {
|
||||||
SuggestFor: []string{"counts"},
|
SuggestFor: []string{"counts"},
|
||||||
Run: emptyRun,
|
Run: emptyRun,
|
||||||
}
|
}
|
||||||
|
rewindCmd := &Command{
|
||||||
|
Use: "rewind",
|
||||||
|
SuggestFor: []string{"dejavu"},
|
||||||
|
Run: emptyRun,
|
||||||
|
}
|
||||||
|
timesCmd.AddCommand(rewindCmd)
|
||||||
rootCmd.AddCommand(timesCmd)
|
rootCmd.AddCommand(timesCmd)
|
||||||
|
|
||||||
templateWithSuggestions := "Error: unknown command \"%s\" for \"root\"\n\nDid you mean this?\n\t%s\n\nRun 'root --help' for usage.\n"
|
templateSuggestions := "\nDid you mean this?\n\t%s\n\n"
|
||||||
templateWithoutSuggestions := "Error: unknown command \"%s\" for \"root\"\nRun 'root --help' for usage.\n"
|
|
||||||
|
|
||||||
tests := map[string]string{
|
templatePrefix := "Error: unknown command \"%s\" for \"%s\"\n"
|
||||||
"time": "times",
|
templateSuffix := "Run '%s --help' for usage.\n"
|
||||||
"tiems": "times",
|
|
||||||
"tims": "times",
|
tests := []struct {
|
||||||
"timeS": "times",
|
input string
|
||||||
"rimes": "times",
|
targetCommand string
|
||||||
"ti": "times",
|
expectedSuggestion string
|
||||||
"t": "times",
|
}{
|
||||||
"timely": "times",
|
{
|
||||||
"ri": "",
|
input: "time",
|
||||||
"timezone": "",
|
expectedSuggestion: "times",
|
||||||
"foo": "",
|
},
|
||||||
"counts": "times",
|
{
|
||||||
|
input: "tiems",
|
||||||
|
expectedSuggestion: "times",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "tims",
|
||||||
|
expectedSuggestion: "times",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "timeS",
|
||||||
|
expectedSuggestion: "times",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "rimes",
|
||||||
|
expectedSuggestion: "times",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "ti",
|
||||||
|
expectedSuggestion: "times",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "t",
|
||||||
|
expectedSuggestion: "times",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "timely",
|
||||||
|
expectedSuggestion: "times",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "ri",
|
||||||
|
expectedSuggestion: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "timezone",
|
||||||
|
expectedSuggestion: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "foo",
|
||||||
|
expectedSuggestion: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "counts",
|
||||||
|
expectedSuggestion: "times",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "foo rewind",
|
||||||
|
expectedSuggestion: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "times rewin",
|
||||||
|
targetCommand: "root times",
|
||||||
|
expectedSuggestion: "rewind",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "times dejavu",
|
||||||
|
targetCommand: "root times",
|
||||||
|
expectedSuggestion: "rewind",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for typo, suggestion := range tests {
|
for index := range tests {
|
||||||
for _, suggestionsDisabled := range []bool{true, false} {
|
for _, suggestionsDisabled := range []bool{true, false} {
|
||||||
|
test := tests[index]
|
||||||
|
|
||||||
|
timesCmd.DisableSuggestions = suggestionsDisabled
|
||||||
rootCmd.DisableSuggestions = suggestionsDisabled
|
rootCmd.DisableSuggestions = suggestionsDisabled
|
||||||
|
|
||||||
var expected string
|
args := strings.Split(test.input, " ")
|
||||||
output, _ := executeCommand(rootCmd, typo)
|
output, _ := executeCommand(rootCmd, args...)
|
||||||
|
|
||||||
if suggestion == "" || suggestionsDisabled {
|
unknownArg := args[len(args)-1]
|
||||||
expected = fmt.Sprintf(templateWithoutSuggestions, typo)
|
if test.targetCommand == "" {
|
||||||
} else {
|
test.targetCommand = rootCmd.Use
|
||||||
expected = fmt.Sprintf(templateWithSuggestions, typo, suggestion)
|
unknownArg = args[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expected := fmt.Sprintf(templatePrefix, unknownArg, test.targetCommand)
|
||||||
|
if test.expectedSuggestion != "" && !suggestionsDisabled {
|
||||||
|
expected += fmt.Sprintf(templateSuggestions, test.expectedSuggestion)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected += fmt.Sprintf(templateSuffix, test.targetCommand)
|
||||||
|
|
||||||
if output != expected {
|
if output != expected {
|
||||||
t.Errorf("Unexpected response.\nExpected:\n %q\nGot:\n %q\n", expected, output)
|
t.Errorf("Unexpected response.\nExpected:\n %q\nGot:\n %q\n", expected, output)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue