Split examples and fix tree

Signed-off-by: jolheiser <john.olheiser@gmail.com>
main v0.0.1
jolheiser 2021-10-30 16:47:47 -05:00
parent 34293148d7
commit 2b03d73292
Signed by: jolheiser
GPG Key ID: B853ADA5DA7BBF7A
10 changed files with 202 additions and 148 deletions

View File

@ -0,0 +1,8 @@
# Examples
Each directory contains a sample flagset/command setup and the resulting
generated docs.
- [flagset](flagset) - Using only stdlib `flag.FlagSet`
- [single](single) - Using a single `ffcli.Command`
- [multiple](multiple) - Using `ffcli.Command` with multiple sub-commands

View File

@ -1,55 +0,0 @@
# myapp
myapp
```
myapp
```
```
[--help]
[--myapp-bool-flag-f]
[--myapp-bool-flag-t]
[--myapp-duration-flag]=[value]
[--myapp-duration-flag-default]=[value]
[--myapp-int-flag]=[value]
[--myapp-int-flag-default]=[value]
[--myapp-string-flag]=[value]
[--myapp-string-flag-default]=[value]
```
**Usage**:
```
myapp [FLAGS] [ARGS...]
```
**--help**: Show help
**--myapp-bool-flag-f**: Bool flag false
**--myapp-bool-flag-t**: Bool flag true (default: `true`)
**--myapp-duration-flag**="": Duration flag with no default
**--myapp-duration-flag-default**="": Duration flag with default (default: `5m0s`)
**--myapp-int-flag**="": Int flag with no default
**--myapp-int-flag-default**="": Int flag with default (default: `100`)
**--myapp-string-flag**="": String flag with no default
**--myapp-string-flag-default**="": String flag with default (default: `string default`)
-----

View File

@ -0,0 +1,44 @@
//go:build generate
// +build generate
package main
import (
"flag"
"os"
"time"
"go.jolheiser.com/ffmd"
)
//go:generate go run main.go
func main() {
fs := flag.NewFlagSet("myapp", flag.ExitOnError)
fs.String("string-flag", "", "String flag with no default")
fs.String("string-flag-default", "string default", "String flag with default")
fs.Int("int-flag", 0, "Int flag with no default")
fs.Int("int-flag-default", 100, "Int flag with default")
fs.Bool("bool-flag-f", false, "Bool flag false")
fs.Bool("bool-flag-t", true, "Bool flag true")
fs.Duration("duration-flag", 0, "Duration flag with no default")
fs.Duration("duration-flag-default", time.Minute*5, "Duration flag with default")
md, err := ffmd.FromFlagSet(fs)
if err != nil {
panic(err)
}
write("flagset.md", md)
}
func write(path, content string) {
fi, err := os.Create(path)
if err != nil {
panic(err)
}
defer fi.Close()
if _, err := fi.WriteString(content); err != nil {
panic(err)
}
}

View File

@ -14,59 +14,8 @@ import (
"go.jolheiser.com/ffmd" "go.jolheiser.com/ffmd"
) )
//go:generate go run examples.go //go:generate go run main.go
func main() { func main() {
fs := flagSet("")
md, err := ffmd.FromFlagSet(fs)
if err != nil {
panic(err)
}
write("flagset.md", md)
command()
commandSub()
}
func write(path, content string) {
fi, err := os.Create(path)
if err != nil {
panic(err)
}
defer fi.Close()
if _, err := fi.WriteString(content); err != nil {
panic(err)
}
}
func flagSet(name string) *flag.FlagSet {
fs := flag.NewFlagSet("myapp", flag.ExitOnError)
fs.String(fmt.Sprintf("%sstring-flag", name), "", "String flag with no default")
fs.String(fmt.Sprintf("%sstring-flag-default", name), "string default", "String flag with default")
fs.Int(fmt.Sprintf("%sint-flag", name), 0, "Int flag with no default")
fs.Int(fmt.Sprintf("%sint-flag-default", name), 100, "Int flag with default")
fs.Bool(fmt.Sprintf("%sbool-flag-f", name), false, "Bool flag false")
fs.Bool(fmt.Sprintf("%sbool-flag-t", name), true, "Bool flag true")
fs.Duration(fmt.Sprintf("%sduration-flag", name), 0, "Duration flag with no default")
fs.Duration(fmt.Sprintf("%sduration-flag-default", name), time.Minute*5, "Duration flag with default")
return fs
}
func command() {
fs1 := flagSet("myapp-")
cmd1 := &ffcli.Command{
Name: "myapp",
FlagSet: fs1,
Subcommands: nil,
}
md, err := ffmd.FromCommand(cmd1)
if err != nil {
panic(err)
}
write("command.md", md)
}
func commandSub() {
fs := flagSet("myapp-") fs := flagSet("myapp-")
cmd := &ffcli.Command{ cmd := &ffcli.Command{
Name: "myapp", Name: "myapp",
@ -119,3 +68,27 @@ func commandSub() {
} }
write("command-sub.md", md) write("command-sub.md", md)
} }
func write(path, content string) {
fi, err := os.Create(path)
if err != nil {
panic(err)
}
defer fi.Close()
if _, err := fi.WriteString(content); err != nil {
panic(err)
}
}
func flagSet(name string) *flag.FlagSet {
fs := flag.NewFlagSet("myapp", flag.ExitOnError)
fs.String(fmt.Sprintf("%sstring-flag", name), "", "String flag with no default")
fs.String(fmt.Sprintf("%sstring-flag-default", name), "string default", "String flag with default")
fs.Int(fmt.Sprintf("%sint-flag", name), 0, "Int flag with no default")
fs.Int(fmt.Sprintf("%sint-flag-default", name), 100, "Int flag with default")
fs.Bool(fmt.Sprintf("%sbool-flag-f", name), false, "Bool flag false")
fs.Bool(fmt.Sprintf("%sbool-flag-t", name), true, "Bool flag true")
fs.Duration(fmt.Sprintf("%sduration-flag", name), 0, "Duration flag with no default")
fs.Duration(fmt.Sprintf("%sduration-flag-default", name), time.Minute*5, "Duration flag with default")
return fs
}

View File

@ -0,0 +1,50 @@
//go:build generate
// +build generate
package main
import (
"flag"
"os"
"time"
"github.com/peterbourgon/ff/v3/ffcli"
"go.jolheiser.com/ffmd"
)
//go:generate go run main.go
func main() {
fs := flag.NewFlagSet("myapp", flag.ExitOnError)
fs.String("string-flag", "", "String flag with no default")
fs.String("string-flag-default", "string default", "String flag with default")
fs.Int("int-flag", 0, "Int flag with no default")
fs.Int("int-flag-default", 100, "Int flag with default")
fs.Bool("bool-flag-f", false, "Bool flag false")
fs.Bool("bool-flag-t", true, "Bool flag true")
fs.Duration("duration-flag", 0, "Duration flag with no default")
fs.Duration("duration-flag-default", time.Minute*5, "Duration flag with default")
cmd := &ffcli.Command{
Name: "myapp",
FlagSet: fs,
Subcommands: nil,
}
md, err := ffmd.FromCommand(cmd)
if err != nil {
panic(err)
}
write("single.md", md)
}
func write(path, content string) {
fi, err := os.Create(path)
if err != nil {
panic(err)
}
defer fi.Close()
if _, err := fi.WriteString(content); err != nil {
panic(err)
}
}

View File

@ -0,0 +1,55 @@
# myapp
myapp
```
myapp
```
```
[--bool-flag-f]
[--bool-flag-t]
[--duration-flag]=[value]
[--duration-flag-default]=[value]
[--help]
[--int-flag]=[value]
[--int-flag-default]=[value]
[--string-flag]=[value]
[--string-flag-default]=[value]
```
**Usage**:
```
myapp [FLAGS] [ARGS...]
```
**--bool-flag-f**: Bool flag false
**--bool-flag-t**: Bool flag true (default: `true`)
**--duration-flag**="": Duration flag with no default
**--duration-flag-default**="": Duration flag with default (default: `5m0s`)
**--help**: Show help
**--int-flag**="": Int flag with no default
**--int-flag-default**="": Int flag with default (default: `100`)
**--string-flag**="": String flag with no default
**--string-flag-default**="": String flag with default (default: `string default`)
-----

View File

@ -1 +0,0 @@
package ffmd

48
tree.go
View File

@ -2,49 +2,27 @@ package ffmd
import ( import (
"fmt" "fmt"
"github.com/peterbourgon/ff/v3/ffcli"
"sort" "sort"
"strings" "strings"
"github.com/peterbourgon/ff/v3/ffcli"
) )
// Tree returns a tree-representation of a ffcli.Command // Tree returns a tree-representation of a ffcli.Command
func Tree(cmd *ffcli.Command) string { func Tree(cmd *ffcli.Command) string {
t := tree{} t := tree{cmd.Name: commandTree(cmd)}
for _, path := range commandPaths(cmd, "") {
t.add(path)
}
s := t.String(true, "") s := t.String(true, "")
return strings.TrimSpace(s) return strings.TrimSpace(s)
} }
func commandPaths(cmd *ffcli.Command, path string) []string {
root := fmt.Sprintf("%s%s", path, cmd.Name)
s := []string{root}
for _, sub := range cmd.Subcommands {
s = append(s, commandPaths(sub, root+"/")...)
}
sort.SliceStable(s, func(i, j int) bool {
return s[i] < s[j]
})
return s
}
type tree map[string]tree type tree map[string]tree
func (t tree) add(path string) { func commandTree(cmd *ffcli.Command) tree {
t.addParts(strings.Split(path, "/")) t := tree{}
for _, sub := range cmd.Subcommands {
t[sub.Name] = commandTree(sub)
} }
return t
func (t tree) addParts(parts []string) {
if len(parts) == 0 {
return
}
next, ok := t[parts[0]]
if !ok {
next = tree{}
t[parts[0]] = next
}
next.addParts(parts[1:])
} }
func (t tree) keys() []string { func (t tree) keys() []string {
@ -61,8 +39,10 @@ func (t tree) String(root bool, padding string) string {
index := 0 index := 0
for _, k := range t.keys() { for _, k := range t.keys() {
v := t[k] v := t[k]
s.WriteString(fmt.Sprintf("%s%s\n", padding+pipePad(root, pipe(index, len(t))), k)) p := pipe(index, len(t))
s.WriteString(v.String(false, padding+pipePad(root, outerPipe(index, len(t))))) s.WriteString(fmt.Sprintf("%s%s\n", padding+pipePad(root, p), k))
op := outerPipe(index, len(t))
s.WriteString(v.String(false, padding+pipePad(root, op)))
index++ index++
} }
return s.String() return s.String()
@ -70,10 +50,10 @@ func (t tree) String(root bool, padding string) string {
func pipe(index int, len int) string { func pipe(index int, len int) string {
switch { switch {
case index+1 == len:
return "└─"
case index+1 > len: case index+1 > len:
return " " return " "
case index+1 == len:
return "└─"
default: default:
return "├─" return "├─"
} }