rework Find() to make it more obvious what is happening

We had lots of quirky if statements like `commandFound.Name() ==
c.Name() && len(stripFlags(args, c)) > 0 && commandFound.Name() !=
args[0]` which embeed all sorts of artifacts which are hard to parse. So
in general, just try to simplify and make stuff readable.
This commit is contained in:
Eric Paris 2015-06-09 13:52:43 -04:00
parent 66816bcd03
commit d0bb3e33e6

View file

@ -381,49 +381,47 @@ func (c *Command) Find(args []string) (*Command, []string, error) {
return nil, nil, fmt.Errorf("Called find() on a nil Command") return nil, nil, fmt.Errorf("Called find() on a nil Command")
} }
// If there are no arguments, return the root command. If the root has no
// subcommands, args reflects arguments that should actually be passed to
// the root command, so also return the root command.
if len(args) == 0 || !c.Root().HasSubCommands() {
return c.Root(), args, nil
}
var innerfind func(*Command, []string) (*Command, []string) var innerfind func(*Command, []string) (*Command, []string)
innerfind = func(c *Command, innerArgs []string) (*Command, []string) { innerfind = func(c *Command, innerArgs []string) (*Command, []string) {
if len(innerArgs) > 0 && c.HasSubCommands() { argsWOflags := stripFlags(innerArgs, c)
argsWOflags := stripFlags(innerArgs, c) if len(argsWOflags) == 0 {
if len(argsWOflags) > 0 { return c, innerArgs
matches := make([]*Command, 0) }
for _, cmd := range c.commands { nextSubCmd := argsWOflags[0]
if cmd.Name() == argsWOflags[0] || cmd.HasAlias(argsWOflags[0]) { // exact name or alias match matches := make([]*Command, 0)
return innerfind(cmd, argsMinusFirstX(innerArgs, argsWOflags[0])) for _, cmd := range c.commands {
} else if EnablePrefixMatching { if cmd.Name() == nextSubCmd || cmd.HasAlias(nextSubCmd) { // exact name or alias match
if strings.HasPrefix(cmd.Name(), argsWOflags[0]) { // prefix match return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd))
matches = append(matches, cmd) }
} if EnablePrefixMatching {
for _, x := range cmd.Aliases { if strings.HasPrefix(cmd.Name(), nextSubCmd) { // prefix match
if strings.HasPrefix(x, argsWOflags[0]) { matches = append(matches, cmd)
matches = append(matches, cmd) }
} for _, x := range cmd.Aliases {
} if strings.HasPrefix(x, nextSubCmd) {
matches = append(matches, cmd)
} }
} }
// only accept a single prefix match - multiple matches would be ambiguous
if len(matches) == 1 {
return innerfind(matches[0], argsMinusFirstX(innerArgs, argsWOflags[0]))
}
} }
} }
// only accept a single prefix match - multiple matches would be ambiguous
if len(matches) == 1 {
return innerfind(matches[0], argsMinusFirstX(innerArgs, argsWOflags[0]))
}
return c, innerArgs return c, innerArgs
} }
commandFound, a := innerfind(c, args) commandFound, a := innerfind(c, args)
// If we matched on the root, but we asked for a subcommand, return an error
argsWOflags := stripFlags(a, commandFound) argsWOflags := stripFlags(a, commandFound)
// no subcommand, always take args
if !commandFound.HasSubCommands() {
return commandFound, a, nil
}
// root command with subcommands, do subcommand checking
if commandFound == c && len(argsWOflags) > 0 { if commandFound == c && len(argsWOflags) > 0 {
return nil, a, fmt.Errorf("unknown command %q", argsWOflags[0]) return nil, a, fmt.Errorf("unknown command %q", argsWOflags[0])
} }