diff --git a/examples/alias/README.md b/examples/alias/README.md new file mode 100644 index 0000000..fc42d12 --- /dev/null +++ b/examples/alias/README.md @@ -0,0 +1,39 @@ +# myapp + +myapp + +``` +myapp +``` + + +``` +[--bool-flag,-bf] +[--duration-flag,-df]=[value] +[--help] +[--int-flag,-if]=[value] +[--string-flag,-sf]=[value] +``` +**Usage**: + +``` +myapp [FLAGS] [ARGS...] +``` + +**--bool-flag,-bf**: Bool flag + + +**--duration-flag,-df**="": Duration flag + + +**--help**: Show help + + +**--int-flag,-if**="": Int flag + + +**--string-flag,-sf**="": String flag + + +----- + diff --git a/examples/alias/main.go b/examples/alias/main.go new file mode 100644 index 0000000..7214dab --- /dev/null +++ b/examples/alias/main.go @@ -0,0 +1,48 @@ +//go:build generate +// +build generate + +package main + +import ( + "flag" + "github.com/peterbourgon/ff/v3/ffcli" + "os" + + "go.jolheiser.com/ffmd" +) + +//go:generate go run main.go +func main() { + fs := flag.NewFlagSet("myapp", flag.ExitOnError) + stringFlag := fs.String("string-flag", "", "String flag") + fs.StringVar(stringFlag, "sf", *stringFlag, "--string-flag") + intFlag := fs.Int("int-flag", 0, "Int flag") + fs.IntVar(intFlag, "if", *intFlag, "--int-flag") + boolFlag := fs.Bool("bool-flag", false, "Bool flag") + fs.BoolVar(boolFlag, "bf", *boolFlag, "--bool-flag") + durFlag := fs.Duration("duration-flag", 0, "Duration flag") + fs.DurationVar(durFlag, "df", *durFlag, "--duration-flag") + + cmd := &ffcli.Command{ + Name: "myapp", + FlagSet: fs, + Subcommands: nil, + } + + md, err := ffmd.Command(cmd) + if err != nil { + panic(err) + } + write("README.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) + } +} diff --git a/ffmd.go b/ffmd.go index 1b7d0a7..4ec24a3 100644 --- a/ffmd.go +++ b/ffmd.go @@ -3,6 +3,7 @@ package ffmd import ( "bytes" _ "embed" + "errors" "flag" "fmt" "reflect" @@ -30,6 +31,9 @@ func FlagSet(fs *flag.FlagSet) (string, error) { } func fromCommand(cmd *ffcli.Command, section int) (string, error) { + if cmd.FlagSet == nil { + return "", errors.New("all commands should have a flagset, even if empty") + } c := flagSetCommand(cmd.FlagSet, section) c.Name = cmd.Name c.Usage = fmt.Sprintf("%s [FLAGS] [ARGS...]", cmd.Name) @@ -77,19 +81,33 @@ func flagSetCommand(fs *flag.FlagSet, section int) command { }, }, } + aliases := make(map[string][]string) fs.VisitAll(func(f *flag.Flag) { _, isBool := f.Value.(boolFlag) def := f.DefValue if isZeroValue(f, def) { def = "" } - a.Flags = append(a.Flags, appFlag{ + af := appFlag{ Name: f.Name, Usage: f.Usage, Default: def, IsBool: isBool, - }) + } + if strings.HasPrefix(af.Usage, "--") { + aliasOf := strings.TrimPrefix(af.Usage, "--") + if _, ok := aliases[aliasOf]; !ok { + aliases[aliasOf] = make([]string, 0) + } + aliases[aliasOf] = append(aliases[aliasOf], af.Name) + return + } + a.Flags = append(a.Flags, af) }) + for idx, f := range a.Flags { + f.Aliases = aliases[f.Name] + a.Flags[idx] = f + } sort.Slice(a.Flags, func(i, j int) bool { return a.Flags[i].Name < a.Flags[j].Name }) @@ -119,11 +137,20 @@ func (c command) Markdown() (string, error) { type appFlag struct { Name string + Aliases []string Usage string Default string IsBool bool } +func (a appFlag) AllNames() string { + names := []string{"--" + a.Name} + for _, alias := range a.Aliases { + names = append(names, "-"+alias) + } + return strings.Join(names, ",") +} + // From stdlib func isZeroValue(f *flag.Flag, value string) bool { diff --git a/ffmd.tmpl b/ffmd.tmpl index 1139971..eb7c852 100644 --- a/ffmd.tmpl +++ b/ffmd.tmpl @@ -10,7 +10,7 @@ {{end}} ```{{range $flag := .Flags}} -[--{{$flag.Name}}]{{if not $flag.IsBool}}=[value]{{end}} +[{{$flag.AllNames}}]{{if not $flag.IsBool}}=[value]{{end}} {{- end}} ``` {{- if .Usage}} @@ -22,5 +22,5 @@ {{- end -}} {{range $flag := .Flags}} -**--{{$flag.Name}}**{{if not $flag.IsBool}}=""{{end}}: {{$flag.Usage}}{{if $flag.Default}} (default: `{{$flag.Default}}`){{end}} +**{{$flag.AllNames}}**{{if not $flag.IsBool}}=""{{end}}: {{$flag.Usage}}{{if $flag.Default}} (default: `{{$flag.Default}}`){{end}} {{end}} \ No newline at end of file