From f760960f649b5fb04689346bc8186c6f849c8883 Mon Sep 17 00:00:00 2001 From: inhere Date: Sat, 27 Feb 2021 10:09:35 +0800 Subject: [PATCH] update some for command help render --- app.go | 68 +++++++++++++++++++++++++++---------------------------- base.go | 15 ++++++------ cmd.go | 44 +++++++++++++++++++++++++++++++---- define.go | 9 ++++++-- 4 files changed, 88 insertions(+), 48 deletions(-) diff --git a/app.go b/app.go index 15d85e9..2bea912 100644 --- a/app.go +++ b/app.go @@ -265,7 +265,7 @@ func (app *App) parseGlobalOpts(args []string) (ok bool) { color.Enable = false } - Debugf("global option parsed, verbose level: %d(%s)", gOpts.verbose, gOpts.verbose.String()) + Debugf("global option parsed, verbose level: %s", gOpts.verbose.String()) app.args = app.GlobalFlags().FSetArgs() // TODO show auto-completion for bash/zsh @@ -288,13 +288,8 @@ func (app *App) prepareRun() (code int, name string) { return } - var cmds []string - if isValidCmdName(app.args[0]) { - cmds = []string{app.args[0]} - } - // like 'help COMMAND' - code = app.showCommandHelp(cmds) + code = app.showCommandHelp(app.args) return } @@ -346,11 +341,11 @@ func (app *App) findCommandName(args []string) (name string) { // check first arg is valid name string. if isValidCmdName(name) { + app.args = args[1:] // update args. realName := app.ResolveAlias(name) // is valid command name. if app.IsCommand(realName) { - app.args = args[1:] // update args. app.inputName = name Debugf("input command: '%s', real command: '%s'", name, realName) } @@ -404,7 +399,7 @@ func (app *App) Run(args []string) (code int) { } func (app *App) doRunCmd(name string, args []string) (code int) { - cmd := app.Command(name) + cmd := app.GetCommand(name) app.fireEvent(EvtAppBefore, cmd.Copy()) Debugf("will run command '%s' with args: %v", name, args) @@ -460,6 +455,7 @@ func (app *App) Exec(name string, args []string) (err error) { return fmt.Errorf("exec unknown command name '%s'", name) } + Debugf("manual exec the application command: %s", name) cmd := app.commands[name] // parse flags and execute command @@ -501,23 +497,6 @@ func (app *App) fireEvent(event string, data interface{}) { * display app help *************************************************************/ -// AppHelpTemplate help template for app(all commands) -var AppHelpTemplate = `{{.Desc}} (Version: {{.Version}}) -Usage: - {$binName} [global Options...] COMMAND [--option ...] [argument ...] - {$binName} [global Options...] COMMAND [--option ...] SUB-COMMAND [--option ...] [argument ...] - -Global Options: -{{.GOpts}} -Available Commands:{{range $module, $cs := .Cs}}{{if $module}} - {{ $module }}{{end}}{{ range $cs }} - {{.Name | paddingName }} {{.Desc}}{{if .Aliases}} (alias: {{ join .Aliases ","}}){{end}}{{end}}{{end}} - - {{ paddingName "help" }} Display help information - -Use "{$binName} {COMMAND} -h" for more information about a command -` - // display app version info func (app *App) showVersionInfo() { Debugf("print application version info") @@ -545,14 +524,29 @@ func (app *App) showCommandTips(name string) { color.Printf("\nUse %s --help to see available commands\n", app.binName) } -// display app help and list all commands +// AppHelpTemplate help template for app(all commands) +var AppHelpTemplate = `{{.Desc}} (Version: {{.Version}}) +Usage: + {$binName} [global Options...] COMMAND [--option ...] [argument ...] + {$binName} [global Options...] COMMAND [--option ...] SUB-COMMAND [--option ...] [argument ...] + +Global Options: +{{.GOpts}} +Available Commands:{{range $cmdName, $c := .Cs}} + {{$c.Name | paddingName }} {{$c.Desc}}{{if $c.Aliases}} (alias: {{ join $c.Aliases ","}}){{end}}{{end}} + {{ paddingName "help" }} Display help information + +Use "{$binName} {COMMAND} -h" for more information about a command +` + +// display app help and list all commands. showCommandList() func (app *App) showApplicationHelp() { - Debugf("render application commands list") + Debugf("render application help and commands list") // cmdHelpTemplate = color.ReplaceTag(cmdHelpTemplate) // render help text template s := helper.RenderText(AppHelpTemplate, map[string]interface{}{ - "Cs": app.moduleCommands, + "Cs": app.commands, "GOpts": app.gFlags.String(), // app version "Version": app.Version, @@ -571,26 +565,32 @@ func (app *App) showApplicationHelp() { // showCommandHelp display help for an command func (app *App) showCommandHelp(list []string) (code int) { binName := app.binName - if len(list) != 1 { - color.Error.Tips("Too many arguments given.\n\nUsage: %s help {COMMAND}", binName) + if len(list) == 0 { + color.Error.Tips("Too many arguments given.\n\nUsage: %s help COMMAND", binName) return ERR } // get real name name := app.cmdAliases.ResolveAlias(list[0]) if name == HelpCommand || name == "-h" { + Debugf("render help command information") + color.Println("Display help message for application or command.\n") - color.Printf("Usage:\n %s {COMMAND} --help OR %s help {COMMAND}\n", binName, binName) + color.Printf(`Usage: + %s COMMAND --help + %s COMMAND SUB_COMMAND --help + %s help COMMAND +`, binName, binName, binName) return } cmd, exist := app.commands[name] if !exist { - color.Error.Prompt("Unknown command name '%s'. Run '%s -h' see all commands", name, binName) + color.Error.Prompt("Unknown command name '%s'. Run '%s -h' see all commands", name, binName) return ERR } - // show help for the command. + // show help for the give command. cmd.ShowHelp() return } diff --git a/base.go b/base.go index 7e86daa..e6ef202 100644 --- a/base.go +++ b/base.go @@ -61,11 +61,17 @@ func newCommandBase() commandBase { } } -// Command get an command by name -func (b commandBase) Command(name string) *Command { +// GetCommand get an command by name +func (b commandBase) GetCommand(name string) *Command { return b.commands[name] } +// Command get an command by name +func (b commandBase) Command(name string) (c *Command, exist bool) { + c, exist = b.commands[name] + return +} + // IsAlias name check func (b commandBase) IsAlias(alias string) bool { return b.cmdAliases.HasAlias(alias) @@ -172,11 +178,6 @@ func (b commandBase) MatchByPath(path string) *Command { return b.Match(names) } -// GetCommand get command by name. eg "sub" -func (b commandBase) GetCommand(name string) *Command { - return b.commands[name] -} - // SetLogo text and color style func (b commandBase) SetLogo(logo string, style ...string) { b.Logo.Text = logo diff --git a/cmd.go b/cmd.go index 94c685a..4f45fd2 100644 --- a/cmd.go +++ b/cmd.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "strings" + "text/template" "github.com/gookit/color" "github.com/gookit/gcli/v3/helper" @@ -467,16 +468,35 @@ func (c *Command) innerDispatch(args []string) (err error) { if name[0] != '-' { name = c.ResolveAlias(name) - // name is an sub command name? - if c.IsCommand(name) { - sub := c.Command(args[0]) - + // is valid sub command + if sub, has := c.Command(name); has { // loop find sub...command and run it. return sub.innerDispatch(args[1:]) } } } + // defaultCommand is not empty. + name := c.defaultCommand + if name != "" { + // is valid sub command + if sub, has := c.Command(name); has { + Debugf("will run the default command '%s' of the '%s'", name, c.Name) + + // run the default command + return sub.innerExecute(args, true) + } + + return fmt.Errorf("the default command '%s' is invalid", name) + } + + // not set command func and has sub commands. + if c.Func == nil && len(c.commands) > 0 { + Logf(VerbWarn, "cmd: %s - c.Func is empty, but has sub commands, will render help list", c.Name) + c.ShowHelp() + return err + } + // do execute command return c.doExecute(args) } @@ -537,6 +557,10 @@ func (c *Command) doExecute(args []string) (err error) { // do call command handler func if c.Func == nil { + // if len(c.commands) > 0 { + // c.Infoln("please input ") + // } + Logf(VerbWarn, "the command '%s' no handler func to running", c.Name) } else { // err := c.Func.Run(c, args) @@ -567,6 +591,9 @@ var CmdHelpTemplate = `{{.Desc}} {{.Options}}{{end}}{{if .Cmd.Args}} Arguments:{{range $a := .Cmd.Args}} {{$a.HelpName | printf "%-12s"}}{{$a.Desc | ucFirst}}{{if $a.Required}}*{{end}}{{end}} +{{end}}{{ if .Subs }} +Sub Commands:{{range $n,$c := .Subs}} + {{$c.Name | paddingName }} {{$c.Desc}}{{if $c.Aliases}} (alias: {{ join $c.Aliases ","}}){{end}}{{end}} {{end}}{{if .Cmd.Examples}} Examples: {{.Cmd.Examples}}{{end}}{{if .Cmd.Help}} @@ -575,6 +602,8 @@ var CmdHelpTemplate = `{{.Desc}} // ShowHelp show command help info func (c *Command) ShowHelp() { + Debugf("render command '%s' help information", c.Name) + // custom help render func if c.HelpRender != nil { c.HelpRender(c) @@ -594,13 +623,18 @@ func (c *Command) ShowHelp() { // render help message s := helper.RenderText(CmdHelpTemplate, map[string]interface{}{ "Cmd": c, + "Subs": c.commands, // global options "GOpts": c.gFlags.String(), // parse options to string "Options": c.Flags.String(), // always upper first char "Desc": c.Desc, - }, nil) + }, template.FuncMap{ + "paddingName": func(n string) string { + return strutil.PadRight(n, " ", c.nameMaxWidth) + }, + }) // parse help vars then print help color.Print(c.ReplaceVars(s)) diff --git a/define.go b/define.go index dedf7e7..93794d7 100644 --- a/define.go +++ b/define.go @@ -8,13 +8,18 @@ import ( type verbLevel uint +// String verbose level to string. +func (vl verbLevel) String() string { + return fmt.Sprintf("%d=%s", vl, vl.Name()) +} + // Upper verbose level to string. func (vl verbLevel) Upper() string { - return strings.ToUpper(vl.String()) + return strings.ToUpper(vl.Name()) } // String verbose level to string. -func (vl verbLevel) String() string { +func (vl verbLevel) Name() string { switch vl { case VerbQuiet: return "quiet"