package wand import ( "fmt" "github.com/iancoleman/strcase" "io" "sort" "strings" ) func formatHelp(out io.Writer, doc doc) error { printf, println, finish := printer(out) printf(escapeTeletype(doc.fullCommand)) println() if doc.hasImplementation || doc.synopsis.hasSubcommands { println() printf("Synopsis") println() } if doc.hasImplementation { println() printf(escapeTeletype(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("...") 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) } } println() } if doc.synopsis.hasSubcommands { println() printf("%s [options or args...]", escapeTeletype(doc.synopsis.command)) println() println() printf("(For the details about the available subcommands, see the related section below.)") println() } if doc.description != "" { println() printf(escapeTeletype(paragraphs(doc.description))) println() } if len(doc.options) > 0 { println() printf("Options") if doc.hasBoolOptions || doc.hasListOptions { println() if doc.hasBoolOptions { println() printf("[b]: booelan flag, true or false, or no argument means true") } if doc.hasListOptions { println() printf("[*]: accepts multiple instances of the same option") } } println() println() names, od := prepareOptions(doc.options) 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", escapeTeletype(lines(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, escapeTeletype(doc.name), sc.name) } else if sc.hasHelpOption { d = fmt.Sprintf("%s - For help, see: %s %s --help", d, escapeTeletype(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", escapeTeletype(paragraphs(cd[n]))) } println() } } if len(doc.options) > 0 && commandNameExpression.MatchString(doc.appName) { println("Environment Variables") println() printf(escapeTeletype(paragraphs(envDocs))) println() println() o := doc.options[0] printf("Example environment variable:") println() println() printf(strcase.ToSnake(fmt.Sprintf("%s-%s", doc.appName, o.name))) printf("=") if o.isBool { printf("true") } else { printf("42") } println() } if len(doc.options) > 0 && len(doc.configFiles) > 0 { println("Configuration Files") println() printf(escapeTeletype(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) printf(":") println() printf(strcase.ToSnake(o.name)) printf(" = ") if o.isBool { printf("true") } else { printf("42") } println() println() printf("Example for discarding an inherited entry:") println() println() printf("# discarding an inherited entry:") println() printf(strcase.ToSnake(o.name)) println() } return finish() }