2025-08-24 04:46:54 +02:00
|
|
|
package wand
|
|
|
|
|
|
2025-08-26 03:21:35 +02:00
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"github.com/iancoleman/strcase"
|
|
|
|
|
"io"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func header(level int) string {
|
|
|
|
|
s := make([]string, level+2)
|
|
|
|
|
return strings.Join(s, "#")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func formatMarkdownCommand(printf func(string, ...any), println func(...any), doc doc, level int) {
|
|
|
|
|
printf("%s Synopsis\n\n", header(level))
|
|
|
|
|
println("```")
|
|
|
|
|
printf(doc.synopsis.command)
|
|
|
|
|
if doc.synopsis.hasOptions {
|
|
|
|
|
printf(" [options...]")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := range doc.synopsis.arguments.names {
|
|
|
|
|
printf(
|
|
|
|
|
" [%s %s]",
|
|
|
|
|
doc.synopsis.arguments.names[i],
|
|
|
|
|
doc.synopsis.arguments.types[i],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if doc.synopsis.arguments.variadic {
|
|
|
|
|
printf("...")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
println()
|
|
|
|
|
println("```")
|
|
|
|
|
|
|
|
|
|
min := doc.synopsis.arguments.minPositional
|
|
|
|
|
max := doc.synopsis.arguments.maxPositional
|
|
|
|
|
if doc.synopsis.arguments.variadic {
|
|
|
|
|
if min > 0 || max > 0 {
|
|
|
|
|
println()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch {
|
|
|
|
|
case min > 0 && max > 0:
|
|
|
|
|
printf("min %d and max %d total positional arguments\n", min, max)
|
|
|
|
|
case min > 0:
|
|
|
|
|
printf("min %d total positional arguments\n", min)
|
|
|
|
|
case max > 0:
|
|
|
|
|
printf("max %d total positional arguments\n", max)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if doc.synopsis.hasSubcommands {
|
|
|
|
|
println()
|
|
|
|
|
println("```")
|
|
|
|
|
for _, sc := range doc.subcommands {
|
|
|
|
|
printf("%s %s\n", escapeMD(doc.name), sc.name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
println("```")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if doc.description != "" {
|
|
|
|
|
printf("\n%s Description\n\n", header(level))
|
|
|
|
|
println(escapeMD(paragraphs(doc.description)))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(doc.options) > 0 {
|
|
|
|
|
printf("\n%s Options\n\n", header(level))
|
|
|
|
|
if doc.hasBoolOptions {
|
|
|
|
|
printf("- [b]: booelan flag, true or false, or no argument means true\n")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if doc.hasListOptions {
|
|
|
|
|
printf("- [*]: accepts multiple instances of the same option\n")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if doc.hasBoolOptions || doc.hasListOptions {
|
|
|
|
|
println()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
names, descriptions := prepareOptions(doc.options)
|
|
|
|
|
for _, n := range names {
|
|
|
|
|
printf("- **%s**: %s\n", escapeMD(n), escapeMD(lines(descriptions[n])))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(doc.options) > 0 && commandNameExpression.MatchString(doc.appName) {
|
|
|
|
|
printf("\n.%s Environment Variables\n\n", header(level))
|
|
|
|
|
println(escapeMD(paragraphs(envDocs)))
|
|
|
|
|
println()
|
|
|
|
|
println("Example environment variable:")
|
|
|
|
|
println()
|
|
|
|
|
o := doc.options[0]
|
|
|
|
|
println("```")
|
|
|
|
|
printf(strcase.ToSnake(fmt.Sprintf("%s-%s", doc.appName, o.name)))
|
|
|
|
|
printf("=")
|
|
|
|
|
if o.isBool {
|
|
|
|
|
printf("true")
|
|
|
|
|
} else {
|
|
|
|
|
printf("42")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
println()
|
|
|
|
|
println("```")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(doc.options) > 0 && len(doc.configFiles) > 0 {
|
|
|
|
|
printf("\n.Configuration Files\n\n")
|
|
|
|
|
println(escapeMD(paragraphs(configDocs)))
|
|
|
|
|
println()
|
|
|
|
|
println("Config files:")
|
|
|
|
|
println()
|
|
|
|
|
for _, cf := range doc.configFiles {
|
|
|
|
|
if cf.fromOption {
|
|
|
|
|
println("- zero or more configuration files defined by the --config option\n")
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cf.fn != "" {
|
|
|
|
|
printf("- %s", cf.fn)
|
|
|
|
|
if cf.optional {
|
|
|
|
|
printf(" (optional)")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
println()
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
println()
|
|
|
|
|
println("Example configuration entry:")
|
|
|
|
|
println()
|
|
|
|
|
o := doc.options[0]
|
|
|
|
|
println("```")
|
|
|
|
|
printf("# default for --%s:\n", o.name)
|
|
|
|
|
printf(strcase.ToSnake(o.name))
|
|
|
|
|
printf(" = ")
|
|
|
|
|
if o.isBool {
|
|
|
|
|
printf("true")
|
|
|
|
|
} else {
|
|
|
|
|
printf("42")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
println()
|
|
|
|
|
println("```")
|
|
|
|
|
println()
|
|
|
|
|
println("Example for discarding an inherited entry:")
|
|
|
|
|
println()
|
|
|
|
|
println("```")
|
|
|
|
|
println("# discarding an inherited entry:")
|
|
|
|
|
println(strcase.ToSnake(o.name))
|
|
|
|
|
println("```")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func formatMarkdownMultiCommand(out io.Writer, doc doc, level int) error {
|
|
|
|
|
printf, println, finish := printer(out)
|
|
|
|
|
printf("%s %s\n\n", header(level), escapeMD(doc.appName))
|
|
|
|
|
println("Provides several commands:")
|
|
|
|
|
println()
|
|
|
|
|
allCommands := allCommands(doc)
|
|
|
|
|
for _, c := range allCommands {
|
|
|
|
|
printf("- %s\n", escapeMD(c.fullCommand))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
println()
|
|
|
|
|
for _, c := range allCommands {
|
|
|
|
|
printf("%s %s\n\n", header(level+1), escapeMD(c.fullCommand))
|
|
|
|
|
formatMarkdownCommand(printf, println, c, level+2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return finish()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func formatMarkdownSingleCommand(out io.Writer, doc doc, level int) error {
|
|
|
|
|
printf, println, finish := printer(out)
|
|
|
|
|
printf("%s %s\n\n", header(level), doc.appName)
|
|
|
|
|
formatMarkdownCommand(printf, println, doc, level+1)
|
|
|
|
|
return finish()
|
|
|
|
|
}
|
2025-08-24 04:46:54 +02:00
|
|
|
|
|
|
|
|
func formatMarkdown(out io.Writer, doc doc, level int) error {
|
2025-08-26 03:21:35 +02:00
|
|
|
var hasSubcommands bool
|
|
|
|
|
for _, sc := range doc.subcommands {
|
|
|
|
|
if !sc.isHelp && !sc.isVersion {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hasSubcommands = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if hasSubcommands {
|
|
|
|
|
return formatMarkdownMultiCommand(out, doc, level)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return formatMarkdownSingleCommand(out, doc, level)
|
2025-08-24 04:46:54 +02:00
|
|
|
}
|