urfave-cli/suggestions.go
Sascha Grunert 002bde2233
Add suggestions support
The new option `app.Suggest` enables command and flag suggestions via
the jaro-winkler distance algorithm. Flags are scoped to their
appropriate commands whereas command suggestions are scoped to the
current command level.

Signed-off-by: Sascha Grunert <sgrunert@suse.com>
2020-03-03 13:06:34 +01:00

76 lines
1.6 KiB
Go

package cli
import (
"fmt"
"github.com/antzucaro/matchr"
)
const didYouMeanTemplate = "Did you mean '%s'?"
func (a *App) suggestFlagFromError(err error, command string) (string, error) {
flag, parseErr := flagFromError(err)
if parseErr != nil {
return "", err
}
flags := a.Flags
if command != "" {
cmd := a.Command(command)
if cmd == nil {
return "", err
}
flags = cmd.Flags
}
suggestion := a.suggestFlag(flags, flag)
if len(suggestion) == 0 {
return "", err
}
return fmt.Sprintf(didYouMeanTemplate+"\n\n", suggestion), nil
}
func (a *App) suggestFlag(flags []Flag, provided string) (suggestion string) {
distance := 0.0
for _, flag := range flags {
flagNames := flag.Names()
if !a.HideHelp {
flagNames = append(flagNames, HelpFlag.Names()...)
}
for _, name := range flagNames {
newDistance := matchr.JaroWinkler(name, provided, true)
if newDistance > distance {
distance = newDistance
suggestion = name
}
}
}
if len(suggestion) == 1 {
suggestion = "-" + suggestion
} else if len(suggestion) > 1 {
suggestion = "--" + suggestion
}
return suggestion
}
// suggestCommand takes a list of commands and a provided string to suggest a
// command name
func suggestCommand(commands []*Command, provided string) (suggestion string) {
distance := 0.0
for _, command := range commands {
for _, name := range append(command.Names(), helpName, helpAlias) {
newDistance := matchr.JaroWinkler(name, provided, true)
if newDistance > distance {
distance = newDistance
suggestion = name
}
}
}
return fmt.Sprintf(didYouMeanTemplate, suggestion)
}