Improve suggestions - prefix will match

This commit is contained in:
Fabiano Franz 2015-09-25 11:41:47 -03:00
parent 53d96508f5
commit 3afa4db2c6
2 changed files with 42 additions and 28 deletions

View File

@ -818,20 +818,30 @@ func TestRootSuggestions(t *testing.T) {
tests := map[string]string{ tests := map[string]string{
"time": "times", "time": "times",
"tiems": "times", "tiems": "times",
"tims": "times",
"timeS": "times", "timeS": "times",
"rimes": "times", "rimes": "times",
"ti": "times",
"t": "times",
"timely": "times",
"ri": "",
"timezone": "",
"foo": "",
} }
for typo, suggestion := range tests { for typo, suggestion := range tests {
cmd.DisableSuggestions = false for _, suggestionsDisabled := range []bool{false, true} {
cmd.DisableSuggestions = suggestionsDisabled
result := simpleTester(cmd, typo) result := simpleTester(cmd, typo)
if expected := fmt.Sprintf(outputWithSuggestions, typo, suggestion); result.Output != expected { 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) 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)
} }
} }
} }

View File

@ -429,33 +429,37 @@ func (c *Command) Find(args []string) (*Command, []string, error) {
// root command with subcommands, do subcommand checking // root command with subcommands, do subcommand checking
if commandFound == c && len(argsWOflags) > 0 { if commandFound == c && len(argsWOflags) > 0 {
suggestions := "" suggestionsString := ""
if !c.DisableSuggestions { if !c.DisableSuggestions {
if c.SuggestionsMinimumDistance <= 0 { if c.SuggestionsMinimumDistance <= 0 {
c.SuggestionsMinimumDistance = 2 c.SuggestionsMinimumDistance = 2
} }
similar := []string{} if suggestions := c.SuggestionsFor(argsWOflags[0]); len(suggestions) > 0 {
for _, cmd := range c.commands { suggestionsString += "\n\nDid you mean this?\n"
if cmd.IsAvailableCommand() { for _, s := range suggestions {
levenshtein := ld(argsWOflags[0], cmd.Name(), true) suggestionsString += fmt.Sprintf("\t%v\n", s)
if levenshtein <= c.SuggestionsMinimumDistance {
similar = append(similar, cmd.Name())
} }
} }
} }
if len(similar) > 0 { return commandFound, a, fmt.Errorf("unknown command %q for %q%s", argsWOflags[0], commandFound.CommandPath(), suggestionsString)
suggestions += "\n\nDid you mean this?\n"
for _, s := range similar {
suggestions += 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, nil 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 { func (c *Command) Root() *Command {
var findRoot func(*Command) *Command var findRoot func(*Command) *Command