Skip to content

Commit

Permalink
Fix help output
Browse files Browse the repository at this point in the history
  • Loading branch information
kenshaw committed Dec 7, 2024
1 parent b593b88 commit 4305695
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 16 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
/_examples/bind/bind.exe
/_examples/reflect/reflect
/_examples/reflect/reflect.exe
/_examples/podboy/podboy
/_examples/podboy/podboy.exe
/ox.test
/ox.test.exe
*.txt
13 changes: 13 additions & 0 deletions cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,19 @@ func (cmd *Command) Command(name string) *Command {
return nil
}

// Lookup returns the furthest matching command in the command tree.
func (cmd *Command) Lookup(names ...string) *Command {
ret := cmd
for _, name := range names {
if c := ret.Command(name); c != nil {
ret = c
continue
}
break
}
return ret
}

// CommandSpecial returns the sub command with the special value.
func (cmd *Command) CommandSpecial(special string) *Command {
for _, c := range cmd.Commands {
Expand Down
35 changes: 21 additions & 14 deletions defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,24 @@ import (
)

// NewVersion adds a `version` sub command to the command.
func NewVersion(cmd *Command) error {
return cmd.Sub(
func NewVersion(cmd *Command, opts ...Option) error {
return cmd.Sub(prepend(
opts,
Usage(text.VersionCommandName, text.VersionCommandDesc),
Exec(func(ctx context.Context) error {
c, _ := Ctx(ctx)
_ = DefaultVersion(c)
return ErrExit
}),
Usage(text.VersionCommandName, text.VersionCommandDesc),
)
)...)
}

// NewVersionFlag adds a `--version` flag to the command, or hooks the command's
// flag with `Special == "hook:version"`.
func NewVersionFlag(cmd *Command) error {
func NewVersionFlag(cmd *Command, opts ...Option) error {
if g := cmd.FlagSpecial("hook:version"); g != nil {
g.Type, g.Def, g.NoArg, g.NoArgDef = HookT, DefaultVersion, true, ""
} else {
var opts []Option
if cmd.Flag(text.VersionFlagShort, false, true) == nil {
opts = append(opts, Short(text.VersionFlagShort))
}
Expand All @@ -44,14 +44,16 @@ func NewVersionFlag(cmd *Command) error {

// NewHelp adds a `help` sub command to the command.
func NewHelp(cmd *Command, opts ...Option) error {
return cmd.Sub(
Exec(func(ctx context.Context) error {
return cmd.Sub(prepend(
opts,
Usage(text.HelpCommandName, text.HelpCommandDesc),
Exec(func(ctx context.Context, args []string) error {
c, _ := Ctx(ctx)
_, _ = cmd.HelpContext(c).WriteTo(c.Stdout)
_, _ = cmd.Lookup(args...).HelpContext(c).WriteTo(c.Stdout)
return ErrExit
}),
Usage(text.HelpCommandName, text.HelpCommandDesc),
)
Option(OnErrContinue),
)...)
}

// NewHelpFlag adds a `--help` flag to the command, or hooks the command's flag
Expand Down Expand Up @@ -141,7 +143,7 @@ func NewComp(cmd *Command, opts ...Option) error {

// NewCompFlags adds `--completion-script-<type>` flags to a command, or
// hooking any existing flags with `Special == "hook:comp:<type>"`.
func NewCompFlags(cmd *Command, opts ...Option) error {
func NewCompFlags(cmd *Command, _ ...Option) error {
tpls := cmd.Templates
if tpls == nil {
tpls = templates
Expand Down Expand Up @@ -513,13 +515,18 @@ func loadTemplates(tpls fs.FS) (map[string]string, map[string]string, error) {
return txt, tpl, nil
}

// AddHelp recursively adds help for all sub commands on the command.
// AddHelp recursively adds help for all sub commands on the command,
// selectively copying certain settings.
func AddHelp(cmd *Command) error {
if len(cmd.Commands) == 0 {
return nil
}
sort := false
if help, ok := cmd.Help.(*CommandHelp); ok {
sort = help.Sort
}
for _, c := range cmd.Commands {
if err := NewHelpFlag(c); err != nil {
if err := NewHelpFlag(c, Sort(sort)); err != nil {
return err
}
if err := AddHelp(c); err != nil {
Expand Down
41 changes: 41 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,44 @@ func Example_sections() {
//
// Use "tree [command] --help" for more information about a command.
}

// Example_help shows help output.
func Example_help() {
ox.Run(
ox.Usage("cmdtree", "help command tree"),
ox.Defaults(ox.Sort(true)),
ox.Sub(
ox.Usage("sub1", "sub1 tree"),
ox.Sub(
ox.Usage("sub2", "sub2 tree", "sb", "s"),
ox.Flags().
String("my-flag", "my flag").
BigInt("big-int", "big int", ox.Short("B")).
Int("a", "the a int"),
ox.Sub(ox.Usage("sub3", "sub3 tree")),
ox.Sub(ox.Usage("a", "another command")),
),
),
ox.Args("help", "sub1", "sb", "--bad-flag", "-b"),
)
// Output:
// sub2 sub2 tree
//
// Usage:
// cmdtree sub1 sub2 [flags] [command] [args]
//
// Aliases:
// sub2, sb, s
//
// Available Commands:
// a another command
// sub3 sub3 tree
//
// Flags:
// --a int the a int
// -B, --big-int bigint big int
// -h, --help show help, then exit
// --my-flag string my flag
//
// Use "cmdtree sub1 sub2 [command] --help" for more information about a command.
}
21 changes: 21 additions & 0 deletions opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,27 @@ func Footer(footer string) HelpOption {
}
}

// Sort is a [Command] option to set the s sort for flags when used with
// a [Command] .
func Sort(sort bool) CommandOption {
return option{
name: "Sort",
cmd: func(cmd *Command) error {
return nil
},
post: func(cmd *Command) error {
if help, ok := cmd.Help.(*CommandHelp); ok {
help.Sort = sort
}
return nil
},
help: func(help *CommandHelp) error {
help.Sort = sort
return nil
},
}
}

// Sections is a [Help] option to set section names for commands when used with
// a [Command] or flag sections when used with [Help].
func Sections(sections ...string) HelpOption {
Expand Down
4 changes: 4 additions & 0 deletions parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ func parseLong(ctx *Context, cmd *Command, s string, args []string, vars Vars) (
arg, value, ok := strings.Cut(strings.TrimPrefix(s, "--"), "=")
g := cmd.Flag(arg, true, false)
switch {
case g == nil && cmd.OnErr == OnErrContinue:
return args, nil
case g == nil:
return nil, newFlagError(arg, ErrUnknownFlag)
case ok: // --arg=v
Expand All @@ -87,6 +89,8 @@ func parseShort(ctx *Context, cmd *Command, s string, args []string, vars Vars)
for v := []rune(s[1:]); len(v) != 0; v = v[1:] {
arg := string(v[0])
switch g, n := cmd.Flag(arg, true, true), len(v[1:]); {
case g == nil && cmd.OnErr == OnErrContinue:
return args, nil
case g == nil:
return nil, newFlagError(arg, ErrUnknownFlag)
case g.NoArg: // -a
Expand Down
7 changes: 5 additions & 2 deletions value.go
Original file line number Diff line number Diff line change
Expand Up @@ -645,9 +645,12 @@ func inc(val any, delta uint64) {

// invalid returns true if the value is invalid.
func invalid(val any) bool {
// interface for netip.{Addr,AddrPort,Prefix} and timev
if v, ok := val.(interface{ IsValid() bool }); ok {
switch v := val.(type) {
case interface{ IsValid() bool }:
// netip.{Addr,AddrPort,Prefix} and FormattedTime
return !v.IsValid()
case interface{ IsZero() bool }:
return v.IsZero()
}
return false
}
Expand Down

0 comments on commit 4305695

Please sign in to comment.