summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEyal Posener <[email protected]>2020-05-09 13:36:38 +0300
committerEyal Posener <[email protected]>2020-05-09 14:17:09 +0300
commit41182b029c6a536f917139a7e27be08cc3a50d23 (patch)
treea0b54d2e0790e20d300a0ff4e501e97268014a91
parente6d850dd6bc6aaecbaf5391412d1426fbb5ffaf5 (diff)
Autogenerate compflag code
-rw-r--r--compflag/compflag.go182
-rw-r--r--compflag/flags.go259
-rw-r--r--compflag/gen/flags.go.gotmpl83
-rw-r--r--compflag/gen/main.go67
4 files changed, 419 insertions, 172 deletions
diff --git a/compflag/compflag.go b/compflag/compflag.go
index fb1e852..2048c74 100644
--- a/compflag/compflag.go
+++ b/compflag/compflag.go
@@ -36,13 +36,11 @@ package compflag
import (
"flag"
- "fmt"
"os"
"strconv"
"time"
"github.com/posener/complete/v2"
- "github.com/posener/complete/v2/predict"
)
// FlagSet is bash completion enabled flag.FlagSet.
@@ -69,30 +67,6 @@ func (fs *FlagSet) Complete() {
complete.Complete(fs.Name(), complete.FlagSet((*flag.FlagSet)(CommandLine)))
}
-func (fs *FlagSet) String(name string, value string, usage string, options ...predict.Option) *string {
- p := new(string)
- (*flag.FlagSet)(fs).Var(newStringValue(value, p, predict.Options(options...)), name, usage)
- return p
-}
-
-func (fs *FlagSet) Bool(name string, value bool, usage string, options ...predict.Option) *bool {
- p := new(bool)
- (*flag.FlagSet)(fs).Var(newBoolValue(value, p, predict.Options(options...)), name, usage)
- return p
-}
-
-func (fs *FlagSet) Int(name string, value int, usage string, options ...predict.Option) *int {
- p := new(int)
- (*flag.FlagSet)(fs).Var(newIntValue(value, p, predict.Options(options...)), name, usage)
- return p
-}
-
-func (fs *FlagSet) Duration(name string, value time.Duration, usage string, options ...predict.Option) *time.Duration {
- p := new(time.Duration)
- (*flag.FlagSet)(fs).Var(newDurationValue(value, p, predict.Options(options...)), name, usage)
- return p
-}
-
var CommandLine = (*FlagSet)(flag.CommandLine)
// Parse parses command line arguments. It also performs bash completion when needed.
@@ -101,164 +75,28 @@ func Parse() {
CommandLine.Parse(os.Args[1:])
}
-func String(name string, value string, usage string, options ...predict.Option) *string {
- return CommandLine.String(name, value, usage, options...)
-}
-
-func Bool(name string, value bool, usage string, options ...predict.Option) *bool {
- return CommandLine.Bool(name, value, usage, options...)
-}
-
-func Int(name string, value int, usage string, options ...predict.Option) *int {
- return CommandLine.Int(name, value, usage, options...)
-}
-
-func Duration(name string, value time.Duration, usage string, options ...predict.Option) *time.Duration {
- return CommandLine.Duration(name, value, usage, options...)
-}
-
-type boolValue struct {
- v *bool
- predict.Config
-}
-
-func newBoolValue(val bool, p *bool, c predict.Config) *boolValue {
- *p = val
- return &boolValue{v: p, Config: c}
-}
-
-func (b *boolValue) Set(val string) error {
- v, err := strconv.ParseBool(val)
- *b.v = v
- if err != nil {
- return fmt.Errorf("bad value for bool flag")
- }
- return b.Check(val)
-}
-
-func (b *boolValue) Get() interface{} { return *b.v }
-
-func (b *boolValue) String() string {
- if b == nil || b.v == nil {
- return strconv.FormatBool(false)
- }
- return strconv.FormatBool(*b.v)
-}
-
-func (b *boolValue) IsBoolFlag() bool { return true }
-
-func (b *boolValue) Predict(prefix string) []string {
- if b.Predictor != nil {
- return b.Predictor.Predict(prefix)
- }
+func predictBool(value bool, prefix string) []string {
// If false, typing the bool flag is expected to turn it on, so there is nothing to complete
// after the flag.
- if !*b.v {
+ if !value {
return nil
}
// Otherwise, suggest only to turn it off.
return []string{"false"}
}
-type stringValue struct {
- v *string
- predict.Config
-}
+func parseString(s string) (string, error) { return s, nil }
-func newStringValue(val string, p *string, c predict.Config) *stringValue {
- *p = val
- return &stringValue{v: p, Config: c}
-}
+func formatString(v string) string { return v }
-func (s *stringValue) Set(val string) error {
- *s.v = val
- return s.Check(val)
-}
+func parseInt(s string) (int, error) { return strconv.Atoi(s) }
-func (s *stringValue) Get() interface{} {
- return *s.v
-}
-
-func (s *stringValue) String() string {
- if s == nil || s.v == nil {
- return ""
- }
- return *s.v
-}
-
-func (s *stringValue) Predict(prefix string) []string {
- if s.Predictor != nil {
- return s.Predictor.Predict(prefix)
- }
- return []string{""}
-}
-
-type intValue struct {
- v *int
- predict.Config
-}
-
-func newIntValue(val int, p *int, c predict.Config) *intValue {
- *p = val
- return &intValue{v: p, Config: c}
-}
+func formatInt(v int) string { return strconv.Itoa(v) }
-func (i *intValue) Set(val string) error {
- v, err := strconv.ParseInt(val, 0, strconv.IntSize)
- *i.v = int(v)
- if err != nil {
- return fmt.Errorf("bad value for int flag")
- }
- return i.Check(val)
-}
+func parseBool(s string) (bool, error) { return strconv.ParseBool(s) }
-func (i *intValue) Get() interface{} { return *i.v }
+func formatBool(v bool) string { return strconv.FormatBool(v) }
-func (i *intValue) String() string {
- if i == nil || i.v == nil {
- return strconv.Itoa(0)
- }
- return strconv.Itoa(*i.v)
-}
+func parseDuration(s string) (time.Duration, error) { return time.ParseDuration(s) }
-func (s *intValue) Predict(prefix string) []string {
- if s.Predictor != nil {
- return s.Predictor.Predict(prefix)
- }
- return []string{""}
-}
-
-type durationValue struct {
- v *time.Duration
- predict.Config
-}
-
-func newDurationValue(val time.Duration, p *time.Duration, c predict.Config) *durationValue {
- *p = val
- return &durationValue{v: p, Config: c}
-}
-
-func (i *durationValue) Set(val string) error {
- v, err := time.ParseDuration(val)
- *i.v = v
- if err != nil {
- return fmt.Errorf("bad value for duration flag")
- }
- return i.Check(val)
-}
-
-func (i *durationValue) Get() interface{} { return *i.v }
-
-func (i *durationValue) String() string {
- if i == nil || i.v == nil {
- return time.Duration(0).String()
- }
- return i.v.String()
-}
-
-func (s *durationValue) Predict(prefix string) []string {
- if s.Predictor != nil {
- return s.Predictor.Predict(prefix)
- }
- return []string{""}
-}
+func formatDuration(v time.Duration) string { return v.String() }
diff --git a/compflag/flags.go b/compflag/flags.go
new file mode 100644
index 0000000..91b413a
--- /dev/null
+++ b/compflag/flags.go
@@ -0,0 +1,259 @@
+package compflag
+
+import (
+ "flag"
+ "fmt"
+ "time"
+
+ "github.com/posener/complete/v2/predict"
+)
+
+// Code auto generated with `go run ./gen`. DO NOT EDIT
+
+//go:generate go run ./gen
+
+// String if a flag function for a flag of type string.
+func String(name string, value string, usage string, options ...predict.Option) *string {
+ return CommandLine.String(name, value, usage, options...)
+}
+
+// StringVar if a flag function for a flag of already exiting variable of type string.
+func StringVar(v *string, name string, value string, usage string, options ...predict.Option) {
+ CommandLine.StringVar(v, name, value, usage, options...)
+}
+
+// Bool if a flag function for a flag of type bool.
+func Bool(name string, value bool, usage string, options ...predict.Option) *bool {
+ return CommandLine.Bool(name, value, usage, options...)
+}
+
+// BoolVar if a flag function for a flag of already exiting variable of type bool.
+func BoolVar(v *bool, name string, value bool, usage string, options ...predict.Option) {
+ CommandLine.BoolVar(v, name, value, usage, options...)
+}
+
+// Int if a flag function for a flag of type int.
+func Int(name string, value int, usage string, options ...predict.Option) *int {
+ return CommandLine.Int(name, value, usage, options...)
+}
+
+// IntVar if a flag function for a flag of already exiting variable of type int.
+func IntVar(v *int, name string, value int, usage string, options ...predict.Option) {
+ CommandLine.IntVar(v, name, value, usage, options...)
+}
+
+// Duration if a flag function for a flag of type time.Duration.
+func Duration(name string, value time.Duration, usage string, options ...predict.Option) *time.Duration {
+ return CommandLine.Duration(name, value, usage, options...)
+}
+
+// DurationVar if a flag function for a flag of already exiting variable of type time.Duration.
+func DurationVar(v *time.Duration, name string, value time.Duration, usage string, options ...predict.Option) {
+ CommandLine.DurationVar(v, name, value, usage, options...)
+}
+
+// String if a flag function for a flag of type string.
+func (fs *FlagSet) String(name string, value string, usage string, options ...predict.Option) *string {
+ p := new(string)
+ fs.StringVar(p, name, value, usage, options...)
+ return p
+}
+
+// StringVar if a flag function for a flag of already exiting variable of type string.
+func (fs *FlagSet) StringVar(p *string, name string, value string, usage string, options ...predict.Option) {
+ (*flag.FlagSet)(fs).Var(newStringValue(value, p, predict.Options(options...)), name, usage)
+}
+
+// Bool if a flag function for a flag of type bool.
+func (fs *FlagSet) Bool(name string, value bool, usage string, options ...predict.Option) *bool {
+ p := new(bool)
+ fs.BoolVar(p, name, value, usage, options...)
+ return p
+}
+
+// BoolVar if a flag function for a flag of already exiting variable of type bool.
+func (fs *FlagSet) BoolVar(p *bool, name string, value bool, usage string, options ...predict.Option) {
+ (*flag.FlagSet)(fs).Var(newBoolValue(value, p, predict.Options(options...)), name, usage)
+}
+
+// Int if a flag function for a flag of type int.
+func (fs *FlagSet) Int(name string, value int, usage string, options ...predict.Option) *int {
+ p := new(int)
+ fs.IntVar(p, name, value, usage, options...)
+ return p
+}
+
+// IntVar if a flag function for a flag of already exiting variable of type int.
+func (fs *FlagSet) IntVar(p *int, name string, value int, usage string, options ...predict.Option) {
+ (*flag.FlagSet)(fs).Var(newIntValue(value, p, predict.Options(options...)), name, usage)
+}
+
+// Duration if a flag function for a flag of type time.Duration.
+func (fs *FlagSet) Duration(name string, value time.Duration, usage string, options ...predict.Option) *time.Duration {
+ p := new(time.Duration)
+ fs.DurationVar(p, name, value, usage, options...)
+ return p
+}
+
+// DurationVar if a flag function for a flag of already exiting variable of type time.Duration.
+func (fs *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string, options ...predict.Option) {
+ (*flag.FlagSet)(fs).Var(newDurationValue(value, p, predict.Options(options...)), name, usage)
+}
+
+// ============================================================================================== //
+
+type stringValue struct {
+ v *string
+ predict.Config
+}
+
+func newStringValue(val string, p *string, c predict.Config) *stringValue {
+ *p = val
+ return &stringValue{v: p, Config: c}
+}
+
+func (v *stringValue) Set(val string) error {
+ var err error
+ *v.v, err = parseString(val)
+ if err != nil {
+ return fmt.Errorf("bad value for String flag")
+ }
+ return v.Check(val)
+}
+
+func (v *stringValue) Get() interface{} {
+ return *v.v
+}
+
+func (v *stringValue) String() string {
+ if v == nil || v.v == nil {
+ return ""
+ }
+ return formatString(*v.v)
+}
+
+func (v *stringValue) Predict(prefix string) []string {
+ if v.Predictor != nil {
+ return v.Predictor.Predict(prefix)
+ }
+ return []string{""}
+}
+
+// ============================================================================================== //
+
+type boolValue struct {
+ v *bool
+ predict.Config
+}
+
+func newBoolValue(val bool, p *bool, c predict.Config) *boolValue {
+ *p = val
+ return &boolValue{v: p, Config: c}
+}
+
+func (v *boolValue) Set(val string) error {
+ var err error
+ *v.v, err = parseBool(val)
+ if err != nil {
+ return fmt.Errorf("bad value for Bool flag")
+ }
+ return v.Check(val)
+}
+
+func (v *boolValue) Get() interface{} {
+ return *v.v
+}
+
+func (v *boolValue) String() string {
+ if v == nil || v.v == nil {
+ return ""
+ }
+ return formatBool(*v.v)
+}
+
+func (v *boolValue) IsBoolFlag() bool { return true }
+
+func (v *boolValue) Predict(prefix string) []string {
+ if v.Predictor != nil {
+ return v.Predictor.Predict(prefix)
+ }
+ return predictBool(*v.v, prefix)
+}
+
+// ============================================================================================== //
+
+type intValue struct {
+ v *int
+ predict.Config
+}
+
+func newIntValue(val int, p *int, c predict.Config) *intValue {
+ *p = val
+ return &intValue{v: p, Config: c}
+}
+
+func (v *intValue) Set(val string) error {
+ var err error
+ *v.v, err = parseInt(val)
+ if err != nil {
+ return fmt.Errorf("bad value for Int flag")
+ }
+ return v.Check(val)
+}
+
+func (v *intValue) Get() interface{} {
+ return *v.v
+}
+
+func (v *intValue) String() string {
+ if v == nil || v.v == nil {
+ return ""
+ }
+ return formatInt(*v.v)
+}
+
+func (v *intValue) Predict(prefix string) []string {
+ if v.Predictor != nil {
+ return v.Predictor.Predict(prefix)
+ }
+ return []string{""}
+}
+
+// ============================================================================================== //
+
+type durationValue struct {
+ v *time.Duration
+ predict.Config
+}
+
+func newDurationValue(val time.Duration, p *time.Duration, c predict.Config) *durationValue {
+ *p = val
+ return &durationValue{v: p, Config: c}
+}
+
+func (v *durationValue) Set(val string) error {
+ var err error
+ *v.v, err = parseDuration(val)
+ if err != nil {
+ return fmt.Errorf("bad value for Duration flag")
+ }
+ return v.Check(val)
+}
+
+func (v *durationValue) Get() interface{} {
+ return *v.v
+}
+
+func (v *durationValue) String() string {
+ if v == nil || v.v == nil {
+ return ""
+ }
+ return formatDuration(*v.v)
+}
+
+func (v *durationValue) Predict(prefix string) []string {
+ if v.Predictor != nil {
+ return v.Predictor.Predict(prefix)
+ }
+ return []string{""}
+}
diff --git a/compflag/gen/flags.go.gotmpl b/compflag/gen/flags.go.gotmpl
new file mode 100644
index 0000000..9b65dd5
--- /dev/null
+++ b/compflag/gen/flags.go.gotmpl
@@ -0,0 +1,83 @@
+package compflag
+
+// Code auto generated with `go run ./gen`. DO NOT EDIT
+
+//go:generate go run ./gen
+
+
+{{ range . }}
+
+// {{ .Name }} if a flag function for a flag of type {{ .Type }}.
+func {{ .Name }}(name string, value {{ .Type }}, usage string, options ...predict.Option) *{{ .Type }} {
+ return CommandLine.{{ .Name }}(name, value, usage, options...)
+}
+
+// {{ .Name }}Var if a flag function for a flag of already exiting variable of type {{ .Type }}.
+func {{ .Name }}Var(v *{{ .Type }}, name string, value {{ .Type }}, usage string, options ...predict.Option) {
+ CommandLine.{{ .Name }}Var(v, name, value, usage, options...)
+}
+
+{{ end }}
+
+{{ range . }}
+
+// {{ .Name }} if a flag function for a flag of type {{ .Type }}.
+func (fs *FlagSet) {{ .Name }}(name string, value {{ .Type }}, usage string, options ...predict.Option) *{{ .Type }} {
+ p := new({{ .Type }})
+ fs.{{.Name}}Var(p, name, value, usage, options...)
+ return p
+}
+
+// {{ .Name }}Var if a flag function for a flag of already exiting variable of type {{ .Type }}.
+func (fs *FlagSet) {{ .Name }}Var(p *{{ .Type }}, name string, value {{ .Type }}, usage string, options ...predict.Option) {
+ (*flag.FlagSet)(fs).Var({{ .NewInternalTypeFuncName }}(value, p, predict.Options(options...)), name, usage)
+}
+
+{{ end }}
+
+{{ range . }}
+
+// ============================================================================================== //
+
+type {{ .InternalTypeName }} struct {
+ v *{{ .Type }}
+ predict.Config
+}
+
+func {{ .NewInternalTypeFuncName }}(val {{ .Type }}, p *{{ .Type }}, c predict.Config) *{{ .InternalTypeName }} {
+ *p = val
+ return &{{ .InternalTypeName}} {v: p, Config: c}
+}
+
+func (v *{{ .InternalTypeName }}) Set(val string) error {
+ var err error
+ *v.v, err = parse{{ .Name }}(val)
+ if err != nil {
+ return fmt.Errorf("bad value for {{ .Name }} flag")
+ }
+ return v.Check(val)
+}
+
+func (v *{{ .InternalTypeName }}) Get() interface{} {
+ return *v.v
+}
+
+func (v *{{ .InternalTypeName }}) String() string {
+ if v == nil || v.v == nil {
+ return ""
+ }
+ return format{{ .Name }}(*v.v)
+}
+
+{{ if .IsBool }}
+func (v *{{ .InternalTypeName }}) IsBoolFlag() bool { return true }
+{{ end}}
+
+func (v *{{ .InternalTypeName }}) Predict(prefix string) []string {
+ if v.Predictor != nil {
+ return v.Predictor.Predict(prefix)
+ }
+ return {{ if .CustomPredict }}predict{{ .Name }}(*v.v, prefix){{ else }}[]string{""}{{ end }}
+}
+
+{{ end }} \ No newline at end of file
diff --git a/compflag/gen/main.go b/compflag/gen/main.go
new file mode 100644
index 0000000..cbea96f
--- /dev/null
+++ b/compflag/gen/main.go
@@ -0,0 +1,67 @@
+// Generates flags.go.
+package main
+
+import (
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+ "text/template"
+
+ "github.com/posener/script"
+)
+
+const tmplGlob = "gen/*.go.gotmpl"
+
+type flag struct {
+ Name string
+ Type string
+ IsBool bool
+ CustomPredict bool
+}
+
+func (f flag) NewInternalTypeFuncName() string {
+ return "new" + strings.Title(f.InternalTypeName())
+}
+
+func (f flag) InternalTypeName() string {
+ return strings.ToLower(f.Name[:1]) + f.Name[1:] + "Value"
+}
+
+var flags = []flag{
+ {Name: "String", Type: "string"},
+ {Name: "Bool", Type: "bool", IsBool: true, CustomPredict: true},
+ {Name: "Int", Type: "int"},
+ {Name: "Duration", Type: "time.Duration"},
+}
+
+var tmpl = template.Must(template.ParseGlob(tmplGlob))
+
+func main() {
+ for _, t := range tmpl.Templates() {
+ fileName := outFileName(t.Name())
+ f, err := os.Create(fileName)
+ if err != nil {
+ panic(err)
+ }
+ defer f.Close()
+
+ log.Printf("Writing %s", fileName)
+ err = t.Execute(f, flags)
+ if err != nil {
+ panic(err)
+ }
+
+ // Format the file.
+ err = script.ExecHandleStderr(os.Stderr, "goimports", "-w", fileName).ToStdout()
+ if err != nil {
+ panic(err)
+ }
+ }
+}
+
+func outFileName(templateName string) string {
+ name := filepath.Base(templateName)
+ // Remove .gotmpl suffix.
+ return name[:strings.LastIndex(name, ".")]
+}