diff --git a/cmd.go b/cmd.go index 8a55bf9..da652b7 100644 --- a/cmd.go +++ b/cmd.go @@ -143,7 +143,7 @@ func (cmd *Command) CommandSpecial(special string) *Command { } // Flag finds a flag from the command or the command's parents. -func (cmd *Command) Flag(name string, short bool) *Flag { +func (cmd *Command) Flag(name string, parents, short bool) *Flag { if cmd.Flags != nil { if i := slices.IndexFunc(cmd.Flags.Flags, func(g *Flag) bool { return g.Name == name && !short || @@ -155,8 +155,8 @@ func (cmd *Command) Flag(name string, short bool) *Flag { return cmd.Flags.Flags[i] } } - if cmd.Parent != nil { - return cmd.Parent.Flag(name, short) + if parents && cmd.Parent != nil { + return cmd.Parent.Flag(name, parents, short) } return nil } diff --git a/example_test.go b/example_test.go index 364bf53..2d330e2 100644 --- a/example_test.go +++ b/example_test.go @@ -8,6 +8,7 @@ import ( "github.com/xo/ox" ) +// Example is a quick example demonstrating the xo/ox package. func Example() { type Verbosity int args := struct { @@ -38,13 +39,15 @@ func Example() { // -i, --ints int a slice of ints // -d, --date date formatted date // -v, --verbose enable verbose - // -v, --version show version, then exit + // --version show version, then exit // -h, --help show help, then exit // // See: https://github.com/xo/ox for more information. } -func Example_test() { +// Example_argsTest provides an example for testing arbitrary command-line +// invocations by setting the arguments to [Parse] with [ox.Args]. +func Example_argsTest() { args := struct { Number float64 `ox:"a number"` }{} @@ -53,10 +56,12 @@ func Example_test() { }{} ox.RunContext( context.Background(), + // ox.Exec(myFunc), ox.Usage("extest", "test example"), ox.Defaults(), ox.From(&args), ox.Sub( + // ox.Exec(mySubFunc), ox.Usage("sub", "a sub command to test"), ox.From(&subArgs), ), @@ -121,7 +126,8 @@ func Example_psql() { Password bool `ox:"force password prompt (should happen automatically),short:W,section:3"` }{} ox.Run( - ox.Usage("psql", ""), + // ox.Exec(myFunc), + ox.Usage("psql", "the PostgreSQL interactive terminal"), ox.Help( ox.Banner("psql is the PostgreSQL interactive terminal."), ox.Spec("[OPTION]... [DBNAME [USERNAME]]"), diff --git a/help.go b/help.go index 7847cb0..8cf49d5 100644 --- a/help.go +++ b/help.go @@ -16,7 +16,11 @@ func NewVersionFor(cmd *Command) error { if g := cmd.FlagSpecial("hook:version"); g != nil { g.Type, g.Def, g.NoArg, g.NoArgDef = HookT, DefaultVersion, true, "" } else { - cmd.Flags = cmd.Flags.Hook(text.VersionFlagName, text.VersionFlagDesc, DefaultVersion, Short(text.VersionFlagShort)) + var opts []Option + if cmd.Flag(text.VersionFlagShort, false, true) == nil { + opts = append(opts, Short(text.VersionFlagShort)) + } + cmd.Flags = cmd.Flags.Hook(text.VersionFlagName, text.VersionFlagDesc, DefaultVersion, opts...) } return nil } @@ -35,7 +39,11 @@ func NewHelpFor(cmd *Command, opts ...Option) error { if g := cmd.FlagSpecial("hook:help"); g != nil { g.Type, g.Def, g.NoArg, g.NoArgDef = HookT, f, true, "" } else { - cmd.Flags = cmd.Flags.Hook(text.HelpFlagName, text.HelpFlagDesc, f, Short(text.HelpFlagShort)) + var opts []Option + if cmd.Flag(text.HelpFlagShort, false, true) == nil { + opts = append(opts, Short(text.HelpFlagShort)) + } + cmd.Flags = cmd.Flags.Hook(text.HelpFlagName, text.HelpFlagDesc, f, opts...) } return nil } diff --git a/opts.go b/opts.go index 5cb7dbf..8e06aae 100644 --- a/opts.go +++ b/opts.go @@ -619,7 +619,7 @@ func (m SectionMap) Option() option { post: func(cmd *Command) error { for _, k := range slices.Sorted(maps.Keys(m)) { if strings.HasPrefix(k, "flag:") { - if g := cmd.Flag(strings.TrimPrefix(k, "flag:"), false); g != nil { + if g := cmd.Flag(strings.TrimPrefix(k, "flag:"), false, false); g != nil { g.Section = m[k] } } else if c := cmd.Command(k); c != nil { diff --git a/parse.go b/parse.go index 8927830..92ee87e 100644 --- a/parse.go +++ b/parse.go @@ -61,7 +61,7 @@ func parse(ctx *Context, cmd *Command, args []string, vars Vars) (*Command, []st // parseLong parses a long flag ('--arg' '--arg v' '--arg k=v' '--arg=' '--arg=v'). func parseLong(ctx *Context, cmd *Command, s string, args []string, vars Vars) ([]string, error) { arg, value, ok := strings.Cut(strings.TrimPrefix(s, "--"), "=") - g := cmd.Flag(arg, false) + g := cmd.Flag(arg, true, false) switch { case g == nil: return nil, newFlagError(arg, ErrUnknownFlag) @@ -86,7 +86,7 @@ func parseLong(ctx *Context, cmd *Command, s string, args []string, vars Vars) ( func parseShort(ctx *Context, cmd *Command, s string, args []string, vars Vars) ([]string, error) { for v := []rune(s[1:]); len(v) != 0; v = v[1:] { arg := string(v[0]) - switch g, n := cmd.Flag(arg, true), len(v[1:]); { + switch g, n := cmd.Flag(arg, true, true), len(v[1:]); { case g == nil: return nil, newFlagError(arg, ErrUnknownFlag) case g.NoArg: // -a