wand/formathelp.go

240 lines
4.7 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"
)
2025-08-26 03:21:35 +02:00
func formatHelp(out io.Writer, doc doc) error {
printf, println, finish := printer(out)
printf(escapeTeletype(doc.fullCommand))
2025-08-24 04:46:54 +02:00
println()
if doc.hasImplementation || doc.synopsis.hasSubcommands {
println()
printf("Synopsis")
println()
}
if doc.hasImplementation {
println()
2025-08-26 03:21:35 +02:00
printf(escapeTeletype(doc.synopsis.command))
2025-08-24 04:46:54 +02:00
if doc.synopsis.hasOptions {
2025-08-26 03:21:35 +02:00
printf(" [options...]")
2025-08-24 04:46:54 +02:00
}
2025-08-26 03:21:35 +02:00
for i := range doc.synopsis.arguments.names {
printf(
" [%s %s]",
doc.synopsis.arguments.names[i],
doc.synopsis.arguments.types[i],
)
2025-08-24 04:46:54 +02:00
}
if doc.synopsis.arguments.variadic {
printf("...")
2025-08-26 03:21:35 +02:00
min := doc.synopsis.arguments.minPositional
max := doc.synopsis.arguments.maxPositional
switch {
case min > 0 && max > 0:
printf("\nmin %d and max %d total positional arguments", min, max)
case min > 0:
printf("\nmin %d total positional arguments", min)
case max > 0:
printf("\nmax %d total positional arguments", max)
2025-08-24 04:46:54 +02:00
}
}
println()
}
if doc.synopsis.hasSubcommands {
2025-08-26 03:21:35 +02:00
println()
printf("%s <subcommand> [options or args...]", escapeTeletype(doc.synopsis.command))
2025-08-24 04:46:54 +02:00
println()
println()
2025-08-26 03:21:35 +02:00
printf("(For the details about the available subcommands, see the related section below.)")
2025-08-24 04:46:54 +02:00
println()
}
2025-08-26 03:21:35 +02:00
if doc.description != "" {
2025-08-24 04:46:54 +02:00
println()
2025-08-26 03:21:35 +02:00
printf(escapeTeletype(paragraphs(doc.description)))
2025-08-24 04:46:54 +02:00
println()
}
if len(doc.options) > 0 {
println()
printf("Options")
2025-08-26 03:21:35 +02:00
if doc.hasBoolOptions || doc.hasListOptions {
println()
if doc.hasBoolOptions {
println()
printf("[b]: booelan flag, true or false, or no argument means true")
2025-08-24 04:46:54 +02:00
}
2025-08-26 03:21:35 +02:00
if doc.hasListOptions {
println()
printf("[*]: accepts multiple instances of the same option")
2025-08-24 04:46:54 +02:00
}
}
2025-08-26 03:21:35 +02:00
println()
println()
names, od := prepareOptions(doc.options)
2025-08-24 04:46:54 +02:00
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), " ")
2025-08-26 03:21:35 +02:00
names[i] = fmt.Sprintf("%s:%s", names[i], pad)
2025-08-24 04:46:54 +02:00
}
for _, n := range names {
printf(n)
if od[n] != "" {
2025-08-26 03:21:35 +02:00
printf(" %s", escapeTeletype(lines(od[n])))
2025-08-24 04:46:54 +02:00
}
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 {
2025-08-26 03:21:35 +02:00
d = fmt.Sprintf("%s - For help, see: %s %s help", d, escapeTeletype(doc.name), sc.name)
2025-08-24 04:46:54 +02:00
} else if sc.hasHelpOption {
2025-08-26 03:21:35 +02:00
d = fmt.Sprintf("%s - For help, see: %s %s --help", d, escapeTeletype(doc.name), sc.name)
2025-08-24 04:46:54 +02:00
}
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] != "" {
2025-08-26 03:21:35 +02:00
printf(": %s", escapeTeletype(paragraphs(cd[n])))
2025-08-24 04:46:54 +02:00
}
println()
}
}
2025-08-26 03:21:35 +02:00
if len(doc.options) > 0 && commandNameExpression.MatchString(doc.appName) {
println("Environment Variables")
println()
printf(escapeTeletype(paragraphs(envDocs)))
2025-08-24 04:46:54 +02:00
println()
println()
o := doc.options[0]
printf("Example environment variable:")
println()
println()
2025-08-26 03:21:35 +02:00
printf(strcase.ToSnake(fmt.Sprintf("%s-%s", doc.appName, o.name)))
2025-08-24 04:46:54 +02:00
printf("=")
if o.isBool {
printf("true")
} else {
printf("42")
}
println()
}
if len(doc.options) > 0 && len(doc.configFiles) > 0 {
2025-08-26 03:21:35 +02:00
println("Configuration Files")
println()
printf(escapeTeletype(paragraphs(configDocs)))
2025-08-24 04:46:54 +02:00
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)
2025-08-26 03:21:35 +02:00
printf(":")
2025-08-24 04:46:54 +02:00
println()
printf(strcase.ToSnake(o.name))
printf(" = ")
if o.isBool {
printf("true")
} else {
printf("42")
}
println()
2025-08-26 03:21:35 +02:00
println()
printf("Example for discarding an inherited entry:")
println()
println()
printf("# discarding an inherited entry:")
println()
printf(strcase.ToSnake(o.name))
println()
2025-08-24 04:46:54 +02:00
}
2025-08-26 03:21:35 +02:00
return finish()
2025-08-24 04:46:54 +02:00
}