1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
package cli
import (
"bytes"
"regexp"
"strings"
"github.com/mitchellh/cli"
"github.com/mitchellh/go-glint"
)
// formatHelp takes a raw help string and attempts to colorize it automatically.
func formatHelp(v string) string {
// Trim the empty space
v = strings.TrimSpace(v)
var buf bytes.Buffer
d := glint.New()
d.SetRenderer(&glint.TerminalRenderer{
Output: &buf,
// We set rows/cols here manually. The important bit is the cols
// needs to be wide enough so glint doesn't clamp any text and
// lets the terminal just autowrap it. Rows doesn't make a big
// difference.
Rows: 10,
Cols: 180,
})
for _, line := range strings.Split(v, "\n") {
// Usage: prefix lines
prefix := "Usage: "
if strings.HasPrefix(line, prefix) {
d.Append(glint.Layout(
glint.Style(
glint.Text(prefix),
glint.Color("lightMagenta"),
),
glint.Text(line[len(prefix):]),
).Row())
continue
}
// Alias: prefix lines
prefix = "Alias: "
if strings.HasPrefix(line, prefix) {
d.Append(glint.Layout(
glint.Style(
glint.Text(prefix),
glint.Color("lightMagenta"),
),
glint.Text(line[len(prefix):]),
).Row())
continue
}
// A header line
if reHelpHeader.MatchString(line) {
d.Append(glint.Style(
glint.Text(line),
glint.Bold(),
))
continue
}
// If we have a command in the line, then highlight that.
if matches := reCommand.FindAllStringIndex(line, -1); len(matches) > 0 {
var cs []glint.Component
idx := 0
for _, match := range matches {
start := match[0] + 1
end := match[1] - 1
cs = append(
cs,
glint.Text(line[idx:start]),
glint.Style(
glint.Text(line[start:end]),
glint.Color("lightMagenta"),
),
)
idx = end
}
// Add the rest of the text
cs = append(cs, glint.Text(line[idx:]))
d.Append(glint.Layout(cs...).Row())
continue
}
// Normal line
d.Append(glint.Text(line))
}
d.RenderFrame()
return buf.String()
}
type helpCommand struct {
SynopsisText string
HelpText string
}
func (c *helpCommand) Run(args []string) int {
return cli.RunResultHelp
}
func (c *helpCommand) Synopsis() string {
return strings.TrimSpace(c.SynopsisText)
}
func (c *helpCommand) Help() string {
if c.HelpText == "" {
return c.SynopsisText
}
return formatHelp(c.HelpText)
}
func (c *helpCommand) HelpTemplate() string {
return formatHelp(helpTemplate)
}
var (
reHelpHeader = regexp.MustCompile(`^[a-zA-Z0-9_-].*:$`)
reCommand = regexp.MustCompile(`"vagrant \w+"`)
)
const helpTemplate = `
Usage: {{.Name}} {{.SubcommandName}} SUBCOMMAND
{{indent 2 (trim .Help)}}{{if gt (len .Subcommands) 0}}
Subcommands:
{{- range $value := .Subcommands }}
{{ $value.NameAligned }} {{ $value.Synopsis }}{{ end }}
{{- end }}
`
|