mirror of
https://github.com/spf13/cobra
synced 2025-01-28 22:46:46 +00:00
Rework to allow override on suggestion output, only, keeping common search logic.
This commit is contained in:
parent
4d65edfb54
commit
5897ead246
3 changed files with 46 additions and 51 deletions
4
args.go
4
args.go
|
@ -33,7 +33,7 @@ func legacyArgs(cmd *Command, args []string) error {
|
|||
|
||||
// root command with subcommands, do subcommand checking.
|
||||
if !cmd.HasParent() && len(args) > 0 {
|
||||
return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.SuggestFunc(args[0]))
|
||||
return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0]))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ func OnlyValidArgs(cmd *Command, args []string) error {
|
|||
}
|
||||
for _, v := range args {
|
||||
if !stringInSlice(v, validArgs) {
|
||||
return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.SuggestFunc(args[0]))
|
||||
return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
69
command.go
69
command.go
|
@ -180,8 +180,8 @@ type Command struct {
|
|||
helpCommand *Command
|
||||
// helpCommandGroupID is the group id for the helpCommand
|
||||
helpCommandGroupID string
|
||||
// suggestFunc is suggest func defined by the user.
|
||||
suggestFunc func(string) string
|
||||
// suggestOutputFunc is user's override for the suggestion output.
|
||||
suggestOutputFunc func([]string) string
|
||||
|
||||
// completionCommandGroupID is the group id for the completion command
|
||||
completionCommandGroupID string
|
||||
|
@ -342,8 +342,8 @@ func (c *Command) SetHelpCommandGroupID(groupID string) {
|
|||
c.helpCommandGroupID = groupID
|
||||
}
|
||||
|
||||
func (c *Command) SetSuggestFunc(f func(string) string) {
|
||||
c.suggestFunc = f
|
||||
func (c *Command) SetSuggestOutputFunc(f func([]string) string) {
|
||||
c.suggestOutputFunc = f
|
||||
}
|
||||
|
||||
// SetCompletionCommandGroupID sets the group id of the completion command.
|
||||
|
@ -483,37 +483,6 @@ func (c *Command) Help() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SuggestFunc returns suggestions for the provided typedName using either
|
||||
// the function set by SetSuggestFunc for this command, parent's or a default one.
|
||||
// When searching for a parent's function, it recursively checks towards the root
|
||||
// and returns the first one found. If none found, uses direct parent's default.
|
||||
func (c *Command) SuggestFunc(typedName string) string {
|
||||
if c.DisableSuggestions {
|
||||
return ""
|
||||
}
|
||||
if c.suggestFunc != nil {
|
||||
return c.suggestFunc(typedName)
|
||||
}
|
||||
if c.HasParent() {
|
||||
var getParentFunc func(*Command) func(string) string
|
||||
getParentFunc = func(parent *Command) func(string) string {
|
||||
if parent.suggestFunc != nil {
|
||||
return parent.suggestFunc
|
||||
}
|
||||
if !parent.HasParent() {
|
||||
return nil
|
||||
}
|
||||
return getParentFunc(parent.Parent())
|
||||
}
|
||||
parentFunc := getParentFunc(c.Parent())
|
||||
if parentFunc != nil {
|
||||
return parentFunc(typedName)
|
||||
}
|
||||
return c.Parent().findSuggestions(typedName)
|
||||
}
|
||||
return c.findSuggestions(typedName)
|
||||
}
|
||||
|
||||
// UsageString returns usage string.
|
||||
func (c *Command) UsageString() string {
|
||||
// Storing normal writers
|
||||
|
@ -786,15 +755,41 @@ func (c *Command) Find(args []string) (*Command, []string, error) {
|
|||
return commandFound, a, nil
|
||||
}
|
||||
|
||||
func (c *Command) findSuggestions(arg string) string {
|
||||
// findSuggestions returns suggestions for the provided typedName if suggestions aren't disabled.
|
||||
// The output building function can be overridden by setting it with the SetSuggestOutputFunc.
|
||||
// If the output override is, instead, set on a parent, it uses the first one found.
|
||||
// If none is set, a default is used.
|
||||
func (c *Command) findSuggestions(typedName string) string {
|
||||
if c.DisableSuggestions {
|
||||
return ""
|
||||
}
|
||||
if c.SuggestionsMinimumDistance <= 0 {
|
||||
c.SuggestionsMinimumDistance = 2
|
||||
}
|
||||
|
||||
suggestions := c.SuggestionsFor(typedName)
|
||||
|
||||
if c.suggestOutputFunc != nil {
|
||||
return c.suggestOutputFunc(suggestions)
|
||||
}
|
||||
if c.HasParent() {
|
||||
var getParentFunc func(*Command) func([]string) string
|
||||
getParentFunc = func(parent *Command) func([]string) string {
|
||||
if parent.suggestOutputFunc != nil {
|
||||
return parent.suggestOutputFunc
|
||||
}
|
||||
if !parent.HasParent() {
|
||||
return nil
|
||||
}
|
||||
return getParentFunc(parent.Parent())
|
||||
}
|
||||
if parentFunc := getParentFunc(c.Parent()); parentFunc != nil {
|
||||
return parentFunc(suggestions)
|
||||
}
|
||||
}
|
||||
|
||||
var sb strings.Builder
|
||||
if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 {
|
||||
if len(suggestions) > 0 {
|
||||
sb.WriteString("\n\nDid you mean this?\n")
|
||||
for _, s := range suggestions {
|
||||
_, _ = fmt.Fprintf(&sb, "\t%v\n", s)
|
||||
|
|
|
@ -1421,11 +1421,11 @@ func TestCustomSuggestions(t *testing.T) {
|
|||
}
|
||||
|
||||
rootCmd.DisableSuggestions = false
|
||||
rootCmd.SetSuggestFunc(func(typedName string) string {
|
||||
return "\nSome custom suggestion.\n"
|
||||
rootCmd.SetSuggestOutputFunc(func(suggestions []string) string {
|
||||
return fmt.Sprintf("\nSuggestions:\n\t%s\n", strings.Join(suggestions, "\n"))
|
||||
})
|
||||
|
||||
expected = fmt.Sprintf("Error: unknown command \"%s\" for \"root\"\nSome custom suggestion.\n\nRun 'root --help' for usage.\n", "time")
|
||||
expected = fmt.Sprintf("Error: unknown command \"time\" for \"root\"\nSuggestions:\n\ttimes\n\nRun 'root --help' for usage.\n")
|
||||
output, _ = executeCommand(rootCmd, "time")
|
||||
if output != expected {
|
||||
t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
|
||||
|
@ -1471,42 +1471,42 @@ func TestCustomSuggestions_OnlyValidArgs(t *testing.T) {
|
|||
}
|
||||
|
||||
// 2nd level typo.
|
||||
expected = "Error: invalid argument \"paren\" for \"root grandparent\"\nUsage:\n root grandparent [flags]\n root grandparent [command]\n\nAvailable Commands:\n parent \n\nFlags:\n -h, --help help for grandparent\n\nUse \"root grandparent [command] --help\" for more information about a command.\n\n"
|
||||
expected = "Error: invalid argument \"paren\" for \"root grandparent\"\n\nDid you mean this?\n\tparent\n\nUsage:\n root grandparent [flags]\n root grandparent [command]\n\nAvailable Commands:\n parent \n\nFlags:\n -h, --help help for grandparent\n\nUse \"root grandparent [command] --help\" for more information about a command.\n\n"
|
||||
output, _ = executeCommand(rootCmd, "grandparent", "paren")
|
||||
if output != expected {
|
||||
t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
|
||||
}
|
||||
|
||||
// 3rd level typo.
|
||||
expected = "Error: invalid argument \"time\" for \"root grandparent parent\"\nUsage:\n root grandparent parent [flags]\n root grandparent parent [command]\n\nAvailable Commands:\n times \n\nFlags:\n -h, --help help for parent\n\nUse \"root grandparent parent [command] --help\" for more information about a command.\n\n"
|
||||
expected = "Error: invalid argument \"time\" for \"root grandparent parent\"\n\nDid you mean this?\n\ttimes\n\nUsage:\n root grandparent parent [flags]\n root grandparent parent [command]\n\nAvailable Commands:\n times \n\nFlags:\n -h, --help help for parent\n\nUse \"root grandparent parent [command] --help\" for more information about a command.\n\n"
|
||||
output, _ = executeCommand(rootCmd, "grandparent", "parent", "time")
|
||||
if output != expected {
|
||||
t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
|
||||
}
|
||||
|
||||
// Custom suggestion on root function.
|
||||
rootCmd.SetSuggestFunc(func(typedName string) string {
|
||||
return "\nRoot custom suggestion.\n"
|
||||
rootCmd.SetSuggestOutputFunc(func(suggestions []string) string {
|
||||
return fmt.Sprintf("\nRoot Suggestions:\n\t%s\n", strings.Join(suggestions, "\n"))
|
||||
})
|
||||
|
||||
expected = "Error: invalid argument \"grandparen\" for \"root\"\nRoot custom suggestion.\n\nUsage:\n root [flags]\n root [command]\n\nAvailable Commands:\n completion Generate the autocompletion script for the specified shell\n grandparent \n help Help about any command\n\nFlags:\n -h, --help help for root\n\nUse \"root [command] --help\" for more information about a command.\n\n"
|
||||
expected = "Error: invalid argument \"grandparen\" for \"root\"\nRoot Suggestions:\n\tgrandparent\n\nUsage:\n root [flags]\n root [command]\n\nAvailable Commands:\n completion Generate the autocompletion script for the specified shell\n grandparent \n help Help about any command\n\nFlags:\n -h, --help help for root\n\nUse \"root [command] --help\" for more information about a command.\n\n"
|
||||
output, _ = executeCommand(rootCmd, "grandparen")
|
||||
if output != expected {
|
||||
t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
|
||||
}
|
||||
|
||||
expected = "Error: invalid argument \"time\" for \"root grandparent parent\"\nRoot custom suggestion.\n\nUsage:\n root grandparent parent [flags]\n root grandparent parent [command]\n\nAvailable Commands:\n times \n\nFlags:\n -h, --help help for parent\n\nUse \"root grandparent parent [command] --help\" for more information about a command.\n\n"
|
||||
expected = "Error: invalid argument \"time\" for \"root grandparent parent\"\nRoot Suggestions:\n\ttimes\n\nUsage:\n root grandparent parent [flags]\n root grandparent parent [command]\n\nAvailable Commands:\n times \n\nFlags:\n -h, --help help for parent\n\nUse \"root grandparent parent [command] --help\" for more information about a command.\n\n"
|
||||
output, _ = executeCommand(rootCmd, "grandparent", "parent", "time")
|
||||
if output != expected {
|
||||
t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
|
||||
}
|
||||
|
||||
// Custom suggestion on parent function (kept root's to make sure this one is prioritised).
|
||||
parentCmd.SetSuggestFunc(func(typedName string) string {
|
||||
return "\nParent custom suggestion.\n"
|
||||
parentCmd.SetSuggestOutputFunc(func(suggestions []string) string {
|
||||
return fmt.Sprintf("\nParent Suggestions:\n\t%s\n", strings.Join(suggestions, "\n"))
|
||||
})
|
||||
|
||||
expected = "Error: invalid argument \"time\" for \"root grandparent parent\"\nParent custom suggestion.\n\nUsage:\n root grandparent parent [flags]\n root grandparent parent [command]\n\nAvailable Commands:\n times \n\nFlags:\n -h, --help help for parent\n\nUse \"root grandparent parent [command] --help\" for more information about a command.\n\n"
|
||||
expected = "Error: invalid argument \"time\" for \"root grandparent parent\"\nParent Suggestions:\n\ttimes\n\nUsage:\n root grandparent parent [flags]\n root grandparent parent [command]\n\nAvailable Commands:\n times \n\nFlags:\n -h, --help help for parent\n\nUse \"root grandparent parent [command] --help\" for more information about a command.\n\n"
|
||||
output, _ = executeCommand(rootCmd, "grandparent", "parent", "time")
|
||||
if output != expected {
|
||||
t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
|
||||
|
|
Loading…
Reference in a new issue