@@ -65,8 +65,7 @@ func New(name string, options ...Option) (*Command, error) {
6565 return nil , fmt .Errorf ("bad arguments expected [<command> <args>...], got %v" , os .Args )
6666 }
6767
68- // Default implementation
69- cfg := config {
68+ cmd := & Command {
7069 flags : flag .NewSet (),
7170 stdin : os .Stdin ,
7271 stdout : os .Stdout ,
@@ -81,30 +80,47 @@ func New(name string, options ...Option) (*Command, error) {
8180 // to report in one go
8281 var errs error
8382 for _ , option := range options {
84- errs = errors .Join (errs , option .apply (& cfg ))
83+ errs = errors .Join (errs , option .apply (cmd ))
8584 }
8685
87- // Ensure we always have at least help and version flags
88- err := Flag (& cfg .helpCalled , "help" , 'h' , "Show help for " + name ).apply (& cfg )
89- errs = errors .Join (errs , err ) // nil errors are discarded in join
90-
91- err = Flag (& cfg .versionCalled , "version" , 'V' , "Show version info for " + name ).apply (& cfg )
92-
93- errs = errors .Join (errs , err )
86+ // Ensure we always have at least help and version flags. Wired in
87+ // directly rather than via the Flag option to skip the closure +
88+ // Option interface boxing on every cli.New.
89+ errs = errors .Join (
90+ errs ,
91+ addAutoBoolFlag (cmd .flags , & cmd .helpCalled , "help" , 'h' , "Show help for " + name ),
92+ addAutoBoolFlag (cmd .flags , & cmd .versionCalled , "version" , 'V' , "Show version info for " + name ),
93+ )
9494 if errs != nil {
9595 return nil , errs
9696 }
9797
9898 // Additional validation that can't be done per-option
9999 // A command cannot have no subcommands and no run function, it must define one or the other
100- if cfg .run == nil && len (cfg .subcommands ) == 0 {
100+ if cmd .run == nil && len (cmd .subcommands ) == 0 {
101101 return nil , fmt .Errorf (
102102 "command %s has no subcommands and no run function, a command must either be runnable or have subcommands" ,
103- cfg .name ,
103+ cmd .name ,
104104 )
105105 }
106106
107- return cfg .build (), nil
107+ // Loop through each subcommand and set this command as their immediate parent
108+ for _ , subcommand := range cmd .subcommands {
109+ subcommand .parent = cmd
110+ }
111+
112+ return cmd , nil
113+ }
114+
115+ // addAutoBoolFlag wires the implicit --help / --version flags onto the
116+ // flag set without going through the Flag option.
117+ func addAutoBoolFlag (set * flag.Set , target * bool , name string , short rune , usage string ) error {
118+ f , err := flag .New (target , name , short , usage , flag.Config [bool ]{})
119+ if err != nil {
120+ return err
121+ }
122+
123+ return flag .AddToSet (set , f )
108124}
109125
110126// Command represents a CLI command.
0 commit comments