@@ -148,44 +148,88 @@ type ParsedFrom struct {
148148 RawDefault bool
149149}
150150
151- func (c * Command ) Opt (id string ) any {
152- if v , ok := c .LookupOpt (id ); ok {
153- return v
154- }
155- panic ("no parsed option value found for id '" + id + "'" )
156- }
157-
158- func (c * Command ) LookupOpt (id string ) (any , bool ) {
151+ // LookupOpt looks for an option value with the given id in the given Command and converts
152+ // the value to the given type T through an untested type assertion (so this will panic if
153+ // the value is found and can't be converted to type T). So if the option is present, the
154+ // typed value will be returned and the boolean will be true. Otherwise, the zero value of
155+ // type T will be returned and the boolean will be false.
156+ func LookupOpt [T any ](c * Command , id string ) (T , bool ) {
159157 for i := len (c .Opts ) - 1 ; i >= 0 ; i -- {
160158 if c .Opts [i ].ID == id {
161- return c .Opts [i ].Value , true
159+ return c .Opts [i ].Value .( T ) , true
162160 }
163161 }
164- return nil , false
162+ var zero T
163+ return zero , false
164+ }
165+
166+ // GetOpt gets the option value with the given id in the given Command and converts the
167+ // value to the given type T through an untested type assertion. This function will panic
168+ // if the value isn't found or if the value can't be converted to type T. To check
169+ // whether the value is found instead of panicking, see [LookupOpt].
170+ func GetOpt [T any ](c * Command , id string ) T {
171+ if v , ok := LookupOpt [T ](c , id ); ok {
172+ return v
173+ }
174+ panic ("no parsed option value found for id '" + id + "'" )
165175}
166176
167- func (c * Command ) Arg (id string ) any {
168- if v , ok := c .LookupArg (id ); ok {
177+ // GetOptOr looks for an option value with the given id in the given Command and converts
178+ // the value to the given type T through an untested type assertion (so this will panic if
179+ // the value is found and can't be converted to type T). If the value isn't found, the
180+ // given fallback value will be returned. To check whether the value is found instead of
181+ // using a fallback value, see [LookupOpt].
182+ func GetOptOr [T any ](c * Command , id string , fallback T ) T {
183+ if v , ok := LookupOpt [T ](c , id ); ok {
169184 return v
170185 }
171- panic ( "no parsed argument value found for id '" + id + "'" )
186+ return fallback
172187}
173188
174- func (c * Command ) LookupArg (id string ) (any , bool ) {
189+ // LookupArg looks for a positional argument value with the given id in the given Command
190+ // and converts the value to the given type T through an untested type assertion (so this
191+ // will panic if the value is found and can't be converted to type T). So if the positional
192+ // argument is present, the typed value will be returned and the boolean will be true.
193+ // Otherwise, the zero value of type T will be returned and the boolean will be false.
194+ func LookupArg [T any ](c * Command , id string ) (T , bool ) {
175195 for i := len (c .Args ) - 1 ; i >= 0 ; i -- {
176196 if c .Args [i ].ID == id {
177- return c .Args [i ].Value , true
197+ return c .Args [i ].Value .( T ) , true
178198 }
179199 }
180- return nil , false
200+ var zero T
201+ return zero , false
202+ }
203+
204+ // GetArg gets the positional argument value with the given id in the given Command and
205+ // converts the value to the given type T through an untested type assertion. This
206+ // function will panic if the value isn't found or if the value can't be converted to type
207+ // T. To check whether the value is found instead of panicking, see [LookupArg].
208+ func GetArg [T any ](c * Command , id string ) T {
209+ if v , ok := LookupArg [T ](c , id ); ok {
210+ return v
211+ }
212+ panic ("no parsed value found for positional argument id '" + id + "'" )
213+ }
214+
215+ // GetArgOr looks for a positional argument value with the given id in the given Command
216+ // and converts the value to the given type T through an untested type assertion (so this
217+ // will panic if the value is found and can't be converted to type T). If the value isn't
218+ // found, the given fallback value will be returned. To check whether the value is found
219+ // instead of using a fallback value, see [LookupArg].
220+ func GetArgOr [T any ](c * Command , id string , fallback T ) T {
221+ if v , ok := LookupArg [T ](c , id ); ok {
222+ return v
223+ }
224+ return fallback
181225}
182226
183227// ParseOrExit will parse input based on this CommandInfo. If help was requested, it
184228// will print the help message and exit the program successfully (status code 0). If
185229// there is any other error, it will print the error and exit the program with failure
186230// (status code 1). The input parameter semantics are the same as [CommandInfo.Parse].
187- func (c CommandInfo ) ParseOrExit (args ... string ) Command {
188- p , err := c .Parse (args ... )
231+ func (in CommandInfo ) ParseOrExit (args ... string ) * Command {
232+ c , err := in .Parse (args ... )
189233 if err != nil {
190234 if e , ok := err .(HelpRequestError ); ok {
191235 fmt .Print (e .HelpMsg )
@@ -195,47 +239,61 @@ func (c CommandInfo) ParseOrExit(args ...string) Command {
195239 os .Exit (1 )
196240 }
197241 }
198- return p
242+ return c
199243}
200244
201245// ParseOrExit will parse input based on this CommandInfo. If no function arguments
202246// are provided, the [os.Args] will be used.
203- func (c * CommandInfo ) Parse (args ... string ) (Command , error ) {
204- if ! c .isPrepped {
205- c .prepareAndValidate ()
206- c .isPrepped = true
247+ func (in * CommandInfo ) Parse (args ... string ) (* Command , error ) {
248+ if ! in .isPrepped {
249+ in .prepareAndValidate ()
250+ in .isPrepped = true
207251 }
208252 if args == nil {
209253 args = os .Args [1 :]
210254 }
211- p := Command {
255+ c := & Command {
212256 Opts : make ([]Input , 0 , len (args )),
213257 }
214- err := parse (c , & p , args )
215- return p , err
258+ err := parse (in , c , args )
259+ return c , err
216260}
217261
218262type HelpRequestError struct {
219- RootCause error
220- HelpMsg string
263+ HelpMsg string
221264}
222265
223266func (h HelpRequestError ) Error () string {
224- if h .RootCause != nil {
225- return h .RootCause .Error ()
226- }
227267 return h .HelpMsg
228268}
229269
230- func lookupOptionByShortName (c * CommandInfo , shortName string ) * InputInfo {
231- for i := range c .opts {
232- if c .opts [i ].nameShort == shortName {
233- return & c .opts [i ]
270+ func lookupOptionByShortName (in * CommandInfo , shortName string ) * InputInfo {
271+ for i := range in .opts {
272+ if in .opts [i ].nameShort == shortName {
273+ return & in .opts [i ]
234274 }
235275 }
236276 return nil
237277}
238278
279+ func hasOpt (c * Command , id string ) bool {
280+ for i := range c .Opts {
281+ if c .Opts [i ].ID == id {
282+ return true
283+ }
284+ }
285+ return false
286+ }
287+
288+ func hasArg (c * Command , id string ) bool {
289+ for i := range c .Args {
290+ if c .Args [i ].ID == id {
291+ return true
292+ }
293+ }
294+ return false
295+ }
296+
239297func parse (c * CommandInfo , p * Command , args []string ) error {
240298 // set any defaults
241299 for i := range c .opts {
@@ -419,8 +477,7 @@ func parse(c *CommandInfo, p *Command, args []string) error {
419477 var missing []string
420478 for i := range c .opts {
421479 if c .opts [i ].isRequired {
422- _ , ok := p .LookupOpt (c .opts [i ].id )
423- if ! ok {
480+ if ! hasOpt (p , c .opts [i ].id ) {
424481 var name string
425482 if c .opts [i ].nameLong != "" {
426483 name = "--" + c .opts [i ].nameLong
@@ -458,8 +515,7 @@ func parse(c *CommandInfo, p *Command, args []string) error {
458515 if ! c .args [i ].isRequired {
459516 break
460517 }
461- _ , ok := p .LookupArg (c .args [i ].id )
462- if ! ok {
518+ if ! hasArg (p , c .args [i ].id ) {
463519 missing = append (missing , c .args [i ].valueName )
464520 }
465521 }
0 commit comments