/
usage.go
156 lines (138 loc) · 3.25 KB
/
usage.go
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
145
146
147
148
149
150
151
152
153
154
155
156
package cmdline
import (
"fmt"
"io"
"strings"
"github.com/gregoryv/nexus"
)
// type Usage is for documenting the configured parser
type Usage struct {
*Parser
preface strings.Builder
examples strings.Builder
}
// Preface adds lines just before the options section
func (me *Usage) Preface(lines ...string) {
for _, line := range lines {
me.preface.WriteString(line)
me.preface.WriteString("\n")
}
}
// Example adds an examples section. The examples are placed last
// after options and named arguments. Examples are plain text and not
// evaluated in any way.
func (me *Usage) Example(lines ...string) {
for _, line := range lines {
if me.examples.Len() > 0 {
me.examples.WriteString("\n")
}
me.examples.WriteString(indent)
me.examples.WriteString(line)
}
}
// WriteUsageTo writes names, defaults and documentation to the given
// writer with the first line being
//
// Usage: COMMAND [OPTIONS] ARGUMENTS...
func (me *Usage) WriteTo(w io.Writer) (int64, error) {
p, err := nexus.NewPrinter(w)
p.Printf("Usage: %s [OPTIONS]", me.args[0])
// Named arguments
for _, arg := range me.arguments {
if arg.required {
p.Printf(" %s", arg.name)
continue
}
p.Printf(" [%s]", arg.name)
}
// Preface
p.Print("\n\n")
me.writePreface(p)
// Options
p.Println("Options")
me.WriteOptionsTo(p)
if len(me.options) > 0 {
fmt.Fprintln(w)
}
me.writeGroups(p)
me.writeExamples(p)
p.Println()
return p.Written, *err
}
const indent = " "
func (me *Usage) writeGroups(p *nexus.Printer) {
if len(me.groups) == 0 {
return
}
for _, grp := range me.groups {
p.Println(grp.Title())
first := grp.Items()[0]
writeItem(p, first, me.args, indent, true)
for _, item := range grp.Items()[1:] {
writeItem(p, item, me.args, indent, false)
}
}
}
// WriteOptionsTo writes the Options section to the given writer.
func (me *Usage) WriteOptionsTo(w io.Writer) {
me.writeOptionsTo(w, "")
}
func (me *Usage) writePreface(p *nexus.Printer) {
if me.preface.Len() == 0 {
return
}
p.Println(me.preface.String())
}
func (me *Usage) writeExamples(p *nexus.Printer) {
if me.examples.Len() == 0 {
return
}
if len(me.groups) > 0 {
p.Println()
}
p.Println("Examples")
p.Print(me.examples.String())
}
func (me *Usage) writeOptionsTo(w io.Writer, indent string) {
for _, opt := range me.options {
writeOptionTo(w, opt, indent)
}
}
func writeItem(w io.Writer, me *Item, args []string, indent string, dflt bool) {
if dflt {
fmt.Fprintf(w, "%s%s (default)\n", indent, me.Name)
} else {
fmt.Fprintf(w, "%s%s\n", indent, me.Name)
}
extra := NewParser()
extra.args = args
me.Load(extra)
extra.Usage().writeOptionsTo(w, indent)
}
func writeOptionTo(w io.Writer, opt *Option, indent string) {
var def string
val := opt.defaultValue
if opt.hidden {
val = "********"
}
if val != "" {
def = fmt.Sprintf(" : %v", val)
}
if opt.quoteValue {
def = fmt.Sprintf(" : %q", val)
}
var enum string
if len(opt.enumerated) > 0 {
enum = fmt.Sprintf(" %v", opt.enumerated)
}
fmt.Fprintf(w, "%s %s%s%v\n", indent, opt.names, def, enum)
writeDocTo(w, opt, indent)
}
func writeDocTo(w io.Writer, opt *Option, indent string) {
if len(opt.doc) > 0 {
for _, line := range opt.doc {
fmt.Fprintf(w, "%s %s\n", indent, line)
}
fmt.Fprintln(w)
}
}