diff options
| author | Eyal Posener <[email protected]> | 2020-05-09 14:18:11 +0300 | 
|---|---|---|
| committer | GitHub <[email protected]> | 2020-05-09 14:18:11 +0300 | 
| commit | be08f3c4229efa432ebf26da112572e1f7e6a65e (patch) | |
| tree | a0b54d2e0790e20d300a0ff4e501e97268014a91 | |
| parent | e6d850dd6bc6aaecbaf5391412d1426fbb5ffaf5 (diff) | |
| parent | 41182b029c6a536f917139a7e27be08cc3a50d23 (diff) | |
Merge pull request #122 from posener/gen
Autogenerate compflag code
| -rw-r--r-- | compflag/compflag.go | 182 | ||||
| -rw-r--r-- | compflag/flags.go | 259 | ||||
| -rw-r--r-- | compflag/gen/flags.go.gotmpl | 83 | ||||
| -rw-r--r-- | compflag/gen/main.go | 67 | 
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, ".")] +}  | 
