Add Command.Aliases and deprecate Command.ShortName

`Aliases` will be more flexible while still allowing "ShortName"
behaviour via `Aliases`.
This commit is contained in:
jszwedko 2015-03-09 21:24:57 -07:00
parent 3e0905345c
commit bf65971a6a
7 changed files with 75 additions and 71 deletions

View File

@ -210,7 +210,7 @@ Subcommands can be defined for a more git-like command line app.
app.Commands = []cli.Command{ app.Commands = []cli.Command{
{ {
Name: "add", Name: "add",
ShortName: "a", Names: []string{"a"},
Usage: "add a task to the list", Usage: "add a task to the list",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
println("added task: ", c.Args().First()) println("added task: ", c.Args().First())
@ -218,7 +218,7 @@ app.Commands = []cli.Command{
}, },
{ {
Name: "complete", Name: "complete",
ShortName: "c", Names: []string{"c"},
Usage: "complete a task on the list", Usage: "complete a task on the list",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
println("completed task: ", c.Args().First()) println("completed task: ", c.Args().First())
@ -226,7 +226,7 @@ app.Commands = []cli.Command{
}, },
{ {
Name: "template", Name: "template",
ShortName: "r", Names: []string{"r"},
Usage: "options for task templates", Usage: "options for task templates",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
@ -244,7 +244,7 @@ app.Commands = []cli.Command{
}, },
}, },
}, },
}, },
} }
... ...
``` ```
@ -262,8 +262,8 @@ app := cli.NewApp()
app.EnableBashCompletion = true app.EnableBashCompletion = true
app.Commands = []cli.Command{ app.Commands = []cli.Command{
{ {
Name: "complete", Name: "complete",
ShortName: "c", Names: []string{"c"},
Usage: "complete a task on the list", Usage: "complete a task on the list",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
println("completed task: ", c.Args().First()) println("completed task: ", c.Args().First())

7
app.go
View File

@ -5,6 +5,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"strings"
"text/tabwriter" "text/tabwriter"
"text/template" "text/template"
"time" "time"
@ -91,8 +92,12 @@ func (a *App) Run(arguments []string) (err error) {
}() }()
HelpPrinter = func(templ string, data interface{}) { HelpPrinter = func(templ string, data interface{}) {
funcMap := template.FuncMap{
"join": strings.Join,
}
w := tabwriter.NewWriter(a.Writer, 0, 8, 1, '\t', 0) w := tabwriter.NewWriter(a.Writer, 0, 8, 1, '\t', 0)
t := template.Must(template.New("help").Parse(templ)) t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
err := t.Execute(w, data) err := t.Execute(w, data)
if err != nil { if err != nil {
panic(err) panic(err)

View File

@ -29,41 +29,24 @@ func ExampleApp() {
// Hello Jeremy // Hello Jeremy
} }
func ExampleAppSubcommand() { func ExampleAppCommands() {
// set args for examples sake // set args for examples sake
os.Args = []string{"say", "hi", "english", "--name", "Jeremy"} os.Args = []string{"greet", "--name", "Jeremy"}
app := cli.NewApp()
app.Name = "say"
app.Commands = []cli.Command{
{
Name: "hello",
ShortName: "hi",
Usage: "use it to see a description",
Description: "This is how we describe hello the function",
Subcommands: []cli.Command{
{
Name: "english",
ShortName: "en",
Usage: "sends a greeting in english",
Description: "greets someone in english",
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Value: "Bob",
Usage: "Name of the person to greet",
},
},
Action: func(c *cli.Context) {
fmt.Println("Hello,", c.String("name"))
},
},
},
},
}
app := cli.NewApp()
app.Name = "greet"
app.Flags = []cli.Flag{
cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
}
app.Action = func(c *cli.Context) {
fmt.Printf("Hello %v\n", c.String("name"))
}
app.Author = "Harrison"
app.Email = "harrison@lolwut.com"
app.Authors = []cli.Author{{"Oliver Allen", "oliver@toyshop.com"}}
app.Run(os.Args) app.Run(os.Args)
// Output: // Output:
// Hello, Jeremy // Hello Jeremy
} }
func ExampleAppHelp() { func ExampleAppHelp() {
@ -78,7 +61,7 @@ func ExampleAppHelp() {
app.Commands = []cli.Command{ app.Commands = []cli.Command{
{ {
Name: "describeit", Name: "describeit",
ShortName: "d", Aliases: []string{"d"},
Usage: "use it to see a description", Usage: "use it to see a description",
Description: "This is how we describe describeit the function", Description: "This is how we describe describeit the function",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
@ -108,7 +91,7 @@ func ExampleAppBashComplete() {
app.Commands = []cli.Command{ app.Commands = []cli.Command{
{ {
Name: "describeit", Name: "describeit",
ShortName: "d", Aliases: []string{"d"},
Usage: "use it to see a description", Usage: "use it to see a description",
Description: "This is how we describe describeit the function", Description: "This is how we describe describeit the function",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
@ -162,8 +145,8 @@ var commandAppTests = []struct {
func TestApp_Command(t *testing.T) { func TestApp_Command(t *testing.T) {
app := cli.NewApp() app := cli.NewApp()
fooCommand := cli.Command{Name: "foobar", ShortName: "f"} fooCommand := cli.Command{Name: "foobar", Aliases: []string{"f"}}
batCommand := cli.Command{Name: "batbaz", ShortName: "b"} batCommand := cli.Command{Name: "batbaz", Aliases: []string{"b"}}
app.Commands = []cli.Command{ app.Commands = []cli.Command{
fooCommand, fooCommand,
batCommand, batCommand,

View File

@ -12,17 +12,17 @@ func Example() {
app.Usage = "task list on the command line" app.Usage = "task list on the command line"
app.Commands = []cli.Command{ app.Commands = []cli.Command{
{ {
Name: "add", Name: "add",
ShortName: "a", Aliases: []string{"a"},
Usage: "add a task to the list", Usage: "add a task to the list",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
println("added task: ", c.Args().First()) println("added task: ", c.Args().First())
}, },
}, },
{ {
Name: "complete", Name: "complete",
ShortName: "c", Aliases: []string{"c"},
Usage: "complete a task on the list", Usage: "complete a task on the list",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
println("completed task: ", c.Args().First()) println("completed task: ", c.Args().First())
}, },
@ -38,13 +38,13 @@ func ExampleSubcommand() {
app.Commands = []cli.Command{ app.Commands = []cli.Command{
{ {
Name: "hello", Name: "hello",
ShortName: "hi", Aliases: []string{"hi"},
Usage: "use it to see a description", Usage: "use it to see a description",
Description: "This is how we describe hello the function", Description: "This is how we describe hello the function",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
Name: "english", Name: "english",
ShortName: "en", Aliases: []string{"en"},
Usage: "sends a greeting in english", Usage: "sends a greeting in english",
Description: "greets someone in english", Description: "greets someone in english",
Flags: []cli.Flag{ Flags: []cli.Flag{
@ -58,9 +58,9 @@ func ExampleSubcommand() {
println("Hello, ", c.String("name")) println("Hello, ", c.String("name"))
}, },
}, { }, {
Name: "spanish", Name: "spanish",
ShortName: "sp", Aliases: []string{"sp"},
Usage: "sends a greeting in spanish", Usage: "sends a greeting in spanish",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: "surname", Name: "surname",
@ -72,9 +72,9 @@ func ExampleSubcommand() {
println("Hola, ", c.String("surname")) println("Hola, ", c.String("surname"))
}, },
}, { }, {
Name: "french", Name: "french",
ShortName: "fr", Aliases: []string{"fr"},
Usage: "sends a greeting in french", Usage: "sends a greeting in french",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: "nickname", Name: "nickname",

View File

@ -10,8 +10,10 @@ import (
type Command struct { type Command struct {
// The name of the command // The name of the command
Name string Name string
// short name of the command. Typically one character // short name of the command. Typically one character (deprecated, use `Aliases`)
ShortName string ShortName string
// A list of aliases for the command
Aliases []string
// A short description of the usage of this command // A short description of the usage of this command
Usage string Usage string
// A longer explanation of how the command works // A longer explanation of how the command works
@ -117,9 +119,24 @@ func (c Command) Run(ctx *Context) error {
return nil return nil
} }
func (c Command) Names() []string {
names := []string{c.Name}
if c.ShortName != "" {
names = append(names, c.ShortName)
}
return append(names, c.Aliases...)
}
// Returns true if Command.Name or Command.ShortName matches given name // Returns true if Command.Name or Command.ShortName matches given name
func (c Command) HasName(name string) bool { func (c Command) HasName(name string) bool {
return c.Name == name || (c.ShortName != "" && c.ShortName == name) for _, n := range c.Names() {
if n == name {
return true
}
}
return false
} }
func (c Command) startApp(ctx *Context) error { func (c Command) startApp(ctx *Context) error {

View File

@ -17,7 +17,7 @@ func TestCommandDoNotIgnoreFlags(t *testing.T) {
command := cli.Command{ command := cli.Command{
Name: "test-cmd", Name: "test-cmd",
ShortName: "tc", Aliases: []string{"tc"},
Usage: "this is for testing", Usage: "this is for testing",
Description: "testing", Description: "testing",
Action: func(_ *cli.Context) {}, Action: func(_ *cli.Context) {},
@ -37,7 +37,7 @@ func TestCommandIgnoreFlags(t *testing.T) {
command := cli.Command{ command := cli.Command{
Name: "test-cmd", Name: "test-cmd",
ShortName: "tc", Aliases: []string{"tc"},
Usage: "this is for testing", Usage: "this is for testing",
Description: "testing", Description: "testing",
Action: func(_ *cli.Context) {}, Action: func(_ *cli.Context) {},

21
help.go
View File

@ -18,7 +18,7 @@ AUTHOR(S):
{{range .Authors}}{{ . }} {{end}} {{range .Authors}}{{ . }} {{end}}
COMMANDS: COMMANDS:
{{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
{{end}}{{if .Flags}} {{end}}{{if .Flags}}
GLOBAL OPTIONS: GLOBAL OPTIONS:
{{range .Flags}}{{.}} {{range .Flags}}{{.}}
@ -52,7 +52,7 @@ USAGE:
{{.Name}} command{{if .Flags}} [command options]{{end}} [arguments...] {{.Name}} command{{if .Flags}} [command options]{{end}} [arguments...]
COMMANDS: COMMANDS:
{{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
{{end}}{{if .Flags}} {{end}}{{if .Flags}}
OPTIONS: OPTIONS:
{{range .Flags}}{{.}} {{range .Flags}}{{.}}
@ -60,9 +60,9 @@ OPTIONS:
` `
var helpCommand = Command{ var helpCommand = Command{
Name: "help", Name: "help",
ShortName: "h", Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command", Usage: "Shows a list of commands or help for one command",
Action: func(c *Context) { Action: func(c *Context) {
args := c.Args() args := c.Args()
if args.Present() { if args.Present() {
@ -74,9 +74,9 @@ var helpCommand = Command{
} }
var helpSubcommand = Command{ var helpSubcommand = Command{
Name: "help", Name: "help",
ShortName: "h", Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command", Usage: "Shows a list of commands or help for one command",
Action: func(c *Context) { Action: func(c *Context) {
args := c.Args() args := c.Args()
if args.Present() { if args.Present() {
@ -102,9 +102,8 @@ func ShowAppHelp(c *Context) {
// Prints the list of subcommands as the default app completion method // Prints the list of subcommands as the default app completion method
func DefaultAppComplete(c *Context) { func DefaultAppComplete(c *Context) {
for _, command := range c.App.Commands { for _, command := range c.App.Commands {
fmt.Fprintln(c.App.Writer, command.Name) for _, name := range command.Names() {
if command.ShortName != "" { fmt.Fprintln(c.App.Writer, name)
fmt.Fprintln(c.App.Writer, command.ShortName)
} }
} }
} }