Add help menu

This commit is contained in:
Evan Fiordeliso 2023-11-10 13:17:01 -05:00
parent d1b61e2eb4
commit 5519d58908
4 changed files with 158 additions and 28 deletions

46
cmd/test.go Normal file
View File

@ -0,0 +1,46 @@
package main
import (
"fmt"
"os"
"go.fifitido.net/cmd"
)
var root = cmd.NewRoot(
cmd.WithShortDescription("Example command"),
cmd.WithLongDescription(`An example command to show how to use go.fifitido.net/cmd
this example is just a simple hello world program to show
the basics of the library.`),
cmd.WithSubcommand(subcmd),
cmd.WithArgument("name", false),
cmd.WithRunFunc(func(args []string) {
if len(args) == 0 {
fmt.Println("Hello World!")
} else {
fmt.Printf("Hello %s!\n", args[0])
}
}),
)
var subcmd = cmd.New(
"test",
cmd.WithShortDescription("Example command"),
cmd.WithLongDescription(`An example command to show how to use go.fifitido.net/cmd
this example is just a simple hello world program to show
the basics of the library.`),
cmd.WithArgument("name", false),
cmd.WithRunFunc(func(args []string) {
if len(args) == 0 {
fmt.Println("Hello World!")
} else {
fmt.Printf("Hello %s!\n", args[0])
}
}),
)
func main() {
root.Execute(os.Args)
}

View File

@ -1,20 +1,22 @@
package cmd package cmd
import "go.fifitido.net/cmd/flags" import (
"os"
"path/filepath"
type RunFunc func(args []string) "go.fifitido.net/cmd/flags"
type RunErrFunc func(args []string) error )
type Command struct { type Command struct {
Name string Name string
ShortDescription string ShortDescription string
LongDescription string LongDescription string
Aliases []string aliases []string
Arguments []*Argument arguments []*Argument
Flags []flags.Flag flags []flags.Flag
Subcommands []*Command subcommands []*Command
Run RunFunc parent *Command
RunE RunErrFunc run func(args []string)
isRoot bool isRoot bool
} }
@ -36,36 +38,53 @@ func (c *Command) ApplyOptions(options ...Option) {
} }
} }
func (c *Command) CommandPath() string {
if c.parent == nil {
return filepath.Base(os.Args[0])
}
return c.parent.CommandPath() + " " + c.Name
}
func (c *Command) CanRun() bool {
return c.run != nil
}
func (c *Command) Run(args []string) {
c.run(args)
}
func (c *Command) Execute(args []string) { func (c *Command) Execute(args []string) {
if c.isRoot { if c.isRoot {
args = args[1:] args = args[1:]
} }
if len(args) > 0 { if len(args) > 0 {
for _, subcommand := range c.Subcommands { for _, subcommand := range c.subcommands {
if subcommand.Name == args[0] { if subcommand.Name == args[0] {
subcommand.Execute(args[1:]) subcommand.Execute(args[1:])
return return
} }
for _, alias := range subcommand.Aliases { for _, alias := range subcommand.aliases {
if alias == args[0] { if alias == args[0] {
subcommand.Execute(args[1:]) subcommand.Execute(args[1:])
return return
} }
} }
} }
// TODO: remove when done with flag parsing
if args[0] == "--help" {
c.ShowHelp()
return
}
} }
if c.Run != nil { if c.CanRun() {
c.Run(args) c.Run(args)
return return
} }
if c.RunE != nil { c.ShowHelp()
if err := c.RunE(args); err != nil {
panic(err)
}
return
}
} }

53
help.go Normal file
View File

@ -0,0 +1,53 @@
package cmd
import (
"fmt"
)
func (c *Command) ShowHelp() {
cmdPath := c.CommandPath()
fmt.Println(c.LongDescription)
fmt.Println()
fmt.Println("Usage: ")
fmt.Printf(" %s ", cmdPath)
if len(c.subcommands) > 0 {
if c.CanRun() {
fmt.Print("[command] ")
} else {
fmt.Print("<command> ")
}
}
fmt.Println("[flags]")
if len(c.subcommands) > 0 {
fmt.Println()
if c.isRoot {
fmt.Println("Available commands:")
} else {
fmt.Println("Available subcommands:")
}
for _, s := range c.subcommands {
fmt.Println(" " + s.Name + " " + s.ShortDescription)
}
}
fmt.Println()
fmt.Println("Available flags:")
for _, s := range c.flags {
fmt.Println(" " + s.Name() + " " + s.Description())
}
fmt.Println(" -h, --help Show the help menu")
fmt.Println(" -v, --version Show the app version")
if len(c.subcommands) > 0 {
fmt.Println()
fmt.Println("Run 'go-cli <command> --help' for more information about a command.")
}
}

View File

@ -18,48 +18,60 @@ func WithLongDescription(s string) Option {
func WithArgument(name string, required bool) Option { func WithArgument(name string, required bool) Option {
return func(c *Command) { return func(c *Command) {
c.Arguments = append(c.Arguments, &Argument{name, required}) c.arguments = append(c.arguments, &Argument{name, required})
} }
} }
func WithArguments(args []*Argument) Option { func WithArguments(args []*Argument) Option {
return func(c *Command) { return func(c *Command) {
c.Arguments = append(c.Arguments, args...) c.arguments = append(c.arguments, args...)
} }
} }
func WithFlag(f flags.Flag) Option { func WithFlag(f flags.Flag) Option {
return func(c *Command) { return func(c *Command) {
c.Flags = append(c.Flags, f) c.flags = append(c.flags, f)
} }
} }
func WithFlags(fs []flags.Flag) Option { func WithFlags(fs []flags.Flag) Option {
return func(c *Command) { return func(c *Command) {
c.Flags = append(c.Flags, fs...) c.flags = append(c.flags, fs...)
} }
} }
func WithSubcommand(s *Command) Option { func WithSubcommand(s *Command) Option {
return func(c *Command) { return func(c *Command) {
c.Subcommands = append(c.Subcommands, s) c.subcommands = append(c.subcommands, s)
s.parent = c
} }
} }
func WithSubcommands(ss []*Command) Option { func WithSubcommands(ss []*Command) Option {
return func(c *Command) { return func(c *Command) {
c.Subcommands = append(c.Subcommands, ss...) c.subcommands = append(c.subcommands, ss...)
} }
} }
func WithRunFunc(r RunFunc) Option { func WithParent(p *Command) Option {
return func(c *Command) { return func(c *Command) {
c.Run = r c.parent = p
p.subcommands = append(p.subcommands, c)
} }
} }
func WithRunErrFunc(r RunErrFunc) Option { func WithRunFunc(r func(args []string)) Option {
return func(c *Command) { return func(c *Command) {
c.RunE = r c.run = r
}
}
func WithRunErrFunc(r func(args []string) error) Option {
return func(c *Command) {
c.run = func(args []string) {
if err := r(args); err != nil {
panic(err)
}
}
} }
} }