From 3afa4db2c62a1ff4befba4660b6a3b057ebcdb8a Mon Sep 17 00:00:00 2001 From: Fabiano Franz Date: Fri, 25 Sep 2015 11:41:47 -0300 Subject: [PATCH] Improve suggestions - prefix will match --- cobra_test.go | 36 +++++++++++++++++++++++------------- command.go | 34 +++++++++++++++++++--------------- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/cobra_test.go b/cobra_test.go index c9eef5d..6e0e5e3 100644 --- a/cobra_test.go +++ b/cobra_test.go @@ -816,22 +816,32 @@ func TestRootSuggestions(t *testing.T) { cmd.AddCommand(cmdTimes) tests := map[string]string{ - "time": "times", - "tiems": "times", - "timeS": "times", - "rimes": "times", + "time": "times", + "tiems": "times", + "tims": "times", + "timeS": "times", + "rimes": "times", + "ti": "times", + "t": "times", + "timely": "times", + "ri": "", + "timezone": "", + "foo": "", } for typo, suggestion := range tests { - cmd.DisableSuggestions = false - result := simpleTester(cmd, typo) - if expected := fmt.Sprintf(outputWithSuggestions, typo, suggestion); result.Output != expected { - t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", expected, result.Output) - } - cmd.DisableSuggestions = true - result = simpleTester(cmd, typo) - if expected := fmt.Sprintf(outputWithoutSuggestions, typo); result.Output != expected { - t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", expected, result.Output) + for _, suggestionsDisabled := range []bool{false, true} { + cmd.DisableSuggestions = suggestionsDisabled + result := simpleTester(cmd, typo) + expected := "" + if len(suggestion) == 0 || suggestionsDisabled { + expected = fmt.Sprintf(outputWithoutSuggestions, typo) + } else { + expected = fmt.Sprintf(outputWithSuggestions, typo, suggestion) + } + if result.Output != expected { + t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", expected, result.Output) + } } } } diff --git a/command.go b/command.go index 0cc0b72..44e962e 100644 --- a/command.go +++ b/command.go @@ -429,33 +429,37 @@ func (c *Command) Find(args []string) (*Command, []string, error) { // root command with subcommands, do subcommand checking if commandFound == c && len(argsWOflags) > 0 { - suggestions := "" + suggestionsString := "" if !c.DisableSuggestions { if c.SuggestionsMinimumDistance <= 0 { c.SuggestionsMinimumDistance = 2 } - similar := []string{} - for _, cmd := range c.commands { - if cmd.IsAvailableCommand() { - levenshtein := ld(argsWOflags[0], cmd.Name(), true) - if levenshtein <= c.SuggestionsMinimumDistance { - similar = append(similar, cmd.Name()) - } - } - } - if len(similar) > 0 { - suggestions += "\n\nDid you mean this?\n" - for _, s := range similar { - suggestions += fmt.Sprintf("\t%v\n", s) + if suggestions := c.SuggestionsFor(argsWOflags[0]); len(suggestions) > 0 { + suggestionsString += "\n\nDid you mean this?\n" + for _, s := range suggestions { + suggestionsString += fmt.Sprintf("\t%v\n", s) } } } - return commandFound, a, fmt.Errorf("unknown command %q for %q%s", argsWOflags[0], commandFound.CommandPath(), suggestions) + return commandFound, a, fmt.Errorf("unknown command %q for %q%s", argsWOflags[0], commandFound.CommandPath(), suggestionsString) } return commandFound, a, nil } +func (c *Command) SuggestionsFor(cmdName string) []string { + suggestions := []string{} + for _, cmd := range c.commands { + if cmd.IsAvailableCommand() { + levenshtein := ld(cmdName, cmd.Name(), true) + if levenshtein <= c.SuggestionsMinimumDistance || strings.HasPrefix(strings.ToLower(cmd.Name()), strings.ToLower(cmdName)) { + suggestions = append(suggestions, cmd.Name()) + } + } + } + return suggestions +} + func (c *Command) Root() *Command { var findRoot func(*Command) *Command