Skip to content

Commit cb037ea

Browse files
committed
improve code generator for new CLI
1 parent d43c00c commit cb037ea

10 files changed

Lines changed: 282 additions & 112 deletions

File tree

pkg/cli/docs.go

Lines changed: 163 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ func (c *Command) GenMarkdown(dir string) error {
2222
return err
2323
}
2424

25+
err = c.Flags().Visit(func(flag *Flag) error {
26+
if len(flag.Examples) == 0 {
27+
return nil
28+
}
29+
return writeFlag(flag, dir)
30+
})
31+
if err != nil {
32+
return err
33+
}
34+
2535
return nil
2636
}
2737

@@ -41,7 +51,7 @@ func writeCommand(c *Command, f *os.File) error {
4151
}
4252

4353
if c.Use != "" {
44-
use := fmt.Sprintf("```bash\n%s\n```\n\n", c.Use)
54+
use := fmt.Sprintf("```bash\n%s\n```", c.Use)
4555
if _, err := f.WriteString(fmt.Sprintf("## Usage\n\n%s\n\n", use)); err != nil {
4656
return err
4757
}
@@ -64,20 +74,92 @@ func writeCommand(c *Command, f *os.File) error {
6474
return nil
6575
}
6676

77+
func writeFlag(f *Flag, dir string) error {
78+
basename := f.Name + markdownExtension
79+
filename := filepath.Join(dir, basename)
80+
w, err := os.Create(filename)
81+
if err != nil {
82+
return err
83+
}
84+
defer w.Close()
85+
86+
if _, err = w.WriteString(fmt.Sprintf("# %s\n\n", f.Name)); err != nil {
87+
return err
88+
}
89+
90+
if f.Description != "" {
91+
if _, err = w.WriteString(fmt.Sprintf("%s\n\n", f.Description)); err != nil {
92+
return err
93+
}
94+
} else {
95+
if _, err = w.WriteString(fmt.Sprintf("%s\n\n", f.Usage)); err != nil {
96+
return err
97+
}
98+
}
99+
100+
if _, err = w.WriteString("## Examples\n\n"); err != nil {
101+
return err
102+
}
103+
104+
for _, example := range f.Examples {
105+
if example.Title != "" {
106+
if _, err = w.WriteString(fmt.Sprintf("### %s\n\n", example.Title)); err != nil {
107+
return err
108+
}
109+
}
110+
111+
if example.Description != "" {
112+
if _, err = w.WriteString(fmt.Sprintf("%s\n\n", example.Description)); err != nil {
113+
return err
114+
}
115+
}
116+
117+
for _, code := range example.Codes {
118+
var s string
119+
if code.Title != "" {
120+
s = fmt.Sprintf("```bash tab=%s\n%s\n```\n", code.Title, code.Source)
121+
} else {
122+
s = fmt.Sprintf("```bash\n%s\n```\n", code)
123+
}
124+
if _, err = w.WriteString(s); err != nil {
125+
return err
126+
}
127+
}
128+
if _, err = w.WriteString("\n"); err != nil {
129+
return err
130+
}
131+
}
132+
133+
if len(f.Aliases) > 0 {
134+
if _, err = w.WriteString(fmt.Sprintf("## Aliases\n\n")); err != nil {
135+
return err
136+
}
137+
138+
for _, alias := range f.Aliases {
139+
if _, err = w.WriteString(fmt.Sprintf("- %s", alias)); err != nil {
140+
return err
141+
}
142+
}
143+
144+
}
145+
146+
return nil
147+
}
148+
67149
type flagGroup struct {
68-
Group string
69-
Subgroup string
70-
Flags []*Flag
150+
Group string
151+
Subgroups []flagGroup
152+
Flags []*Flag
71153
}
72154

73-
func groupFlags(flags *FlagSet) ([]flagGroup, error) {
155+
func groupFlags(flags *FlagSet) ([]*flagGroup, error) {
74156
type key struct {
75157
group string
76158
subgroup string
77159
}
78160

79161
mFlags := map[*Flag]bool{}
80-
flagList := []*Flag{}
162+
var flagList []*Flag
81163
_ = flags.Visit(func(flag *Flag) error {
82164
_, ok := mFlags[flag]
83165
if !ok {
@@ -89,69 +171,111 @@ func groupFlags(flags *FlagSet) ([]flagGroup, error) {
89171

90172
m := map[key][]*Flag{}
91173
var order []key
92-
var groups []flagGroup
93174

94175
for _, f := range flagList {
95176
g, sg := splitFlagName(f.Name)
96177
k := key{g, sg}
178+
if _, ok := m[k]; !ok {
179+
order = append(order, k)
180+
}
97181
m[k] = append(m[k], f)
98-
order = append(order, k)
99182
}
100183

184+
var groups []*flagGroup
185+
var currentGroup *flagGroup
101186
for _, k := range order {
102-
groups = append(groups, flagGroup{
103-
Group: k.group,
104-
Subgroup: k.subgroup,
105-
Flags: m[k],
106-
})
187+
if currentGroup == nil || currentGroup.Group != k.group {
188+
currentGroup = &flagGroup{Group: k.group}
189+
if k.subgroup == "" {
190+
currentGroup.Flags = m[k]
191+
}
192+
groups = append(groups, currentGroup)
193+
}
194+
if k.subgroup != "" {
195+
currentGroup.Subgroups = append(currentGroup.Subgroups, flagGroup{
196+
Group: k.subgroup,
197+
Flags: m[k],
198+
})
199+
}
107200
}
108201

109202
return groups, nil
110203
}
111204

112-
func renderFlagGroup(groups []flagGroup) (string, error) {
205+
func renderFlagGroup(groups []*flagGroup) (string, error) {
113206
var sb strings.Builder
114-
currentGroup := ""
115207
for _, g := range groups {
116208

117-
if g.Group != currentGroup {
118-
if _, err := sb.WriteString(fmt.Sprintf("### %s\n\n", g.Group)); err != nil {
209+
if len(g.Flags) == 0 && len(g.Subgroups) == 1 {
210+
sub := g.Subgroups[0]
211+
sb.WriteString(fmt.Sprintf("### %s-%s\n\n", g.Group, sub.Group))
212+
s, err := renderFlags(sub.Flags)
213+
if err != nil {
119214
return "", err
120215
}
121-
currentGroup = g.Group
216+
sb.WriteString(s)
217+
continue
122218
}
123219

124-
if g.Subgroup != "" {
125-
if _, err := sb.WriteString(fmt.Sprintf("#### %s\n\n", g.Subgroup)); err != nil {
220+
if len(g.Flags) > 0 {
221+
sb.WriteString(fmt.Sprintf("### %s\n\n", g.Group))
222+
s, err := renderFlags(g.Flags)
223+
if err != nil {
126224
return "", err
127225
}
226+
sb.WriteString(s)
128227
}
129228

130-
if _, err := sb.WriteString(`| Flag | Shorthand | Type | Default | Usage |
131-
|------|-----------|------|---------|-------|
132-
`,
133-
); err != nil {
134-
return "", err
135-
}
136-
for _, flag := range g.Flags {
137-
short := flag.Shorthand
138-
if short == "" {
139-
short = "-"
140-
} else {
141-
short = "-" + short
229+
for _, sub := range g.Subgroups {
230+
if len(sub.Flags) == 0 {
231+
continue
142232
}
143-
defaultValue := "-"
144-
if flag.DefaultValue != nil && flag.DefaultValue != "" {
145-
defaultValue = fmt.Sprintf("%v", flag.DefaultValue)
233+
234+
if sub.Group != "" {
235+
sb.WriteString(fmt.Sprintf("#### %s\n\n", sub.Group))
146236
}
147-
if _, err := sb.WriteString(fmt.Sprintf("| --%s | %s | %s | %s | %s |\n", flag.Name, short, flag.Value.Type(), defaultValue, flag.Usage)); err != nil {
237+
238+
s, err := renderFlags(sub.Flags)
239+
if err != nil {
148240
return "", err
149241
}
242+
sb.WriteString(s)
243+
}
244+
}
245+
246+
return sb.String(), nil
247+
}
248+
249+
func renderFlags(flags []*Flag) (string, error) {
250+
var sb strings.Builder
251+
if _, err := sb.WriteString(`| Flag | Shorthand | Type | Default | Usage |
252+
|------|-----------|------|---------|-------|
253+
`,
254+
); err != nil {
255+
return "", err
256+
}
257+
for _, flag := range flags {
258+
short := flag.Shorthand
259+
if short == "" {
260+
short = "-"
261+
} else {
262+
short = "-" + short
263+
}
264+
defaultValue := "-"
265+
if flag.DefaultValue != nil && flag.DefaultValue != "" {
266+
defaultValue = fmt.Sprintf("%v", flag.DefaultValue)
150267
}
151-
if _, err := sb.WriteString("\n"); err != nil {
268+
name := flag.Name
269+
if flag.Examples != nil {
270+
name = fmt.Sprintf("[%s](./%s.md)", name, name)
271+
}
272+
if _, err := sb.WriteString(fmt.Sprintf("| --%s | %s | %s | %s | %s |\n", name, short, flag.Value.Type(), defaultValue, flag.Usage)); err != nil {
152273
return "", err
153274
}
154275
}
276+
if _, err := sb.WriteString("\n"); err != nil {
277+
return "", err
278+
}
155279

156280
return sb.String(), nil
157281
}
@@ -162,6 +286,8 @@ func splitFlagName(name string) (group, subgroup string) {
162286
switch len(parts) {
163287
case 1:
164288
return "General", ""
289+
case 2:
290+
return fmt.Sprintf("%s", caser.String(parts[0])), ""
165291
default:
166292
return caser.String(parts[0]), caser.String(parts[1])
167293
}

pkg/cli/dynamic.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import (
88
var regexIndex = regexp.MustCompile(`\[<.*>]`)
99
var regexKey = regexp.MustCompile(`<.*>`)
1010

11-
func (fs *FlagSet) DynamicInt(name string, usage string) {
11+
func (fs *FlagSet) DynamicInt(name string, usage string) *FlagBuilder {
1212
f := &DynamicFlag{
13-
Usage: usage,
13+
Flag: Flag{Usage: usage},
1414
pattern: convertToPattern(name),
1515
setValue: func(name string, value []string) error {
1616
f, ok := fs.flags[name]
@@ -28,11 +28,12 @@ func (fs *FlagSet) DynamicInt(name string, usage string) {
2828
},
2929
}
3030
fs.dynamic = append(fs.dynamic, f)
31+
return &FlagBuilder{flag: &f.Flag}
3132
}
3233

33-
func (fs *FlagSet) DynamicString(name string, usage string) {
34+
func (fs *FlagSet) DynamicString(name string, usage string) *FlagBuilder {
3435
f := &DynamicFlag{
35-
Usage: usage,
36+
Flag: Flag{Usage: usage},
3637
pattern: convertToPattern(name),
3738
setValue: func(name string, value []string) error {
3839
f, ok := fs.flags[name]
@@ -50,11 +51,12 @@ func (fs *FlagSet) DynamicString(name string, usage string) {
5051
},
5152
}
5253
fs.dynamic = append(fs.dynamic, f)
54+
return &FlagBuilder{flag: &f.Flag}
5355
}
5456

55-
func (fs *FlagSet) DynamicStringSlice(name string, usage string, explode bool) {
57+
func (fs *FlagSet) DynamicStringSlice(name string, usage string, explode bool) *FlagBuilder {
5658
f := &DynamicFlag{
57-
Usage: usage,
59+
Flag: Flag{Usage: usage},
5860
pattern: convertToPattern(name),
5961
setValue: func(name string, value []string) error {
6062
f, ok := fs.flags[name]
@@ -72,6 +74,7 @@ func (fs *FlagSet) DynamicStringSlice(name string, usage string, explode bool) {
7274
},
7375
}
7476
fs.dynamic = append(fs.dynamic, f)
77+
return &FlagBuilder{flag: &f.Flag}
7578
}
7679

7780
func convertToPattern(s string) *regexp.Regexp {

pkg/cli/flag_bool.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,15 @@ func (b *boolFlag) String() string {
4242
return fmt.Sprintf("%v", b.value)
4343
}
4444

45-
func (fs *FlagSet) Bool(name string, defaultValue bool, usage string) {
46-
fs.BoolShort(name, "", defaultValue, usage)
45+
func (fs *FlagSet) Bool(name string, defaultValue bool, usage string) *FlagBuilder {
46+
return fs.BoolShort(name, "", defaultValue, usage)
4747
}
4848

49-
func (fs *FlagSet) BoolShort(name string, short string, defaultValue bool, usage string) {
49+
func (fs *FlagSet) BoolShort(name string, short string, defaultValue bool, usage string) *FlagBuilder {
5050
v := &boolFlag{value: defaultValue}
5151
f := &Flag{Value: v, Name: name, Shorthand: short, Usage: usage, DefaultValue: defaultValue}
5252
fs.setFlag(f)
53+
return &FlagBuilder{flag: f}
5354
}
5455

5556
func (fs *FlagSet) GetBool(name string) bool {

pkg/cli/flag_file.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ func (f *fileFlag) String() string {
3232
return fmt.Sprintf("%v", f.value)
3333
}
3434

35-
func (fs *FlagSet) File(name string, usage string) {
35+
func (fs *FlagSet) File(name string, usage string) *FlagBuilder {
3636
v := &fileFlag{setConfigFile: fs.setConfigFile}
3737
f := &Flag{Name: name, Value: v, Usage: usage}
3838
fs.setFlag(f)
39+
return &FlagBuilder{flag: f}
3940
}

pkg/cli/flag_float.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,15 @@ func (f *floatFlag) String() string {
4141
return fmt.Sprintf("%f", f.value)
4242
}
4343

44-
func (fs *FlagSet) Float(name string, defaultValue float64, usage string) {
45-
fs.FloatShort(name, "", defaultValue, usage)
44+
func (fs *FlagSet) Float(name string, defaultValue float64, usage string) *FlagBuilder {
45+
return fs.FloatShort(name, "", defaultValue, usage)
4646
}
4747

48-
func (fs *FlagSet) FloatShort(name string, short string, defaultValue float64, usage string) {
48+
func (fs *FlagSet) FloatShort(name string, short string, defaultValue float64, usage string) *FlagBuilder {
4949
v := &floatFlag{value: defaultValue}
5050
f := &Flag{Name: name, Shorthand: short, Value: v, Usage: usage, DefaultValue: defaultValue}
5151
fs.setFlag(f)
52+
return &FlagBuilder{flag: f}
5253
}
5354

5455
func (fs *FlagSet) GetFloat(name string) float64 {

pkg/cli/flag_int.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,15 @@ func (f *intFlag) String() string {
4646
return fmt.Sprintf("%d", f.value)
4747
}
4848

49-
func (fs *FlagSet) Int(name string, defaultValue int, usage string) {
50-
fs.IntShort(name, "", defaultValue, usage)
49+
func (fs *FlagSet) Int(name string, defaultValue int, usage string) *FlagBuilder {
50+
return fs.IntShort(name, "", defaultValue, usage)
5151
}
5252

53-
func (fs *FlagSet) IntShort(name string, short string, defaultValue int, usage string) {
53+
func (fs *FlagSet) IntShort(name string, short string, defaultValue int, usage string) *FlagBuilder {
5454
v := &intFlag{value: defaultValue}
5555
f := &Flag{Name: name, Shorthand: short, Value: v, Usage: usage, DefaultValue: defaultValue}
5656
fs.setFlag(f)
57+
return &FlagBuilder{flag: f}
5758
}
5859

5960
func (fs *FlagSet) GetInt(name string) int {

0 commit comments

Comments
 (0)