diff --git a/clap.gen.go b/clap.gen.go index f84bb93..15bd3b4 100644 --- a/clap.gen.go +++ b/clap.gen.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "os" + "reflect" "strconv" ) @@ -93,6 +94,28 @@ func (v *clapString) Set(s string) error { return nil } +type clapInt[T int | int8 | int16 | int32 | int64] struct{ v *T } + +func clapNewInt[T int | int8 | int16 | int32 | int64](p *T) clapInt[T] { return clapInt[T]{p} } + +func (v clapInt[T]) String() string { return strconv.FormatInt(int64(*v.v), 10) } + +func (v clapInt[T]) Set(s string) error { + u64, err := strconv.ParseInt(s, 0, reflect.TypeFor[T]().Bits()) + if err != nil { + return numError(err) + } + *v.v = T(u64) + return nil +} + +func numError(err error) error { + if ne, ok := err.(*strconv.NumError); ok { + return ne.Err + } + return err +} + func (*goclap) UsageHelp() string { return `goclap - Pre-build tool to generate command line argument parsing code from Go comments @@ -100,12 +123,13 @@ usage: goclap [options] options: - -type The root command struct name - -srcdir Directory of source files to parse (default ".") - -with-version Include goclap's version info in the generated code - -out Output file path (default "./clap.gen.go") - -version Print version info and exit - -h Show this help message` + -type The root command struct name + -srcdir Directory of source files to parse (default ".") + -with-version Include goclap's version info in the generated code + -out Output file path (default "./clap.gen.go") + -usg-text-width Max width for lines of text in the usage message + -version Print version info and exit + -h Show this help message` } func (c *goclap) Parse(args []string) { @@ -116,6 +140,7 @@ func (c *goclap) Parse(args []string) { {name: "srcdir", value: clapNewString(&c.srcDir)}, {name: "with-version", value: clapNewBool(&c.withVersion)}, {name: "out", value: clapNewString(&c.outFilePath)}, + {name: "usg-text-width", value: clapNewInt(&c.usgTextWidth)}, {name: "version", value: clapNewBool(&c.version)}, }, } diff --git a/generate.go b/generate.go index 29f116e..4253735 100644 --- a/generate.go +++ b/generate.go @@ -9,8 +9,6 @@ import ( "unicode" ) -const maxUsgLineLen = 90 - var ( //go:embed tmpls/base-unexported.go.tmpl baseUnexportedTmplText string @@ -22,8 +20,8 @@ var ( parseFnTmplText string ) -func generate(incVersion bool, pkgName string, root *command) ([]byte, error) { - g, err := newGenerator() +func generate(incVersion bool, pkgName string, usgTextWidth int, root *command) ([]byte, error) { + g, err := newGenerator(usgTextWidth) if err != nil { return nil, fmt.Errorf("initializing generator: %w", err) } @@ -37,16 +35,15 @@ func generate(incVersion bool, pkgName string, root *command) ([]byte, error) { } type generator struct { - buf bytes.Buffer - usgFnTmpl *template.Template - parseFnTmpl *template.Template + buf bytes.Buffer + usgTextWidth int + usgFnTmpl *template.Template + parseFnTmpl *template.Template } -func newGenerator() (generator, error) { - usgFnTmpl, err := template.New("usagefunc").Parse(usgFnTmplText) - if err != nil { - return generator{}, fmt.Errorf("parsing template: %w", err) - } +func newGenerator(usgTextWidth int) (generator, error) { + usgFnTmpl := template.Must(template.New("usagefunc").Parse(usgFnTmplText)) + parseFuncs := template.FuncMap{ "add": func(a, b int) int { return a + b }, } @@ -55,8 +52,9 @@ func newGenerator() (generator, error) { return generator{}, fmt.Errorf("parsing template: %w", err) } return generator{ - usgFnTmpl: usgFnTmpl, - parseFnTmpl: parseFnTmpl, + usgTextWidth: usgTextWidth, + usgFnTmpl: usgFnTmpl, + parseFnTmpl: parseFnTmpl, }, nil } @@ -183,7 +181,7 @@ func (g *generator) genCmdUsageFunc(c *command) error { if v, ok := o.data.getConfig("env"); ok { desc += " [$" + v + "]" } - optUsgs[i] = paddedNameAndArg + wrapBlurb(desc, len(paddedNameAndArg), maxUsgLineLen) + optUsgs[i] = paddedNameAndArg + wrapBlurb(desc, len(paddedNameAndArg), g.usgTextWidth) } } @@ -201,7 +199,7 @@ func (g *generator) genCmdUsageFunc(c *command) error { if v, ok := a.data.getConfig("env"); ok { desc += " [$" + v + "]" } - argUsgs[i] = paddedName + wrapBlurb(desc, len(paddedName), maxUsgLineLen) + argUsgs[i] = paddedName + wrapBlurb(desc, len(paddedName), g.usgTextWidth) } } @@ -215,7 +213,7 @@ func (g *generator) genCmdUsageFunc(c *command) error { } for i, sc := range c.Subcmds { paddedName := fmt.Sprintf(" %-*s ", subcmdNameColWidth, sc.UsgName()) - subcmdUsgs[i] = paddedName + wrapBlurb(sc.Data.Blurb, len(paddedName), maxUsgLineLen) + subcmdUsgs[i] = paddedName + wrapBlurb(sc.Data.Blurb, len(paddedName), g.usgTextWidth) } } @@ -287,7 +285,8 @@ func (c *command) Overview() string { paras := c.Data.overview var s strings.Builder for i := range paras { - s.WriteString(wrapText(paras[i], 3, maxUsgLineLen)) + s.WriteString(" ") + s.WriteString(paras[i]) if i != len(paras)-1 { s.WriteString("\n\n") } diff --git a/main.go b/main.go index 323d214..8deb58f 100644 --- a/main.go +++ b/main.go @@ -28,6 +28,10 @@ type goclap struct { // // clap:opt out outFilePath string + // Max width for lines of text in the usage message. + // + // clap:opt usg-text-width + usgTextWidth int // Print version info and exit. // // clap:opt version @@ -143,6 +147,10 @@ func (c *command) UsgName() string { } func gen(c *goclap) error { + if c.usgTextWidth == 0 { + c.usgTextWidth = 90 + } + rootCmdTypeName := c.rootCmdType if rootCmdTypeName == "" { fmt.Fprintf(os.Stderr, "no root command type provided\n") @@ -155,7 +163,7 @@ func gen(c *goclap) error { return err } - code, err := generate(c.withVersion, pkgName, &rootCmd) + code, err := generate(c.withVersion, pkgName, c.usgTextWidth, &rootCmd) if err != nil { return err }