- help <command> and <command> --help print Description, Usage,
Arguments, Options with defaults, Global options, Help and Examples
- Command.Examples and Command.Hidden (appended, additive); list --all
shows hidden commands, list --format=json prints a bonfire.Listing
- CheckDocs reports commands lacking description, long help, examples or
argument and option descriptions
- Error block with the ERROR badge, WithHint explanation and Try lines
({bin} replaced), cobra suggestions as Try, -v error chain, messages
scrubbed by sunscreen; Reported errors print nothing and exit 1
126 lines
3.1 KiB
Go
126 lines
3.1 KiB
Go
package bonfire
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// helpUsage is the usage line of a command in help and the JSON listing:
|
|
// the name, its arguments and [options]; passthrough commands end with
|
|
// [--] <args...> because everything after the name reaches them unparsed.
|
|
func helpUsage(c Command) string {
|
|
u := commandUsage(c) + " [options]"
|
|
if c.Passthrough {
|
|
u += " [--] <args...>"
|
|
}
|
|
return u
|
|
}
|
|
|
|
// optionLabel is the left column of a flag: "-x, --name=NAME" for value
|
|
// flags, "--name" for bare flags, indented four spaces without shorthand.
|
|
func optionLabel(f Flag) string {
|
|
label := " "
|
|
if f.Shorthand != "" {
|
|
label = "-" + f.Shorthand + ", "
|
|
}
|
|
label += "--" + f.Name
|
|
if !f.Bare {
|
|
label += "=" + strings.ToUpper(strings.ReplaceAll(f.Name, "-", "_"))
|
|
}
|
|
return label
|
|
}
|
|
|
|
// optionDetail is a flag's description followed by its default and the
|
|
// repeatable marker.
|
|
func optionDetail(f Flag) string {
|
|
parts := []string{}
|
|
if f.Description != "" {
|
|
parts = append(parts, f.Description)
|
|
}
|
|
if f.Default != "" && !f.Bare {
|
|
if _, err := strconv.Atoi(f.Default); err == nil {
|
|
parts = append(parts, "[default: "+f.Default+"]")
|
|
} else {
|
|
parts = append(parts, "[default: "+strconv.Quote(f.Default)+"]")
|
|
}
|
|
}
|
|
if f.Repeatable {
|
|
parts = append(parts, "(multiple values allowed)")
|
|
}
|
|
return strings.Join(parts, " ")
|
|
}
|
|
|
|
// renderHelp writes a command's help in the Artisan layout: Description,
|
|
// Usage, Arguments, Options with defaults, Global options, Help (the long
|
|
// text) and Examples, each section present only when it has content.
|
|
func (st *rootState) renderHelp(c Command, g Globals) error {
|
|
p := DefaultPalette()
|
|
var b strings.Builder
|
|
section := func(title string) {
|
|
if b.Len() > 0 {
|
|
b.WriteString("\n")
|
|
}
|
|
b.WriteString(p.Header.Render(title+":") + "\n")
|
|
}
|
|
|
|
if c.Description != "" {
|
|
section("Description")
|
|
b.WriteString(" " + c.Description + "\n")
|
|
}
|
|
section("Usage")
|
|
b.WriteString(" " + helpUsage(c) + "\n")
|
|
|
|
width := 0
|
|
for _, a := range c.Args {
|
|
width = max(width, len(a.Name))
|
|
}
|
|
for _, f := range c.Flags {
|
|
width = max(width, len(optionLabel(f)))
|
|
}
|
|
row := func(label, detail string) {
|
|
line := " " + p.Success.Render(label)
|
|
if detail != "" {
|
|
line += strings.Repeat(" ", width-len(label)+2) + detail
|
|
}
|
|
b.WriteString(line + "\n")
|
|
}
|
|
if len(c.Args) > 0 {
|
|
section("Arguments")
|
|
for _, a := range c.Args {
|
|
row(a.Name, a.Description)
|
|
}
|
|
}
|
|
if len(c.Flags) > 0 {
|
|
section("Options")
|
|
for _, f := range c.Flags {
|
|
row(optionLabel(f), optionDetail(f))
|
|
}
|
|
}
|
|
section("Global options")
|
|
writeGlobalOptions(&b, p)
|
|
if long := strings.TrimSpace(c.Long); long != "" {
|
|
section("Help")
|
|
for _, line := range strings.Split(long, "\n") {
|
|
if strings.TrimSpace(line) == "" {
|
|
b.WriteString("\n")
|
|
continue
|
|
}
|
|
b.WriteString(" " + line + "\n")
|
|
}
|
|
}
|
|
if len(c.Examples) > 0 {
|
|
section("Examples")
|
|
bin := usageName(st.name)
|
|
for i, e := range c.Examples {
|
|
if i > 0 {
|
|
b.WriteString("\n")
|
|
}
|
|
if e.Description != "" {
|
|
b.WriteString(" " + p.Muted.Render("# "+e.Description) + "\n")
|
|
}
|
|
b.WriteString(" " + bin + " " + e.Command + "\n")
|
|
}
|
|
}
|
|
return writeStyled(st.out, g, b.String())
|
|
}
|