mirror of
https://github.com/spf13/cobra
synced 2024-11-24 14:47:12 +00:00
Replace prefix matching with aliases
This commit is contained in:
parent
83b58a2f9b
commit
881657297e
2 changed files with 34 additions and 40 deletions
|
@ -26,9 +26,10 @@ var cmdPrint = &Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmdEcho = &Command{
|
var cmdEcho = &Command{
|
||||||
Use: "echo [string to echo]",
|
Use: "echo [string to echo]",
|
||||||
Short: "Echo anything to the screen",
|
Aliases: []string{"say"},
|
||||||
Long: `an utterly useless command for testing.`,
|
Short: "Echo anything to the screen",
|
||||||
|
Long: `an utterly useless command for testing.`,
|
||||||
Run: func(cmd *Command, args []string) {
|
Run: func(cmd *Command, args []string) {
|
||||||
te = args
|
te = args
|
||||||
},
|
},
|
||||||
|
@ -38,7 +39,9 @@ var cmdTimes = &Command{
|
||||||
Use: "times [# times] [string to echo]",
|
Use: "times [# times] [string to echo]",
|
||||||
Short: "Echo anything to the screen more times",
|
Short: "Echo anything to the screen more times",
|
||||||
Long: `an slightly useless command for testing.`,
|
Long: `an slightly useless command for testing.`,
|
||||||
Run: timesRunner,
|
Run: func(cmd *Command, args []string) {
|
||||||
|
tt = args
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmdRootNoRun = &Command{
|
var cmdRootNoRun = &Command{
|
||||||
|
@ -62,10 +65,6 @@ var cmdRootWithRun = &Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func timesRunner(cmd *Command, args []string) {
|
|
||||||
tt = args
|
|
||||||
}
|
|
||||||
|
|
||||||
func flagInit() {
|
func flagInit() {
|
||||||
cmdEcho.ResetFlags()
|
cmdEcho.ResetFlags()
|
||||||
cmdPrint.ResetFlags()
|
cmdPrint.ResetFlags()
|
||||||
|
@ -195,8 +194,8 @@ func TestChildCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChildCommandPrefix(t *testing.T) {
|
func TestCommandAlias(t *testing.T) {
|
||||||
noRRSetupTest("ech tim one two")
|
noRRSetupTest("say times one two")
|
||||||
|
|
||||||
if te != nil || tp != nil {
|
if te != nil || tp != nil {
|
||||||
t.Error("Wrong command called")
|
t.Error("Wrong command called")
|
||||||
|
@ -226,23 +225,6 @@ func TestChildSameName(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChildSameNamePrefix(t *testing.T) {
|
|
||||||
c := initializeWithSameName()
|
|
||||||
c.AddCommand(cmdPrint, cmdEcho)
|
|
||||||
c.SetArgs(strings.Split("pr one two", " "))
|
|
||||||
c.Execute()
|
|
||||||
|
|
||||||
if te != nil || tt != nil {
|
|
||||||
t.Error("Wrong command called")
|
|
||||||
}
|
|
||||||
if tp == nil {
|
|
||||||
t.Error("Wrong command called")
|
|
||||||
}
|
|
||||||
if strings.Join(tp, " ") != "one two" {
|
|
||||||
t.Error("Command didn't parse correctly")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFlagLong(t *testing.T) {
|
func TestFlagLong(t *testing.T) {
|
||||||
noRRSetupTest("echo --intone=13 something here")
|
noRRSetupTest("echo --intone=13 something here")
|
||||||
|
|
||||||
|
|
38
command.go
38
command.go
|
@ -35,6 +35,8 @@ type Command struct {
|
||||||
name string
|
name string
|
||||||
// The one-line usage message.
|
// The one-line usage message.
|
||||||
Use string
|
Use string
|
||||||
|
// An array of aliases that can be used instead of the first word in Use.
|
||||||
|
Aliases []string
|
||||||
// The short description shown in the 'help' output.
|
// The short description shown in the 'help' output.
|
||||||
Short string
|
Short string
|
||||||
// The long message shown in the 'help <this-command>' output.
|
// The long message shown in the 'help <this-command>' output.
|
||||||
|
@ -189,7 +191,10 @@ func (c *Command) UsageTemplate() string {
|
||||||
return `{{ $cmd := . }}
|
return `{{ $cmd := . }}
|
||||||
Usage: {{if .Runnable}}
|
Usage: {{if .Runnable}}
|
||||||
{{.UseLine}}{{if .HasFlags}} [flags]{{end}}{{end}}{{if .HasSubCommands}}
|
{{.UseLine}}{{if .HasFlags}} [flags]{{end}}{{end}}{{if .HasSubCommands}}
|
||||||
{{ .CommandPath}} [command]{{end}}
|
{{ .CommandPath}} [command]{{end}}{{if gt .Aliases 0}}
|
||||||
|
|
||||||
|
Aliases:
|
||||||
|
{{.NameAndAliases}}{{end}}
|
||||||
{{ if .HasSubCommands}}
|
{{ if .HasSubCommands}}
|
||||||
Available Commands: {{range .Commands}}{{if .Runnable}}
|
Available Commands: {{range .Commands}}{{if .Runnable}}
|
||||||
{{rpad .Use .UsagePadding }} {{.Short}}{{end}}{{end}}
|
{{rpad .Use .UsagePadding }} {{.Short}}{{end}}{{end}}
|
||||||
|
@ -281,19 +286,11 @@ func (c *Command) Find(arrs []string) (*Command, []string, error) {
|
||||||
if len(args) > 0 && c.HasSubCommands() {
|
if len(args) > 0 && c.HasSubCommands() {
|
||||||
argsWOflags := stripFlags(args)
|
argsWOflags := stripFlags(args)
|
||||||
if len(argsWOflags) > 0 {
|
if len(argsWOflags) > 0 {
|
||||||
matches := make([]*Command, 0)
|
|
||||||
for _, cmd := range c.commands {
|
for _, cmd := range c.commands {
|
||||||
if cmd.Name() == argsWOflags[0] { // exact name match
|
if cmd.Name() == argsWOflags[0] || cmd.HasAlias(argsWOflags[0]) { // exact name or alias match
|
||||||
return innerfind(cmd, argsMinusX(args, cmd.Name()))
|
return innerfind(cmd, argsMinusX(args, argsWOflags[0]))
|
||||||
} else if strings.HasPrefix(cmd.Name(), argsWOflags[0]) { // prefix match
|
|
||||||
matches = append(matches, cmd)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// only accept a single prefix match - multiple matches would be ambiguous
|
|
||||||
if len(matches) == 1 {
|
|
||||||
return innerfind(matches[0], argsMinusX(args, argsWOflags[0]))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,8 +299,9 @@ func (c *Command) Find(arrs []string) (*Command, []string, error) {
|
||||||
|
|
||||||
commandFound, a := innerfind(c, arrs)
|
commandFound, a := innerfind(c, arrs)
|
||||||
|
|
||||||
// if commander returned and not appropriately matched return nil & error
|
// if commander returned and the first argument (if it exists) doesn't
|
||||||
if commandFound.Name() == c.Name() && !strings.HasPrefix(commandFound.Name(), arrs[0]) {
|
// match the command name, return nil & error
|
||||||
|
if commandFound.Name() == c.Name() && len(arrs[0]) > 0 && commandFound.Name() != arrs[0] {
|
||||||
return nil, a, fmt.Errorf("unknown command %q\nRun 'help' for usage.\n", a[0])
|
return nil, a, fmt.Errorf("unknown command %q\nRun 'help' for usage.\n", a[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,6 +612,20 @@ func (c *Command) Name() string {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine if a given string is an alias of the command.
|
||||||
|
func (c *Command) HasAlias(s string) bool {
|
||||||
|
for _, a := range c.Aliases {
|
||||||
|
if a == s {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) NameAndAliases() string {
|
||||||
|
return strings.Join(append([]string{c.Name()}, c.Aliases...), ", ")
|
||||||
|
}
|
||||||
|
|
||||||
// Determine if the command is itself runnable
|
// Determine if the command is itself runnable
|
||||||
func (c *Command) Runnable() bool {
|
func (c *Command) Runnable() bool {
|
||||||
return c.Run != nil
|
return c.Run != nil
|
||||||
|
|
Loading…
Reference in a new issue