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
|
package command
import (
"flag"
"fmt"
"sort"
"strings"
wordwrap "github.com/mitchellh/go-wordwrap"
"github.com/ryanuber/columnize"
)
// AutoHelp specifies the necessary methods required to have their help
// completely generated for them.
type AutoHelp interface {
Usage() string
Description() string
InitOpts()
VisitAllFlags(func(f *flag.Flag))
}
// MakeHelp generates a help string based on the capabilities of the Command
func MakeHelp(c AutoHelp) string {
usageText := c.Usage()
// If the length of Usage() is zero, then assume this is a hidden
// command.
if len(usageText) == 0 {
return ""
}
descriptionText := wordwrap.WrapString(c.Description(), 60)
descrLines := strings.Split(descriptionText, "\n")
prefixedLines := make([]string, len(descrLines))
for i := range descrLines {
prefixedLines[i] = " " + descrLines[i]
}
descriptionText = strings.Join(prefixedLines, "\n")
c.InitOpts()
flags := []*flag.Flag{}
c.VisitAllFlags(func(f *flag.Flag) {
flags = append(flags, f)
})
optionsText := OptionsHelpOutput(flags)
var helpOutput string
switch {
case len(optionsText) == 0 && len(descriptionText) == 0:
helpOutput = usageText
case len(optionsText) == 0:
helpOutput = fmt.Sprintf(`Usage: %s
%s`,
usageText, descriptionText)
case len(descriptionText) == 0 && len(optionsText) > 0:
helpOutput = fmt.Sprintf(`Usage: %s
Options:
%s`,
usageText, optionsText)
default:
helpOutput = fmt.Sprintf(`Usage: %s
%s
Options:
%s`,
usageText, descriptionText, optionsText)
}
return strings.TrimSpace(helpOutput)
}
// ByOptName implements sort.Interface for flag.Flag based on the Name field.
type ByName []*flag.Flag
func (a ByName) Len() int { return len(a) }
func (a ByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByName) Less(i, j int) bool {
// Bubble up single-char args to the top of the list
switch {
case len(a[i].Name) == 1 && len(a[j].Name) != 1:
return true
case len(a[i].Name) != 1 && len(a[j].Name) == 1:
return false
default:
// Case-insensitive sort. Use case as a tie breaker, however.
a1 := strings.ToLower(a[i].Name)
a2 := strings.ToLower(a[j].Name)
if a1 == a2 {
return a[i].Name < a[j].Name
} else {
return a1 < a2
}
}
}
// OptionsHelpOutput returns a string of formatted options
func OptionsHelpOutput(flags []*flag.Flag) string {
sort.Sort(ByName(flags))
var output []string
for _, f := range flags {
if len(f.Usage) == 0 {
continue
}
output = append(output, fmt.Sprintf("-%s | %s", f.Name, f.Usage))
}
optionsOutput := columnize.Format(output, &columnize.Config{
Delim: "|",
Glue: " ",
Prefix: " ",
Empty: "",
})
return optionsOutput
}
|