afd0ecbbf2
Drop support for Go 1.11 Use md2man v2 to avoid dependency issues when building with Go Modules Enabled Update TravisCI build environment images (trusty was deprecated) Add optional Windows build
146 lines
3.1 KiB
Go
146 lines
3.1 KiB
Go
package cli
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"sort"
|
|
"strings"
|
|
"text/template"
|
|
|
|
"github.com/cpuguy83/go-md2man/v2/md2man"
|
|
)
|
|
|
|
// ToMarkdown creates a markdown string for the `*App`
|
|
// The function errors if either parsing or writing of the string fails.
|
|
func (a *App) ToMarkdown() (string, error) {
|
|
var w bytes.Buffer
|
|
if err := a.writeDocTemplate(&w); err != nil {
|
|
return "", err
|
|
}
|
|
return w.String(), nil
|
|
}
|
|
|
|
// ToMan creates a man page string for the `*App`
|
|
// The function errors if either parsing or writing of the string fails.
|
|
func (a *App) ToMan() (string, error) {
|
|
var w bytes.Buffer
|
|
if err := a.writeDocTemplate(&w); err != nil {
|
|
return "", err
|
|
}
|
|
man := md2man.Render(w.Bytes())
|
|
return string(man), nil
|
|
}
|
|
|
|
type cliTemplate struct {
|
|
App *App
|
|
Commands []string
|
|
GlobalArgs []string
|
|
SynopsisArgs []string
|
|
}
|
|
|
|
func (a *App) writeDocTemplate(w io.Writer) error {
|
|
const name = "cli"
|
|
t, err := template.New(name).Parse(MarkdownDocTemplate)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return t.ExecuteTemplate(w, name, &cliTemplate{
|
|
App: a,
|
|
Commands: prepareCommands(a.Commands, 0),
|
|
GlobalArgs: prepareArgsWithValues(a.Flags),
|
|
SynopsisArgs: prepareArgsSynopsis(a.Flags),
|
|
})
|
|
}
|
|
|
|
func prepareCommands(commands []Command, level int) []string {
|
|
coms := []string{}
|
|
for i := range commands {
|
|
command := &commands[i]
|
|
usage := ""
|
|
if command.Usage != "" {
|
|
usage = command.Usage
|
|
}
|
|
|
|
prepared := fmt.Sprintf("%s %s\n\n%s\n",
|
|
strings.Repeat("#", level+2),
|
|
strings.Join(command.Names(), ", "),
|
|
usage,
|
|
)
|
|
|
|
flags := prepareArgsWithValues(command.Flags)
|
|
if len(flags) > 0 {
|
|
prepared += fmt.Sprintf("\n%s", strings.Join(flags, "\n"))
|
|
}
|
|
|
|
coms = append(coms, prepared)
|
|
|
|
// recursevly iterate subcommands
|
|
if len(command.Subcommands) > 0 {
|
|
coms = append(
|
|
coms,
|
|
prepareCommands(command.Subcommands, level+1)...,
|
|
)
|
|
}
|
|
}
|
|
|
|
return coms
|
|
}
|
|
|
|
func prepareArgsWithValues(flags []Flag) []string {
|
|
return prepareFlags(flags, ", ", "**", "**", `""`, true)
|
|
}
|
|
|
|
func prepareArgsSynopsis(flags []Flag) []string {
|
|
return prepareFlags(flags, "|", "[", "]", "[value]", false)
|
|
}
|
|
|
|
func prepareFlags(
|
|
flags []Flag,
|
|
sep, opener, closer, value string,
|
|
addDetails bool,
|
|
) []string {
|
|
args := []string{}
|
|
for _, f := range flags {
|
|
flag, ok := f.(DocGenerationFlag)
|
|
if !ok {
|
|
continue
|
|
}
|
|
modifiedArg := opener
|
|
for _, s := range strings.Split(flag.GetName(), ",") {
|
|
trimmed := strings.TrimSpace(s)
|
|
if len(modifiedArg) > len(opener) {
|
|
modifiedArg += sep
|
|
}
|
|
if len(trimmed) > 1 {
|
|
modifiedArg += fmt.Sprintf("--%s", trimmed)
|
|
} else {
|
|
modifiedArg += fmt.Sprintf("-%s", trimmed)
|
|
}
|
|
}
|
|
modifiedArg += closer
|
|
if flag.TakesValue() {
|
|
modifiedArg += fmt.Sprintf("=%s", value)
|
|
}
|
|
|
|
if addDetails {
|
|
modifiedArg += flagDetails(flag)
|
|
}
|
|
|
|
args = append(args, modifiedArg+"\n")
|
|
|
|
}
|
|
sort.Strings(args)
|
|
return args
|
|
}
|
|
|
|
// flagDetails returns a string containing the flags metadata
|
|
func flagDetails(flag DocGenerationFlag) string {
|
|
description := flag.GetUsage()
|
|
value := flag.GetValue()
|
|
if value != "" {
|
|
description += " (default: " + value + ")"
|
|
}
|
|
return ": " + description
|
|
}
|