From 7e11a1b3ebcbba50cab5605e169c467e930d5af8 Mon Sep 17 00:00:00 2001 From: Tom Fleet Date: Fri, 2 Aug 2024 17:57:31 +0100 Subject: [PATCH] Remove pflag and rely on our own flag set (#61) --- TODO.md | 5 +- command.go | 88 +++++++++++------ command_test.go | 16 +-- go.mod | 5 +- go.sum | 2 - internal/flag/flag.go | 7 +- internal/flag/set.go | 34 ++++++- internal/flag/set_test.go | 33 ++++--- internal/flag/testdata/TestUsage/full.txt | 10 +- .../flag/testdata/TestUsage/no-shorthand.txt | 6 +- internal/flag/testdata/TestUsage/simple.txt | 4 +- option.go | 99 +++++++------------ testdata/TestHelp/default-help.txt | 5 +- testdata/TestHelp/full.txt | 5 +- testdata/TestHelp/no-about.txt | 5 +- testdata/TestHelp/subcommands-flags.txt | 9 +- testdata/TestHelp/subcommands.txt | 5 +- testdata/TestHelp/with-examples.txt | 5 +- 18 files changed, 191 insertions(+), 152 deletions(-) diff --git a/TODO.md b/TODO.md index 79e3d92..ec4279e 100644 --- a/TODO.md +++ b/TODO.md @@ -2,7 +2,7 @@ Things I want to do to make this library as good as it can be and a better, simpler, more intuitive alternative to e.g. Cobra: -- [ ] Replace `pflag.FlagSet` with my own implementation including parsing +- [x] Replace `pflag.FlagSet` with my own implementation including parsing - [x] Make sure `cli.Option` is hidden and a `Command` can only be modified prior to building - [x] Ensure/double check that `cli.Option` applications are order independent - [x] Do some validation and maybe return an error from `cli.New` (TBC, might not need it) @@ -15,6 +15,7 @@ Things I want to do to make this library as good as it can be and a better, simp - [ ] More full test programs as integration tests - [ ] Write a package example doc - [ ] Make the help output as pretty as possible, see [clap] for inspiration as their help is so nice -- [ ] Implement something nice to do the whole `-- ` thing, maybe `ExtraArgs`? +- [x] Implement something nice to do the whole `-- ` thing, maybe `ExtraArgs`? +- [ ] Thin wrapper around tabwriter to keep it consistent [clap]: https://github.com/clap-rs/clap diff --git a/command.go b/command.go index 87492ec..f1e621c 100644 --- a/command.go +++ b/command.go @@ -9,15 +9,15 @@ import ( "slices" "strings" "text/tabwriter" + "unicode/utf8" "github.com/FollowTheProcess/cli/internal/flag" - "github.com/spf13/pflag" ) // TableWriter config, used for showing subcommands in help. const ( - minWidth = 0 // Min cell width - tabWidth = 4 // Tab width in spaces + minWidth = 2 // Min cell width + tabWidth = 8 // Tab width in spaces padding = 1 // Padding padChar = '\t' // Char to pad with ) @@ -42,8 +42,7 @@ func New(name string, options ...Option) (*Command, error) { // Default implementation cfg := config{ - flags: pflag.NewFlagSet(name, pflag.ContinueOnError), - xflags: flag.NewSet(), + flags: flag.NewSet(), stdin: os.Stdin, stdout: os.Stdout, stderr: os.Stderr, @@ -55,11 +54,19 @@ func New(name string, options ...Option) (*Command, error) { argValidator: AnyArgs(), } + // Ensure we always have at least help and version flags + defaultOptions := []Option{ + Flag(&cfg.helpCalled, "help", 'h', false, fmt.Sprintf("Show help for %s", name)), + Flag(&cfg.versionCalled, "version", 'v', false, fmt.Sprintf("Show version info for %s", name)), + } + + toApply := slices.Concat(options, defaultOptions) + // Apply the options, gathering up all the validation errors // to report in one go. Each option returns only one error // so this can be pre-allocated. - errs := make([]error, 0, len(options)) - for _, option := range options { + errs := make([]error, 0, len(toApply)) + for _, option := range toApply { err := option.apply(&cfg) if err != nil { errs = append(errs, err) @@ -97,10 +104,7 @@ type Command struct { run func(cmd *Command, args []string) error // flags is the set of flags for this command. - flags *pflag.FlagSet - - // xflags is my experimental flagset. - xflags *flag.Set + flags *flag.Set // versionFunc is the function thatgets called when the user calls -v/--version. // @@ -143,6 +147,12 @@ type Command struct { // // If the command has no subcommands, this slice will be nil. subcommands []*Command + + // helpCalled is whether or not the --help flag was used. + helpCalled bool + + // versionCalled is whether or not the --version flag was used. + versionCalled bool } // example is a single usage example for a [Command]. @@ -189,12 +199,13 @@ func (c *Command) Execute() error { // If -h/--help was called, call the defined helpFunc and exit so that // the run function is never called. - helpCalled, err := cmd.flagSet().GetBool("help") - if err != nil { - return fmt.Errorf("could not parse help flag: %w", err) + helpCalled, ok := cmd.flagSet().Help() + if !ok { + // Should never get here as we define a default help + return errors.New("help flag not defined") } if helpCalled { - if err = defaultHelp(cmd); err != nil { + if err := defaultHelp(cmd); err != nil { return fmt.Errorf("help function returned an error: %w", err) } return nil @@ -202,9 +213,10 @@ func (c *Command) Execute() error { // If -v/--version was called, call the defined versionFunc and exit so that // the run function is never called - versionCalled, err := cmd.flagSet().GetBool("version") - if err != nil { - return fmt.Errorf("could not parse version flag: %w", err) + versionCalled, ok := cmd.flagSet().Version() + if !ok { + // Again, should be unreachable + return errors.New("version flag not defined") } if versionCalled { if cmd.versionFunc == nil { @@ -244,14 +256,14 @@ func (c *Command) Execute() error { } // Flags returns the set of flags for the command. -func (c *Command) flagSet() *pflag.FlagSet { +func (c *Command) flagSet() *flag.Set { if c == nil { // Only thing to do really, slightly more helpful than a generic // nil pointer dereference panic("Flags called on a nil Command") } if c.flags == nil { - return pflag.NewFlagSet(c.name, pflag.ContinueOnError) + return flag.NewSet() } return c.flags } @@ -271,6 +283,14 @@ func (c *Command) Stdin() io.Reader { return c.root().stdin } +// ExtraArgs returns any additional arguments following a "--", this is useful for when you want to +// implement argument pass through in your commands. +// +// If there were no extra arguments, it will return nil. +func (c *Command) ExtraArgs() []string { + return c.flagSet().ExtraArgs() +} + // root returns the root of the command tree. func (c *Command) root() *Command { if c.parent != nil { @@ -281,24 +301,31 @@ func (c *Command) root() *Command { // hasFlag returns whether the command has a flag of the given name defined. func (c *Command) hasFlag(name string) bool { - flag := c.flagSet().Lookup(name) - if flag == nil { + if name == "" { + return false + } + flag, ok := c.flagSet().Get(name) + if !ok { return false } - return flag.NoOptDefVal != "" + + return flag.DefaultValueNoArg != "" } // hasShortFlag returns whether the command has a shorthand flag of the given name defined. func (c *Command) hasShortFlag(name string) bool { - if len(name) == 0 { + if name == "" { return false } - flag := c.flagSet().ShorthandLookup(name[:1]) - if flag == nil { + char, _ := utf8.DecodeRuneInString(name) + + flag, ok := c.flagSet().GetShort(char) + if !ok { return false } - return flag.NoOptDefVal != "" + + return flag.DefaultValueNoArg != "" } // findRequestedCommand uses the raw arguments and the command tree to determine what @@ -395,6 +422,11 @@ func defaultHelp(cmd *Command) error { if cmd == nil { return errors.New("defaultHelp called on a nil Command") } + usage, err := cmd.flagSet().Usage() + if err != nil { + return fmt.Errorf("could not write usage: %w", err) + } + // Note: The decision to not use text/template here is intentional, template calls // reflect.Value.MethodByName() and/or reflect.Type.MethodByName() which disables dead // code elimination in the compiler, meaning any application that uses cli for it's @@ -460,7 +492,7 @@ func defaultHelp(cmd *Command) error { s.WriteString("\n\n") } s.WriteString("Options:\n") - s.WriteString(cmd.flagSet().FlagUsages()) + s.WriteString(usage) // Subcommand help s.WriteString("\n") diff --git a/command_test.go b/command_test.go index adc9d9e..d3faff5 100644 --- a/command_test.go +++ b/command_test.go @@ -93,11 +93,12 @@ func TestSubCommandExecute(t *testing.T) { stdout string // Expected stdout stderr string // Expected stderr args []string // Args passed to root command + extra []string // Extra args after "--" if present wantErr bool // Whether or not we wanted an error }{ { name: "invoke sub1 no flags", - stdout: "Hello from sub1, my args were: [my subcommand args], force was false, something was ", + stdout: "Hello from sub1, my args were: [my subcommand args], force was false, something was , extra args: []", stderr: "", args: []string{"sub1", "my", "subcommand", "args"}, wantErr: false, @@ -111,28 +112,28 @@ func TestSubCommandExecute(t *testing.T) { }, { name: "invoke sub1 with flags", - stdout: "Hello from sub1, my args were: [my subcommand args], force was true, something was here", + stdout: "Hello from sub1, my args were: [my subcommand args], force was true, something was here, extra args: []", stderr: "", args: []string{"sub1", "my", "subcommand", "args", "--force", "--something", "here"}, wantErr: false, }, { name: "invoke sub1 with arg terminator", - stdout: "Hello from sub1, my args were: [my subcommand args more args here], force was true, something was here", + stdout: "Hello from sub1, my args were: [my subcommand args more args here], force was true, something was here, extra args: [more args here]", stderr: "", args: []string{"sub1", "my", "subcommand", "args", "--force", "--something", "here", "--", "more", "args", "here"}, wantErr: false, }, { name: "invoke sub1 with sub1 in the arg list", - stdout: "Hello from sub1, my args were: [my sub1 args sub1 more args here], force was true, something was here", + stdout: "Hello from sub1, my args were: [my sub1 args sub1 more args here], force was true, something was here, extra args: []", stderr: "", - args: []string{"sub1", "my", "sub1", "args", "sub1", "--force", "--something", "here", "--", "more", "args", "here"}, + args: []string{"sub1", "my", "sub1", "args", "sub1", "--force", "--something", "here", "more", "args", "here"}, wantErr: false, }, { name: "invoke sub1 with sub1 as a flag value", - stdout: "Hello from sub1, my args were: [my subcommand args more args here], force was true, something was sub2", + stdout: "Hello from sub1, my args were: [my subcommand args more args here], force was true, something was sub2, extra args: []", stderr: "", args: []string{"sub1", "my", "subcommand", "args", "--force", "--something", "sub2", "more", "args", "here"}, wantErr: false, @@ -165,10 +166,11 @@ func TestSubCommandExecute(t *testing.T) { } fmt.Fprintf( cmd.Stdout(), - "Hello from sub1, my args were: %v, force was %v, something was %s", + "Hello from sub1, my args were: %v, force was %v, something was %s, extra args: %v", args, force, something, + cmd.ExtraArgs(), ) return nil }), diff --git a/go.mod b/go.mod index fd28ecd..4ff1871 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,6 @@ module github.com/FollowTheProcess/cli go 1.22 -require ( - github.com/FollowTheProcess/test v0.11.1 - github.com/spf13/pflag v1.0.5 -) +require github.com/FollowTheProcess/test v0.11.1 require github.com/google/go-cmp v0.6.0 // indirect diff --git a/go.sum b/go.sum index e9863a1..f107651 100644 --- a/go.sum +++ b/go.sum @@ -2,5 +2,3 @@ github.com/FollowTheProcess/test v0.11.1 h1:f4peMzlID2+ZEbPzb4pITYLoicwqZc2J6iZF github.com/FollowTheProcess/test v0.11.1/go.mod h1:oIqlUoS8wKFmKBFBMJH/+asP7lQXE2D3YFhmUEubTUw= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= diff --git a/internal/flag/flag.go b/internal/flag/flag.go index 5e1f8cc..dcc8130 100644 --- a/internal/flag/flag.go +++ b/internal/flag/flag.go @@ -23,8 +23,6 @@ import ( "unicode" "unicode/utf8" "unsafe" - - "github.com/spf13/pflag" ) const ( @@ -66,10 +64,7 @@ const ( // should be the long hand version only e.g. --count, not -c/--count. const NoShortHand = rune(-1) -var ( - _ pflag.Value = Flag[string]{} // This will fail if we violate pflag.Value - _ Value = Flag[string]{} // This one will fail if we violate our own Value interface -) +var _ Value = Flag[string]{} // This will fail if we violate our Value interface // Flaggable is a type constraint that defines any type capable of being parsed as a command line flag. // diff --git a/internal/flag/set.go b/internal/flag/set.go index 9de0aed..6c2a7a3 100644 --- a/internal/flag/set.go +++ b/internal/flag/set.go @@ -13,7 +13,7 @@ import ( // TableWriter config, used for showing subcommands in help. const ( minWidth = 0 // Min cell width - tabWidth = 4 // Tab width in spaces + tabWidth = 8 // Tab width in spaces padding = 1 // Padding padChar = '\t' // Char to pad with ) @@ -23,6 +23,7 @@ type Set struct { flags map[string]Entry // The actual stored flags, can lookup by name shorthands map[rune]Entry // The flags by shorthand args []string // Arguments minus flags or flag values + extra []string // Arguments after "--" was hit } // NewSet builds and returns a new set of flags. @@ -126,7 +127,8 @@ func (s *Set) Version() (value, ok bool) { return entry.Value.String() == boolTrue, true } -// Args returns a slice of all the non-flag arguments. +// Args returns a slice of all the non-flag arguments, including any +// following a "--" terminator. func (s *Set) Args() []string { if s == nil { return nil @@ -134,7 +136,18 @@ func (s *Set) Args() []string { return s.args } +// ExtraArgs returns any arguments after a "--" was encountered, or nil +// if there were none. +func (s *Set) ExtraArgs() []string { + if s == nil { + return nil + } + return s.extra +} + // Parse parses flags and their values from the command line. +// +// TODO: Currently thinks arg terminator "--" is just an empty flag. func (s *Set) Parse(args []string) (err error) { if s == nil { return errors.New("Parse called on a nil set") @@ -143,6 +156,14 @@ func (s *Set) Parse(args []string) (err error) { arg := args[0] // The argument we're currently inspecting args = args[1:] // Remainder + if arg == "--" { + // "--" terminates the flags + terminatorIndex := len(s.args) + s.args = append(s.args, args...) + s.extra = s.args[terminatorIndex:] + return nil + } + switch { case strings.HasPrefix(arg, "--"): // This is a long flag e.g. --delete @@ -188,8 +209,8 @@ func (s *Set) Usage() (string, error) { } var defaultValue string - if entry.Value.String() != "" { - defaultValue = entry.Value.String() + if entry.DefaultValue != "" { + defaultValue = entry.DefaultValue } else { defaultValue = `""` } @@ -281,6 +302,11 @@ func (s *Set) parseShortFlag(short string, rest []string) (remaining []string, e // Could either be "f", "vfg" or "f=value" shorthands := strings.TrimPrefix(short, "-") + // go test inserts flags like "-test.testlogfile" + if strings.HasPrefix(shorthands, "test.") { + return rest, nil + } + // Is it e.g. f=value shorthand, value, containsEquals := strings.Cut(shorthands, "=") if err := validateFlagName(shorthand); err != nil { diff --git a/internal/flag/set_test.go b/internal/flag/set_test.go index 4a74e59..f48e667 100644 --- a/internal/flag/set_test.go +++ b/internal/flag/set_test.go @@ -62,6 +62,24 @@ func TestParse(t *testing.T) { args: []string{"some", "args", "here", "no", "flags"}, wantErr: false, }, + { + name: "empty set args with terminator", + newSet: func(t *testing.T) *flag.Set { + t.Helper() + return flag.NewSet() + }, + test: func(t *testing.T, set *flag.Set) { + t.Helper() + f, exists := set.Get("something") + test.False(t, exists) + test.Equal(t, f, flag.Entry{}) + + test.EqualFunc(t, set.Args(), []string{"some", "args", "here", "no", "flags", "extra", "args"}, slices.Equal) + test.EqualFunc(t, set.ExtraArgs(), []string{"extra", "args"}, slices.Equal) + }, + args: []string{"some", "args", "here", "no", "flags", "--", "extra", "args"}, + wantErr: false, + }, { name: "empty set with flags", newSet: func(t *testing.T) *flag.Set { @@ -150,16 +168,6 @@ func TestParse(t *testing.T) { wantErr: true, errMsg: "unrecognised shorthand flag: -u", }, - { - name: "bad syntax long empty name", - newSet: func(t *testing.T) *flag.Set { - t.Helper() - return flag.NewSet() - }, - args: []string{"--"}, - wantErr: true, - errMsg: `invalid flag name "": must not be empty`, - }, { name: "bad syntax short empty name", newSet: func(t *testing.T) *flag.Set { @@ -317,9 +325,10 @@ func TestParse(t *testing.T) { test.Equal(t, entry.Value.Type(), "bool") test.Equal(t, entry.Value.String(), "true") - test.EqualFunc(t, set.Args(), []string{"some", "subcommand"}, slices.Equal) + test.EqualFunc(t, set.Args(), []string{"some", "subcommand", "extra", "args"}, slices.Equal) + test.EqualFunc(t, set.ExtraArgs(), []string{"extra", "args"}, slices.Equal) }, - args: []string{"some", "subcommand", "--delete"}, + args: []string{"some", "subcommand", "--delete", "--", "extra", "args"}, wantErr: false, }, { diff --git a/internal/flag/testdata/TestUsage/full.txt b/internal/flag/testdata/TestUsage/full.txt index 40e73ba..095c061 100755 --- a/internal/flag/testdata/TestUsage/full.txt +++ b/internal/flag/testdata/TestUsage/full.txt @@ -1,6 +1,6 @@ Short Long Type Default Usage --c --count int 0 Count things --h --help bool false Show help for test --t --thing string "" Name the thing -N/A --update bool false Update something --v --version bool false Show version info for test +-c --count int 0 Count things +-h --help bool false Show help for test +-t --thing string "" Name the thing +N/A --update bool false Update something +-v --version bool false Show version info for test diff --git a/internal/flag/testdata/TestUsage/no-shorthand.txt b/internal/flag/testdata/TestUsage/no-shorthand.txt index d15e2dc..63c4ca0 100644 --- a/internal/flag/testdata/TestUsage/no-shorthand.txt +++ b/internal/flag/testdata/TestUsage/no-shorthand.txt @@ -1,4 +1,4 @@ Short Long Type Default Usage --h --help bool false Show help for test -N/A --update bool false Update something --v --version bool false Show version info for test +-h --help bool false Show help for test +N/A --update bool false Update something +-v --version bool false Show version info for test diff --git a/internal/flag/testdata/TestUsage/simple.txt b/internal/flag/testdata/TestUsage/simple.txt index b12a3f4..a1e6313 100644 --- a/internal/flag/testdata/TestUsage/simple.txt +++ b/internal/flag/testdata/TestUsage/simple.txt @@ -1,3 +1,3 @@ Short Long Type Default Usage --h --help bool false Show help for test --v --version bool false Show version info for test +-h --help bool false Show help for test +-v --version bool false Show version info for test diff --git a/option.go b/option.go index da8f523..5504736 100644 --- a/option.go +++ b/option.go @@ -7,7 +7,6 @@ import ( "slices" "github.com/FollowTheProcess/cli/internal/flag" - "github.com/spf13/pflag" ) // NoShortHand should be passed as the "short" argument to [Flag] if the desired flag @@ -38,43 +37,45 @@ func (o option) apply(cfg *config) error { // config represents the internal configuration of a [Command]. type config struct { - stdin io.Reader - stdout io.Writer - stderr io.Writer - run func(cmd *Command, args []string) error - flags *pflag.FlagSet - xflags *flag.Set - versionFunc func(cmd *Command) error - parent *Command - argValidator ArgValidator - name string - short string - long string - version string - examples []example - args []string - subcommands []*Command + stdin io.Reader + stdout io.Writer + stderr io.Writer + run func(cmd *Command, args []string) error + flags *flag.Set + versionFunc func(cmd *Command) error + parent *Command + argValidator ArgValidator + name string + short string + long string + version string + examples []example + args []string + subcommands []*Command + helpCalled bool + versionCalled bool } // build builds an returns a Command from the config. func (c *config) build() *Command { cmd := &Command{ - stdin: c.stdin, - stdout: c.stdout, - stderr: c.stderr, - run: c.run, - flags: c.flags, - xflags: c.xflags, - versionFunc: c.versionFunc, - parent: c.parent, - argValidator: c.argValidator, - name: c.name, - short: c.short, - long: c.long, - version: c.version, - examples: c.examples, - args: c.args, - subcommands: c.subcommands, + stdin: c.stdin, + stdout: c.stdout, + stderr: c.stderr, + run: c.run, + flags: c.flags, + versionFunc: c.versionFunc, + parent: c.parent, + argValidator: c.argValidator, + name: c.name, + short: c.short, + long: c.long, + version: c.version, + examples: c.examples, + args: c.args, + subcommands: c.subcommands, + helpCalled: c.helpCalled, + versionCalled: c.versionCalled, } // Loop through each subcommand and set this command as their immediate parent @@ -82,10 +83,6 @@ func (c *config) build() *Command { subcommand.parent = cmd } - // Add the help and version flags - cmd.flagSet().BoolP("help", "h", false, fmt.Sprintf("Show help for %s", cmd.name)) - cmd.flagSet().BoolP("version", "v", false, fmt.Sprintf("Show version info for %s", cmd.name)) - return cmd } @@ -344,7 +341,7 @@ func Allow(validator ArgValidator) Option { // cli.New("rm", cli.Flag(&force, "force", 'f', false, "Force deletion without confirmation")) func Flag[T Flaggable](p *T, name string, short rune, value T, usage string) Option { f := func(cfg *config) error { - if cfg.flags.Lookup(name) != nil { + if _, ok := cfg.flags.Get(name); ok { return fmt.Errorf("flag %q already defined", name) } @@ -354,35 +351,11 @@ func Flag[T Flaggable](p *T, name string, short rune, value T, usage string) Opt } // Experimental flags - if err := flag.AddToSet(cfg.xflags, f); err != nil { + if err := flag.AddToSet(cfg.flags, f); err != nil { // TODO: This error message is just for me debugging for now, make it more user friendly return fmt.Errorf("xflags.Add: %w", err) } - var defVal string - if f.Type() == "bool" { - defVal = "true" - } - - // If we've been told we don't want a shorthand, set it to "" which tells pflag - // not to give it one, otherwise use what we've been given - var shortHand string - if short == NoShortHand { - shortHand = "" - } else { - shortHand = string(short) - } - - // Annoyingly pflag does the same checks we've done above but will panic on error, hopefully - // the above checks will come in handy when I implement my own flag parsing - cfg.flags.AddFlag(&pflag.Flag{ - Name: name, - Shorthand: shortHand, - Usage: usage, - Value: f, - DefValue: f.String(), - NoOptDefVal: defVal, - }) return nil } return option(f) diff --git a/testdata/TestHelp/default-help.txt b/testdata/TestHelp/default-help.txt index 5c8c088..8151bd9 100644 --- a/testdata/TestHelp/default-help.txt +++ b/testdata/TestHelp/default-help.txt @@ -3,7 +3,8 @@ A placeholder for something cool Usage: test [OPTIONS] ARGS... Options: - -h, --help Show help for test - -v, --version Show version info for test +Short Long Type Default Usage +-h --help bool false Show help for test +-v --version bool false Show version info for test Use "test [command] -h/--help" for more information about a command. diff --git a/testdata/TestHelp/full.txt b/testdata/TestHelp/full.txt index 0dfb8ed..abd29bc 100644 --- a/testdata/TestHelp/full.txt +++ b/testdata/TestHelp/full.txt @@ -5,7 +5,8 @@ A longer, probably multiline description Usage: test [OPTIONS] ARGS... Options: - -h, --help Show help for test - -v, --version Show version info for test +Short Long Type Default Usage +-h --help bool false Show help for test +-v --version bool false Show version info for test Use "test [command] -h/--help" for more information about a command. diff --git a/testdata/TestHelp/no-about.txt b/testdata/TestHelp/no-about.txt index 5c8c088..8151bd9 100644 --- a/testdata/TestHelp/no-about.txt +++ b/testdata/TestHelp/no-about.txt @@ -3,7 +3,8 @@ A placeholder for something cool Usage: test [OPTIONS] ARGS... Options: - -h, --help Show help for test - -v, --version Show version info for test +Short Long Type Default Usage +-h --help bool false Show help for test +-v --version bool false Show version info for test Use "test [command] -h/--help" for more information about a command. diff --git a/testdata/TestHelp/subcommands-flags.txt b/testdata/TestHelp/subcommands-flags.txt index 0b3fb3e..820846b 100644 --- a/testdata/TestHelp/subcommands-flags.txt +++ b/testdata/TestHelp/subcommands-flags.txt @@ -9,9 +9,10 @@ Commands: sub2 Do another thing Options: - --count int Count something (default -1) - -d, --delete Delete something - -h, --help Show help for test - -v, --version Show version info for test +Short Long Type Default Usage +N/A --count int -1 Count something +-d --delete bool false Delete something +-h --help bool false Show help for test +-v --version bool false Show version info for test Use "test [command] -h/--help" for more information about a command. diff --git a/testdata/TestHelp/subcommands.txt b/testdata/TestHelp/subcommands.txt index 9e8b6ed..51da83a 100644 --- a/testdata/TestHelp/subcommands.txt +++ b/testdata/TestHelp/subcommands.txt @@ -9,7 +9,8 @@ Commands: sub2 Do another thing Options: - -h, --help Show help for test - -v, --version Show version info for test +Short Long Type Default Usage +-h --help bool false Show help for test +-v --version bool false Show version info for test Use "test [command] -h/--help" for more information about a command. diff --git a/testdata/TestHelp/with-examples.txt b/testdata/TestHelp/with-examples.txt index a5ae602..3249a5c 100644 --- a/testdata/TestHelp/with-examples.txt +++ b/testdata/TestHelp/with-examples.txt @@ -10,7 +10,8 @@ $ test do thing --now $ test do thing --different Options: - -h, --help Show help for test - -v, --version Show version info for test +Short Long Type Default Usage +-h --help bool false Show help for test +-v --version bool false Show version info for test Use "test [command] -h/--help" for more information about a command.