wand/formathelp.go

253 lines
4.5 KiB
Go
Raw Normal View History

2025-08-24 04:46:54 +02:00
package wand
import (
"fmt"
"github.com/iancoleman/strcase"
"io"
"sort"
"strings"
)
func formatHelp(w io.Writer, doc doc) error {
var err error
println := func(a ...any) {
if err != nil {
return
}
_, err = fmt.Fprintln(w, a...)
}
printf := func(f string, a ...any) {
if err != nil {
return
}
_, err = fmt.Fprintf(w, f, a...)
}
printf(doc.fullCommand)
println()
if doc.hasImplementation || doc.synopsis.hasSubcommands {
println()
printf("Synopsis")
println()
}
if doc.hasImplementation {
println()
printf(doc.synopsis.command)
if doc.synopsis.hasOptions {
printf(" [options ...]")
}
for _, n := range doc.synopsis.arguments.names {
printf(" %s", n)
}
if doc.synopsis.arguments.variadic {
printf("...")
if doc.synopsis.arguments.minPositional > 0 {
printf(" min %d arguments", doc.synopsis.arguments.minPositional)
}
if doc.synopsis.arguments.maxPositional > 0 {
printf(" max %d arguments", doc.synopsis.arguments.maxPositional)
}
}
println()
}
if doc.synopsis.hasSubcommands {
if !doc.hasImplementation {
println()
}
printf("%s <subcommand> [options or args...]", doc.synopsis.command)
println()
println()
printf("(For the details about the available subcommands, see the according section below.)")
println()
}
if len(doc.description) > 0 {
println()
printf(paragraphs(doc.description))
println()
}
if len(doc.options) > 0 {
println()
printf("Options")
println()
println()
printf("[*]: accepts multiple instances of the same option")
println()
printf("[b]: booelan flag, true or false, or no argument means true")
println()
println()
var names []string
od := make(map[string]string)
for _, o := range doc.options {
ons := []string{fmt.Sprintf("--%s", o.name)}
for _, sn := range o.shortNames {
ons = append(ons, fmt.Sprintf("-%s", sn))
}
n := strings.Join(ons, ", ")
if o.acceptsMultiple {
n = fmt.Sprintf("%s [*]", n)
}
if o.isBool {
n = fmt.Sprintf("%s [b]", n)
}
names = append(names, n)
od[n] = o.description
}
sort.Strings(names)
var max int
for _, n := range names {
if len(n) > max {
max = len(n)
}
}
for i := range names {
pad := strings.Join(make([]string, max-len(names[i])+1), " ")
names[i] = fmt.Sprintf("%s%s", names[i], pad)
}
for _, n := range names {
printf(n)
if od[n] != "" {
printf(": %s", paragraphs(od[n]))
}
println()
}
}
if len(doc.subcommands) > 0 {
println()
printf("Subcommands")
println()
println()
var names []string
cd := make(map[string]string)
for _, sc := range doc.subcommands {
name := sc.name
if sc.isDefault {
name = fmt.Sprintf("%s (default)", name)
}
d := sc.description
if sc.isHelp {
d = fmt.Sprintf("Show this help. %s", d)
}
if sc.hasHelpSubcommand {
d = fmt.Sprintf("%s - For help, see: %s %s help", d, doc.name, sc.name)
} else if sc.hasHelpOption {
d = fmt.Sprintf("%s - For help, see: %s %s --help", d, doc.name, sc.name)
}
cd[name] = d
}
sort.Strings(names)
var max int
for _, n := range names {
if len(n) > max {
max = len(n)
}
}
for i := range names {
pad := strings.Join(make([]string, max-len(names[i])+1), " ")
names[i] = fmt.Sprintf("%s%s", names[i], pad)
}
for _, n := range names {
printf(n)
if cd[n] != "" {
printf(": %s", paragraphs(cd[n]))
}
println()
}
}
if len(doc.options) > 0 {
printf(paragraphs(envDocs))
println()
println()
o := doc.options[0]
printf("Example environment variable:")
println()
println()
printf(strcase.ToSnake(o.name))
printf("=")
if o.isBool {
printf("true")
} else {
printf("42")
}
println()
}
if len(doc.options) > 0 && len(doc.configFiles) > 0 {
printf(paragraphs(configDocs))
println()
println()
printf("Config files:")
println()
println()
for _, cf := range doc.configFiles {
if cf.fromOption {
printf("zero or more configuration files defined by the --config option")
println()
continue
}
if cf.fn != "" {
printf(cf.fn)
if cf.optional {
printf(" (optional)")
}
println()
continue
}
}
println()
o := doc.options[0]
printf("Example configuration entry:")
println()
println()
printf("# default for --")
printf(o.name)
println()
printf(strcase.ToSnake(o.name))
printf(" = ")
if o.isBool {
printf("true")
} else {
printf("42")
}
println()
}
return err
}