diff --git a/acmd.go b/acmd.go index e814f81..54cd185 100644 --- a/acmd.go +++ b/acmd.go @@ -7,6 +7,7 @@ import ( "os" "os/signal" "sort" + "text/tabwriter" ) // Runner of the sub-commands. @@ -33,9 +34,12 @@ type Command struct { // Config for the runner. type Config struct { - // AppName is an optional nal for the app, if empty os.Args[0] will be used. + // AppName is an optional name for the app, if empty os.Args[0] will be used. AppName string + // AppDescription is an optional description. default is empty. + AppDescription string + // Version of the application. Version string @@ -46,7 +50,7 @@ type Config struct { Args []string // Usage of the application, if nil default will be used, - Usage func(name string, cmds []Command) + Usage func(cfg Config, cmds []Command) } // RunnerOf creates a Runner. @@ -74,6 +78,10 @@ func (r *Runner) init() error { r.ctx, _ = signal.NotifyContext(context.Background(), os.Interrupt) } + if r.cfg.Usage == nil { + r.cfg.Usage = defaultUsage + } + names := make(map[string]struct{}) for _, cmd := range r.cmds { switch { @@ -110,7 +118,7 @@ func (r *Runner) run() error { cmd, params := r.args[0], r.args[1:] switch { case cmd == "help": - r.cfg.Usage(r.cfg.AppName, r.cmds) + r.cfg.Usage(r.cfg, r.cmds) return nil case cmd == "version": fmt.Printf("%s version: %s\n", r.cfg.AppName, r.cfg.Version) @@ -124,3 +132,27 @@ func (r *Runner) run() error { } return fmt.Errorf("no such command %q", cmd) } + +var defaultUsage = func(cfg Config, cmds []Command) { + if cfg.AppDescription != "" { + fmt.Fprintf(os.Stderr, "%s\n\n", cfg.AppDescription) + } + + fmt.Fprintf(os.Stderr, "Usage:\n\n %s [arguments]\n\nThe commands are:\n\n", cfg.AppName) + printCommands(cmds) + + if cfg.Version != "" { + fmt.Fprintf(os.Stderr, "Version: %s\n\n", cfg.Version) + } +} + +// printCommands in a table form (Name and Description) +func printCommands(cmds []Command) { + minwidth, tabwidth, padding, padchar, flags := 0, 0, 11, byte(' '), uint(0) + tw := tabwriter.NewWriter(os.Stderr, minwidth, tabwidth, padding, padchar, flags) + for _, cmd := range cmds { + fmt.Fprintf(tw, " %s\t%s\n", cmd.Name, cmd.Description) + } + fmt.Fprint(tw, "\n") + tw.Flush() +}