Documentation
¶
Overview ¶
Input Sources and Precedence ¶
This library will always parse a program's command line arguments for Inputs. However, inputs can additionally be parsed from environment variables or default values, in that order of precedence. For example, if an input can be parsed from all of those places (command line argument, environment variable, and default value), all will be parsed, but the value from the command line will take precedence over the value from the environment variable, and the value from the environment variable will take precedence over the default value.
Command Line Syntax ¶
Command line arguments are classified as one of the following:
- Options: arguments that begin with "-" or "--" and may or may not require a value.
- Positional Arguments: arguments that are identified by the order in which they appear among other positional arguments.
- Subcommands: All arguments that follow belong to this command.
Command line arguments are parsed as options until a positional argument, subcommand, or an argument of just "--" is encountered. In other words, any options that belong to a command must come before any of that command's positional arguments or subcommands.
Positional arguments and subcommands are mutually exclusive since allowing both to exist at once would invite unnecessary ambiguity when parsing because there's no reliable way to tell if an argument would be a positional argument or the name of a subcommand. Furthermore, positional arguments that are required must appear before any optional ones since it would be impossible to tell when parsing whether a positional argument is filling the spot of a required one or an optional one. Therefore, the format of a command is structured like this:
command [options] [<required_pos_args> [optional_pos_args] [any_surplus_post_args...] | subcommand ...]
Options ¶
There are only two types of options in terms of syntax:
- boolean: Rather than providing some value, the mere presence of this type of option means something. For example, the "--all" in "ls --all" does not take a value; it just modifies the list command to list "all" files.
- non-boolean: This type of option requires a value. For example, in "ls --hide go.sum", the option "--hide" requires a file name or pattern.
Non-boolean options must have a value attached. In other words, while options themselves can either be required or optional, there is no such thing as an option that may or may not have a value.
Options can have appear in one of two forms and can have a name for each form: long or short. Typically an option's long name is more than one character, but an option's short name can only be a single character. Long form options are provided by prefixing the option's name with two hyphens ("--"), and they must appear one at a time, separately. Short form options are provided by prefixing the options short name with a single hyphen ("-"), and they can be "stacked", meaning under certain conditions, they can appear one after the other in the same command line argument.
The following are some common ways of how options can be provided:
--opt // long form boolean option "opt" -o // short form boolean option "o" --opt=val // long form non-boolean option with value of "val" --opt val // same as above, non-boolean options can provide their value as the next command line argument -a -b // two short form boolean options, "a" and "b" -ab // either same as above, or short form non-boolean option "a" with value of "b" (depends on specified command structure)
Basic Usage ¶
c := cli.New().
Help("A full example program").
Opt(cli.NewBoolOpt("yes").
Short('y').
Help("A boolean option on the root command.").
Env("YES")).
Opt(cli.NewOpt("str").
Short('s').
Help("A string option on the root command.").
Env("STR")).
Subcmd(cli.NewCmd("nodat").
Help("Subcommand with no data")).
Subcmd(cli.NewCmd("floats").
Help("Print values for each supported float type (both options required).").
Opt(cli.NewFloat32Opt("f32").Help("32 bit float").Required()).
Opt(cli.NewFloat64Opt("f64").Help("64 bit float").Required())).
Subcmd(cli.NewCmd("ints").
Help("Print values for each supported signed integer type.").
Opt(cli.NewIntOpt("int").Help("Print the given int value."))).
ParseOrExit()
Index ¶
- Variables
- func DefaultFullHelp(c *CommandInfo) string
- func DefaultHelpGenerator(src Input, c *CommandInfo) string
- func DefaultShortHelp(c *CommandInfo) string
- func Fatal(code int, v any)
- func Get[T any](c *Command, id string) T
- func GetAll[T any](c *Command, id string) []T
- func GetAllSeq[T any](c *Command, id string) iter.Seq[T]
- func GetOr[T any](c *Command, id string, fallback T) T
- func GetOrFunc[T any](c *Command, id string, fn func() T) T
- func Lookup[T any](c *Command, id string) (T, bool)
- func ParseBool(s string) (any, error)
- func ParseDuration(s string) (any, error)
- func ParseFloat32(s string) (any, error)
- func ParseFloat64(s string) (any, error)
- func ParseInt(s string) (any, error)
- func ParseURL(s string) (any, error)
- func ParseUint(s string) (any, error)
- type Command
- type CommandInfo
- func (c CommandInfo) Arg(pa InputInfo) CommandInfo
- func (c CommandInfo) ExtraHelp(extra string) CommandInfo
- func (c CommandInfo) Help(blurb string) CommandInfo
- func (c CommandInfo) Opt(o InputInfo) CommandInfo
- func (in *CommandInfo) Parse() (*Command, error)
- func (in CommandInfo) ParseOrExit() *Command
- func (in *CommandInfo) ParseThese(args ...string) (*Command, error)
- func (in CommandInfo) ParseTheseOrExit(args ...string) *Command
- func (c CommandInfo) Subcmd(sc CommandInfo) CommandInfo
- func (c CommandInfo) SubcmdOptional() CommandInfo
- func (c CommandInfo) Usage(lines ...string) CommandInfo
- type HelpGenerator
- type HelpOrVersionRequested
- type Input
- type InputInfo
- func NewArg(id string) InputInfo
- func NewBoolOpt(id string) InputInfo
- func NewFloat32Opt(id string) InputInfo
- func NewFloat64Opt(id string) InputInfo
- func NewIntOpt(id string) InputInfo
- func NewOpt(id string) InputInfo
- func NewUintOpt(id string) InputInfo
- func NewVersionOpt(short byte, long string, cfg VersionOptConfig) InputInfo
- func (in InputInfo) Default(v string) InputInfo
- func (in InputInfo) Env(e string) InputInfo
- func (in InputInfo) Help(blurb string) InputInfo
- func (in InputInfo) Long(name string) InputInfo
- func (in InputInfo) Required() InputInfo
- func (in InputInfo) Short(c byte) InputInfo
- func (in InputInfo) ShortOnly(c byte) InputInfo
- func (in InputInfo) WithHelpGen(hg HelpGenerator) InputInfo
- func (in InputInfo) WithParser(vp ValueParser) InputInfo
- func (in InputInfo) WithValueName(name string) InputInfo
- func (in InputInfo) WithVersioner(ver Versioner) InputInfo
- type MissingArgsError
- type MissingOptionValueError
- type MissingOptionsError
- type ParsedFrom
- type UnknownOptionError
- type UnknownSubcmdError
- type ValueParser
- type VersionOptConfig
- type Versioner
Examples ¶
- CommandInfo.Arg
- CommandInfo.ExtraHelp
- CommandInfo.Opt
- CommandInfo.SubcmdOptional
- CommandInfo.Usage
- DefaultFullHelp
- DefaultShortHelp (Complex)
- DefaultShortHelp (Simple)
- DefaultShortHelp (SimpleWithSubcommands)
- Get (Option)
- Get (PositionalArgs)
- GetAll
- GetAllSeq
- GetOr (Option)
- GetOr (PositionlArgs)
- GetOrFunc
- InputInfo.Default
- InputInfo.Env
- InputInfo.Help
- InputInfo.Long
- InputInfo.Required (Option)
- InputInfo.Required (PostionalArgument)
- InputInfo.Short
- InputInfo.ShortOnly
- InputInfo.WithHelpGen
- InputInfo.WithParser
- InputInfo.WithValueName (Option)
- InputInfo.WithValueName (PositionalArgument)
- Lookup (Option)
- Lookup (PositionalArgs)
- NewFileParser
- NewTimeParser
- ParseDuration
- ParseURL
Constants ¶
This section is empty.
Variables ¶
var ( HelpMsgTextWidth = 90 HelpShortMsgMaxFirstColLen = 24 )
var DefaultHelpInput = NewBoolOpt("help"). Short('h'). Help("Show this help message and exit."). WithHelpGen(DefaultHelpGenerator)
var DefaultVersionOpt = NewVersionOpt('v', "version", VersionOptConfig{
HelpBlurb: "Print the build info version and exit",
})
var ErrNoSubcmd = errors.New("missing subcommand")
Functions ¶
func DefaultFullHelp ¶
func DefaultFullHelp(c *CommandInfo) string
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New("example").
Help("an example command").
Opt(cli.NewOpt("aa").Env("AA").Default("def").Help("an option")).
Opt(cli.NewOpt("bb").
Help("another option that is required and has a really long blurb to show how it will be wrapped").
Required()).
Arg(cli.NewArg("cc").Help("a positional argument")).
Opt(cli.NewBoolOpt("h").
Help("will show how this command looks in the default full help message").
WithHelpGen(func(_ cli.Input, c *cli.CommandInfo) string {
return cli.DefaultFullHelp(c)
}))
_, err := in.ParseThese("-h")
fmt.Println(err)
}
Output: example - an example command usage: example [options] [arguments] options: --aa <arg> an option [default: def] [env: AA] --bb <arg> (required) another option that is required and has a really long blurb to show how it will be wrapped -h will show how this command looks in the default full help message arguments: [cc] a positional argument
func DefaultHelpGenerator ¶
func DefaultHelpGenerator(src Input, c *CommandInfo) string
DefaultHelpGenerator will use DefaultShortHelp if src is the short option, or it'll use DefaultFullHelp if the src is the long option name.
func DefaultShortHelp ¶
func DefaultShortHelp(c *CommandInfo) string
Example (Complex) ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New("example").
Help("an example command").
Opt(cli.NewOpt("aa").Env("AA").Default("def").Help("an option")).
Opt(cli.NewOpt("bb").
Help("another option that is required and has a really long blurb to show how it will be wrapped").
Required()).
Opt(cli.NewOpt("kind-of-a-long-name").
Help("due to this option's name, the blurbs for each option on this command " +
"will begin on their own non-indented lines")).
Arg(cli.NewArg("posarg1").Required().Help("a required positional argument")).
Arg(cli.NewArg("posarg2").Env("PA2").Help("an optional positional argument")).
Opt(cli.NewBoolOpt("h").
Help("will show the default short help message").
WithHelpGen(func(_ cli.Input, c *cli.CommandInfo) string {
return cli.DefaultShortHelp(c)
}))
_, err := in.ParseThese("-h")
fmt.Println(err)
}
Output: example - an example command usage: example [options] [arguments] options: --aa <arg> an option (default: def) [$AA] --bb <arg> another option that is required and has a really long blurb to show how it will be wrapped (required) -h will show the default short help message --kind-of-a-long-name <arg> due to this option's name, the blurbs for each option on this command will begin on their own non-indented lines arguments: <posarg1> a required positional argument (required) [posarg2] an optional positional argument [$PA2]
Example (Simple) ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New("example").
Help("an example command").
Opt(cli.NewOpt("aa").Short('a').Env("AA").Default("def").Help("an option")).
Opt(cli.NewOpt("bb").Short('b').Required().Help("another option")).
Arg(cli.NewArg("cc").Required().Help("a required positional argument")).
Arg(cli.NewArg("dd").Env("PA2").Help("an optional positional argument")).
Opt(cli.NewBoolOpt("h").
Help("will show the default short help message").
WithHelpGen(func(_ cli.Input, c *cli.CommandInfo) string {
return cli.DefaultShortHelp(c)
}))
_, err := in.ParseThese("-h")
fmt.Println(err)
}
Output: example - an example command usage: example [options] [arguments] options: -a, --aa <arg> an option (default: def) [$AA] -b, --bb <arg> another option (required) -h will show the default short help message arguments: <cc> a required positional argument (required) [dd] an optional positional argument [$PA2]
Example (SimpleWithSubcommands) ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New("example").
Help("an example command").
Opt(cli.NewOpt("aa").Short('a').Env("AA").Default("def").Help("an option")).
Opt(cli.NewOpt("bb").Short('b').Required().Help("another option")).
Subcmd(cli.NewCmd("subcommand1").Help("a subcommand")).
Subcmd(cli.NewCmd("subcommand2").Help("another subcommand")).
Opt(cli.NewBoolOpt("h").
Help("will show the default short help message").
WithHelpGen(func(_ cli.Input, c *cli.CommandInfo) string {
return cli.DefaultShortHelp(c)
}))
_, err := in.ParseThese("-h")
fmt.Println(err)
}
Output: example - an example command usage: example [options] <command> options: -a, --aa <arg> an option (default: def) [$AA] -b, --bb <arg> another option (required) -h will show the default short help message commands: subcommand1 a subcommand subcommand2 another subcommand
func Fatal ¶ added in v0.5.0
Fatal logs the given value to Stderr prefixed by "error: " and then exits the program with the given code.
func Get ¶
Get gets the parsed input value with the given id in the given Command and converts the value to the given type T through an untested type assertion. This function will panic if the value isn't found or if the value can't be converted to type T. Therefore, this function would typically only be used to retrieve parsed values for inputs that are required with (which means there will be a parsing error first if there is no value present) or that have a default value specified (which means there will always be at least one parsed value no matter what). In those cases, this function will be completely safe to use.
To check whether the value is found without panicking if it isn't, see Lookup.
Example (Option) ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
c := cli.New().
Opt(cli.NewOpt("a")).
Opt(cli.NewOpt("b")).
ParseTheseOrExit("-b=hello")
// The following line would panic because 'a' isn't present.
// a := cli.Get[string](c, "a")
b := cli.Get[string](c, "b")
fmt.Printf("b: %q\n", b)
}
Output: b: "hello"
Example (PositionalArgs) ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
c := cli.New().
Arg(cli.NewArg("a")).
Arg(cli.NewArg("b")).
ParseTheseOrExit("hello")
// The following line would panic because 'a' isn't present.
// b := cli.Get[string](c, "b")
a := cli.Get[string](c, "a")
fmt.Printf("a: %q\n", a)
}
Output: a: "hello"
func GetAll ¶ added in v0.3.0
GetAll returns all parsed values present for the given id. It converts each value to the given type T through an untested type assertion (so this will panic if any value found can't be converted to type T).
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
c := cli.New().
Opt(cli.NewIntOpt("a").Default("0")).
ParseTheseOrExit("-a", "1", "-a", "2", "-a", "3")
a := cli.GetAll[int](c, "a")
fmt.Printf("%+#v\n", a)
}
Output: []int{0, 1, 2, 3}
func GetAllSeq ¶ added in v0.3.0
GetAllSeq returns an iterator over each parsed value that has the given id. The iterator yields the same values that would be returned by GetAll(c, id) but without constructing the slice.
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
c := cli.New().
Opt(cli.NewOpt("a").Default("Lorem")).
ParseTheseOrExit(
"-a", "ipsum",
"-a", "dolor",
"-a", "sit",
"-a", "amet")
for str := range cli.GetAllSeq[string](c, "a") {
fmt.Printf("%v\n", str)
}
}
Output: Lorem ipsum dolor sit amet
func GetOr ¶
GetOr looks for a parsed input value with the given id in the given Command and converts the value to the given type T through an untested type assertion (so this will panic if the value is found but can't be converted to type T). If the value isn't found, the given fallback value will be returned. To check whether the value is found instead of using a fallback value, see Lookup.
Example (Option) ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
c := cli.New().
Opt(cli.NewOpt("a")).
Opt(cli.NewOpt("b")).
ParseTheseOrExit("-a=hello")
a := cli.Get[string](c, "a")
b := cli.GetOr(c, "b", "world")
fmt.Printf("a: %q\n", a)
fmt.Printf("b: %q\n", b)
}
Output: a: "hello" b: "world"
Example (PositionlArgs) ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
c := cli.New().
Arg(cli.NewArg("a")).
Arg(cli.NewArg("b")).
ParseTheseOrExit("hello")
a := cli.Get[string](c, "a")
b := cli.GetOr(c, "b", "world")
fmt.Printf("a: %q\n", a)
fmt.Printf("b: %q\n", b)
}
Output: a: "hello" b: "world"
func GetOrFunc ¶ added in v0.3.0
GetOrFunc is like GetOr in that it looks for a parsed input value with the given id in the given Command and converts the value to the given type T through an untested type assertion (so this will panic if the value is found but can't be converted to type T). However, if the value isn't found, it will run the provided function fn in order to create and return the fallback value. To check whether the value is found instead of using a fallback, see Lookup.
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
c := cli.New().
Opt(cli.NewOpt("a")).
Opt(cli.NewOpt("b")).
ParseTheseOrExit("-a", "hello")
a := cli.GetOrFunc(c, "a", func() string { return "bye" })
b := cli.GetOrFunc(c, "b", func() string { return "world" })
fmt.Printf("a: %q\n", a)
fmt.Printf("b: %q\n", b)
}
Output: a: "hello" b: "world"
func Lookup ¶
Lookup looks for a parsed input value with the given id in the given Command and converts the value to the given type T through an untested type assertion (so this will panic if the value is found and can't be converted to type T). So if the input is present, the typed value will be returned and the boolean will be true. Otherwise, the zero value of type T will be returned and the boolean will be false.
Example (Option) ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
c := cli.New().
Opt(cli.NewOpt("a")).
Opt(cli.NewOpt("b")).
ParseTheseOrExit("-b=hello")
a, hasA := cli.Lookup[string](c, "a")
b, hasB := cli.Lookup[string](c, "b")
fmt.Printf("a: %q, %v\n", a, hasA)
fmt.Printf("b: %q, %v\n", b, hasB)
}
Output: a: "", false b: "hello", true
Example (PositionalArgs) ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
c := cli.New().
Arg(cli.NewArg("a")).
Arg(cli.NewArg("b")).
ParseTheseOrExit("hello")
a, hasA := cli.Lookup[string](c, "a")
b, hasB := cli.Lookup[string](c, "b")
fmt.Printf("a: %q, %v\n", a, hasA)
fmt.Printf("b: %q, %v\n", b, hasB)
}
Output: a: "hello", true b: "", false
func ParseBool ¶
ParseBool returns the boolean value represented by the given string. See strconv.ParseBool for more info.
func ParseDuration ¶
ParseDuration uses the standard library time.ParseDuration function to parse and return the time.Duration value represented by the given string.
Example ¶
package main
import (
"fmt"
"time"
"github.com/steverusso/cli"
)
func main() {
in := cli.New().
Opt(cli.NewOpt("d").WithParser(cli.ParseDuration))
c := in.ParseTheseOrExit("-d", "1h2m3s")
fmt.Println(cli.Get[time.Duration](c, "d"))
_, err := in.ParseThese("-d", "not_a_duration")
fmt.Println(err)
}
Output: 1h2m3s parsing option 'd': time: invalid duration "not_a_duration"
func ParseFloat32 ¶
ParseFloat32 returns the float32 value represented by the given string. It unwraps any strconv.NumError returned by strconv.ParseFloat for a slightly cleaner error message.
func ParseFloat64 ¶
ParseFloat64 returns the float64 value represented by the given string. It unwraps any strconv.NumError returned by strconv.ParseFloat for a slightly cleaner error message.
func ParseInt ¶
ParseInt returns the int value represented by the given string. It unwraps any strconv.NumError returned by strconv.ParseInt for a slightly cleaner error message.
func ParseURL ¶
ParseURL uses the standard library url.Parse function to parse and return the *url.URL value represented by the given string.
Example ¶
package main
import (
"fmt"
"net/url"
"github.com/steverusso/cli"
)
func main() {
in := cli.New().
Opt(cli.NewOpt("u").WithParser(cli.ParseURL))
c := in.ParseTheseOrExit("-u", "https://pkg.go.dev/github.com/steverusso/cli#ParseURL")
fmt.Println(cli.Get[*url.URL](c, "u"))
_, err := in.ParseThese("-u", "ftp://usr:pass[wd]@svr.com")
fmt.Println(err)
}
Output: https://pkg.go.dev/github.com/steverusso/cli#ParseURL parsing option 'u': parse "ftp://usr:pass[wd]@svr.com": net/url: invalid userinfo
func ParseUint ¶
ParseUint returns the uint value represented by the given string. It unwraps any strconv.NumError returned by strconv.ParseUint for a slightly cleaner error message.
Types ¶
type CommandInfo ¶
type CommandInfo struct {
Name string
Path []string
HelpUsage []string
HelpBlurb string
HelpExtra string
Opts []InputInfo
Args []InputInfo
Subcmds []CommandInfo
// By default, when parsing command line arguments against a CommandInfo that has
// subcommands defined, an error will be returned if there is no subcommand provided.
// However, with this field set to true, there will not be a parsing error if a
// subcommand argument is completely absent, and the parsed subcommand field Subcmd on
// Command will be nil.
IsSubcmdOptional bool
// contains filtered or unexported fields
}
A CommandInfo holds information about the schema of a CLI command. This includes usage information that can form a help message, as well as which options and arguments or subcommands it should expect when parsing. This is data that must be known when parsing in order to properly parse command line arguments. For example, consider the following argument list: {"-a", "b"}. Is "-a" a boolean option and "b" an argument to the command? Or is "b" the option value being provided to the non-boolean option "-a"? The only way for the parser to know is to follow an outline that states which one it is.
The methods on CommandInfo are available to guide library consumers through creating this command schema. Once built, a CommandInfo would typically be used by calling CommandInfo.ParseOrExit or CommandInfo.Parse.
func New ¶ added in v0.3.0
func New(name ...string) CommandInfo
New is intented to initialize a new root command. If no name is provided, it will use runtime information to get the module name and use that for the command's name. Anything more than a single name provided is ignored.
func NewCmd ¶
func NewCmd(name string) CommandInfo
NewCmd returns a new CommandInfo with the Name field set to name and Path field set to a single element slice of name. This function will panic if name is empty or contains whitespace.
func (CommandInfo) Arg ¶
func (c CommandInfo) Arg(pa InputInfo) CommandInfo
Arg adds pa as a positional argument to this CommandInfo. This method will panic if this command already has one or more subcommands (because positional arguments and subcommands are mutually exclusive), or if pa has any option names set, or if pa is required but any previously positional argument is not required (because required positional arguments cannot come after optional ones).
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
c := cli.New().
Arg(cli.NewArg("name")).
ParseTheseOrExit("alice")
fmt.Println(cli.Get[string](c, "name"))
}
Output: alice
func (CommandInfo) ExtraHelp ¶
func (c CommandInfo) ExtraHelp(extra string) CommandInfo
ExtraHelp adds an "overview" section to the Command's help message. This is typically for longer-form content that wouldn't fit well within the 1-2 sentence "blurb."
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New("example").
Help("an example command").
ExtraHelp("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.")
_, err := in.ParseThese("--help")
fmt.Println(err)
}
Output: example - an example command overview: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. usage: example [options] options: -h, --help Show this help message and exit.
func (CommandInfo) Help ¶
func (c CommandInfo) Help(blurb string) CommandInfo
Help sets the HelpBlurb field of this command to blurb.
func (CommandInfo) Opt ¶
func (c CommandInfo) Opt(o InputInfo) CommandInfo
Opt adds o as an option to this CommandInfo. This method will panic if the option has neither a long or short name set (this should never happen when using the builder pattern starting with the NewOpt function or its siblings).
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
c := cli.New().
Opt(cli.NewOpt("a")).
ParseTheseOrExit("-a", "hello")
fmt.Println(cli.Get[string](c, "a"))
}
Output: hello
func (*CommandInfo) Parse ¶
func (in *CommandInfo) Parse() (*Command, error)
Parse calls CommandInfo.ParseThese using os.Args as the command line arguments. See that method's documentation for more info.
func (CommandInfo) ParseOrExit ¶
func (in CommandInfo) ParseOrExit() *Command
ParseOrExit calls CommandInfo.ParseTheseOrExit using os.Args as the command line arguments. See that method's documentation for more info.
func (*CommandInfo) ParseThese ¶ added in v0.5.0
func (in *CommandInfo) ParseThese(args ...string) (*Command, error)
ParseThese prepares and validates this CommandInfo if it hasn't been already. This involves setting the Path field of this command and all subcommands, as well as ensuring there are no logical errors in the structure of this command (such as a command containing duplicate option names). This method will panic if there are any schema errors in this CommandInfo.
Assuming a clean schema, this method then parses input against this CommandInfo using args as the command line arguments. If there is a help or version input found on any command level, this function will return a HelpOrVersionRequested error.
func (CommandInfo) ParseTheseOrExit ¶ added in v0.5.0
func (in CommandInfo) ParseTheseOrExit(args ...string) *Command
ParseTheseOrExit parses input against this CommandInfo using args as the command line arguments. If there is a HelpOrVersionRequested error, it will print the message and exit with status code 0. If there was any other error, it will print the error's message to Stderr and exit with status code 1.
func (CommandInfo) Subcmd ¶
func (c CommandInfo) Subcmd(sc CommandInfo) CommandInfo
Subcmd adds the given CommandInfo sc as a subcommand under c. This function will panic if c already has at least one positional argument because commands cannot contain both positional arguments and subcommands simultaneously.
func (CommandInfo) SubcmdOptional ¶ added in v0.6.0
func (c CommandInfo) SubcmdOptional() CommandInfo
SubcmdOptional sets the IsSubcmdOptional field of this CommandInfo to true. See that field's documentation to learn more about how it is used.
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
// Simple command-with-subcommand structure. Parsing the top-level
// command will return an error if a subcommand isn't provided.
scReq := cli.New("example").
Help("an example program").
Subcmd(cli.NewCmd("cmd1"))
// Same command structure as above, except parsing will
// NOT return an error if a subcommand isn't provided.
scOpt := cli.New("example").
Help("an example program").
Subcmd(cli.NewCmd("cmd1")).
SubcmdOptional()
c, _ := scReq.ParseThese("cmd1")
fmt.Printf("have subcommand %q\n", c.Subcmd.Name)
_, err := scReq.ParseThese()
fmt.Println("err:", err)
c, err = scOpt.ParseThese()
fmt.Printf("err: %v, c.Subcmd: %v\n", err, c.Subcmd) // using c.Subcmd.Name here would panic
}
Output: have subcommand "cmd1" err: missing subcommand err: <nil>, c.Subcmd: <nil>
func (CommandInfo) Usage ¶
func (c CommandInfo) Usage(lines ...string) CommandInfo
Usage overrides the default "usage" lines in the command's help message. These are intended to show the user some different ways to invoke this command using whatever combinations of options / arguments / subcommands.
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New("example").
Help("an example command").
Usage(
"example [--aa <arg>]",
"example [-h]",
).
Opt(cli.NewOpt("aa").Help("an option"))
_, err := in.ParseThese("--help")
fmt.Println(err)
}
Output: example - an example command usage: example [--aa <arg>] example [-h] options: --aa <arg> an option -h, --help Show this help message and exit.
type HelpGenerator ¶
type HelpGenerator = func(Input, *CommandInfo) string
HelpGenerator describes any function that will return a help message based on the Input that triggered it and the CommandInfo of which it is a member. See DefaultHelpGenerator for an example.
type HelpOrVersionRequested ¶ added in v0.5.0
type HelpOrVersionRequested struct {
Msg string
}
HelpOrVersionRequested is returned by the parsing code to signal that a help or version option was encountered.
func (HelpOrVersionRequested) Error ¶ added in v0.5.0
func (h HelpOrVersionRequested) Error() string
type Input ¶
type Input struct {
Value any
ID string
RawValue string
From ParsedFrom
}
Input is a parsed option value or positional argument value along with other information such as the input ID it corresponds to and where it was parsed from.
type InputInfo ¶
type InputInfo struct {
ID string
NameShort byte
NameLong string
HelpBlurb string
EnvVar string
IsBoolOpt bool
IsRequired bool
StrDefault string
HasStrDefault bool
ValueName string
ValueParser ValueParser
// If an input is encountered during parsing that has either HelpGen or Versioner
// set, the parser will return HelpOrVersionRequested with whatever either of those
// functions return as the Msg. See CommandInfo.ParseThese to learn more.
//
// Note: adding an input that has HelpGen set to a CommandInfo will prevent this
// library from automatically adding the DefaultHelpInput to that command.
HelpGen HelpGenerator
Versioner Versioner
}
func NewArg ¶
NewArg returns a new positional argument input. By default, the arg's display name will be the provided id, but this can be overidden with InputInfo.WithValueName method.
func NewBoolOpt ¶
NewBoolOpt returns a new boolean option. If no value is provided to this option when parsing, it will have a "parsed" value of true. If any value is provided, the ParseBool value parser is used. Any other parser set by the user for this option will be ignored.
func NewFloat32Opt ¶
NewFloat32Opt returns a new option that uses the ParseFloat32 value parser.
func NewFloat64Opt ¶
NewFloat64Opt returns a new option that uses the ParseFloat64 value parser.
func NewOpt ¶
NewOpt returns a new non-boolean option with no parser, which means it will just receive the raw string of any provided value. If id is more than a single character long, it will be this option's long name. If id is only a single character, it will be this option's short name instead. In either case, the long name can be reset using the InputInfo.Long method.
func NewUintOpt ¶
NewUintOpt returns a new option that uses the ParseUint value parser.
func NewVersionOpt ¶ added in v0.5.0
func NewVersionOpt(short byte, long string, cfg VersionOptConfig) InputInfo
NewVersionOpt returns a input that will the Versioner field set to a function that outputs information based on the given configuration values. At a minimum, the default version message will always contain the Go module version obtained from debug.BuildInfo. Version inputs, similar to help inputs, cause this library's parsing to return a HelpOrVersionRequested error. This function will panic if the given long name is empty and the given short name is either 0 or '-'.
func (InputInfo) Default ¶
Default sets v as the default string value for this InputInfo, which will be gathered and parsed using this InputInfo's parser before any CLI arguments or environment variables. This will always happen as the first step in parsing a command, so if a default value is set here, then at least it will always be present meaning it's safe to use [InputInfo.Get] to get its parsed value.
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New().Opt(cli.NewIntOpt("flag").Default("1234"))
c1 := in.ParseTheseOrExit()
fmt.Println(cli.Get[int](c1, "flag")) // Default value present for 'flag' even though no CLI arg was provided.
c2 := in.ParseTheseOrExit("--flag", "5678")
fmt.Println(cli.Get[int](c2, "flag"))
}
Output: 1234 5678
func (InputInfo) Env ¶
Env sets the name of the environment variable for this InputInfo. The parser will parse the value of that environment variable for this input if it is set.
Example ¶
package main
import (
"fmt"
"os"
"github.com/steverusso/cli"
)
func main() {
os.Setenv("FLAG", "hello")
c := cli.New().
Opt(cli.NewOpt("flag").Env("FLAG")).
ParseTheseOrExit()
fmt.Println(cli.Get[string](c, "flag"))
}
Output: hello
func (InputInfo) Help ¶
Help sets the brief help blurb for this option or positional argument.
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New("example").
Help("example program").
Opt(cli.NewOpt("aa").Help("a short one or two sentence blurb"))
_, err := in.ParseThese("-h")
fmt.Println(err)
}
Output: example - example program usage: example [options] options: --aa <arg> a short one or two sentence blurb -h, --help Show this help message and exit.
func (InputInfo) Long ¶
Long sets the option long name to the given name. Since an option's long name will be the input ID by default, this method is really only necessary when the long name must differ from the input ID.
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New("example").
Help("example program").
Opt(cli.NewOpt("id1").Help("long name is the id by default")).
Opt(cli.NewOpt("id2").Long("long-name").Help("long name is set to something other than the id"))
_, err := in.ParseThese("-h")
fmt.Println(err)
}
Output: example - example program usage: example [options] options: -h, --help Show this help message and exit. --id1 <arg> long name is the id by default --long-name <arg> long name is set to something other than the id
func (InputInfo) Required ¶
Required marks this InputInfo as required, which means an error will be returned when parsing if a value is not provided. If this is a positional argument, it must be added to a command before any optional positional arguments. Required options, however, can be added in any order. See the "Command Line Syntax" section at the top of the docs
Example (Option) ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New().
Opt(cli.NewOpt("a")).
Opt(cli.NewOpt("b").Required())
c, _ := in.ParseThese("-a", "hello", "-b", "world")
fmt.Println(
cli.Get[string](c, "a"),
cli.Get[string](c, "b"),
)
_, err := in.ParseThese()
fmt.Println(err)
}
Output: hello world cli.test: missing the following required options: -b
Example (PostionalArgument) ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New().
Arg(cli.NewArg("a").Required()).
Arg(cli.NewArg("b"))
c, _ := in.ParseThese("hello", "world")
fmt.Println(
cli.Get[string](c, "a"),
cli.Get[string](c, "b"),
)
_, err := in.ParseThese()
fmt.Println(err)
}
Output: hello world cli.test: missing the following required arguments: a
func (InputInfo) Short ¶
Short sets this option's short name to the given character. In order to create an option that has a short name but no long name, see InputInfo.ShortOnly.
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New().
Opt(cli.NewOpt("flag").Short('f'))
c1 := in.ParseTheseOrExit("-f", "hello")
fmt.Println(cli.Get[string](c1, "flag"))
c2 := in.ParseTheseOrExit("--flag", "world")
fmt.Println(cli.Get[string](c2, "flag"))
}
Output: hello world
func (InputInfo) ShortOnly ¶
ShortOnly sets this option's short name to the given character and removes any long name it may have had at this point. In order to create an option that has both a short and long name, see InputInfo.Short. Use InputInfo.Long to add a long name back.
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New().
Opt(cli.NewOpt("flag").ShortOnly('f'))
c := in.ParseTheseOrExit("-f", "hello")
fmt.Println(cli.Get[string](c, "flag"))
_, err := in.ParseThese("--flag", "helloworld")
fmt.Println(err)
}
Output: hello cli.test: unknown option '--flag'
func (InputInfo) WithHelpGen ¶
func (in InputInfo) WithHelpGen(hg HelpGenerator) InputInfo
WithHelpGen sets the HelpGen field of this input. See the HelpGen field documentation on InputInfo to learn more about how it is used.
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New("example").
Help("an example program").
Opt(cli.NewOpt("a")).
Opt(cli.NewOpt("b")).
Opt(cli.NewBoolOpt("h").
Help("will show a custom help message").
WithHelpGen(func(o cli.Input, c *cli.CommandInfo) string {
return "totally custom help message\n" +
"use data on the provided CommandInfo to form a custom help message\n" +
fmt.Sprintf("for example, this command has %d options including this one", len(c.Opts))
}))
_, err := in.ParseThese("-h")
fmt.Println(err)
}
Output: totally custom help message use data on the provided CommandInfo to form a custom help message for example, this command has 3 options including this one
func (InputInfo) WithParser ¶
func (in InputInfo) WithParser(vp ValueParser) InputInfo
WithParser sets the InputInfo's parser to the given ValueParser. This will override any parser that has been set up until this point. Providing nil as the parser will restore the default behavior of just using the plain string value when this InputInfo is parsed.
Example ¶
package main
import (
"fmt"
"image"
"strconv"
"strings"
"github.com/steverusso/cli"
)
func main() {
// This is a horrible parsing function for coordinates.
// It's just for example purposes.
pointParser := func(s string) (any, error) {
xStr, yStr, _ := strings.Cut(s, ",")
x, _ := strconv.Atoi(xStr)
y, _ := strconv.Atoi(yStr)
return image.Point{X: x, Y: y}, nil
}
c := cli.New().
Opt(cli.NewOpt("aa").WithParser(pointParser)).
ParseTheseOrExit("--aa", "3,7")
fmt.Printf("%+#v\n", cli.Get[image.Point](c, "aa"))
}
Output: image.Point{X:3, Y:7}
func (InputInfo) WithValueName ¶
WithValueName sets the display name of this InputInfo's argument value. For non-boolean options, it's the argument of the option. For positional arguments, it's the argument name itself.
Example (Option) ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New("example").
Help("example program").
Opt(cli.NewOpt("aa").WithValueName("str").Help("it says '<str>' above instead of '<arg>'"))
_, err := in.ParseThese("--help")
fmt.Println(err)
}
Output: example - example program usage: example [options] options: --aa <str> it says '<str>' above instead of '<arg>' -h, --help Show this help message and exit.
Example (PositionalArgument) ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New("example").
Help("example program").
Arg(cli.NewArg("aa").WithValueName("filename").Help("it says '[filename]' above instead of '[aa]'"))
_, err := in.ParseThese("--help")
fmt.Println(err)
}
Output: example - example program usage: example [options] [arguments] options: -h, --help Show this help message and exit. arguments: [filename] it says '[filename]' above instead of '[aa]'
func (InputInfo) WithVersioner ¶ added in v0.5.0
WithVersioner will set this input's Versioner to the given Versioner. This will turn this input into one that, similar to help inputs, causes the parsing to return a HelpOrVersionRequested error. See NewVersionOpt for a convenient way to create version inputs.
type MissingArgsError ¶
type MissingArgsError struct {
CmdInfo *CommandInfo
Names []string
}
func (MissingArgsError) Error ¶
func (mae MissingArgsError) Error() string
func (MissingArgsError) Is ¶
func (mae MissingArgsError) Is(err error) bool
type MissingOptionValueError ¶
type MissingOptionValueError struct {
CmdInfo *CommandInfo
Name string
}
func (MissingOptionValueError) Error ¶
func (mov MissingOptionValueError) Error() string
type MissingOptionsError ¶
type MissingOptionsError struct {
CmdInfo *CommandInfo
Names []string
}
func (MissingOptionsError) Error ¶
func (moe MissingOptionsError) Error() string
func (MissingOptionsError) Is ¶
func (moe MissingOptionsError) Is(err error) bool
type ParsedFrom ¶
type ParsedFrom struct {
Env string // Came from this env var's name.
Opt string // Came from this provided option name.
Arg int // Appeared as the nth positional argument starting from 1.
Default bool // Came from a provided default value.
}
ParsedFrom describes where an Input is parsed from. The place it came from will be the only non-zero field of this struct.
type UnknownOptionError ¶
type UnknownOptionError struct {
CmdInfo *CommandInfo
Name string
}
func (UnknownOptionError) Error ¶
func (uoe UnknownOptionError) Error() string
type UnknownSubcmdError ¶
type UnknownSubcmdError struct {
CmdInfo *CommandInfo
Name string
}
func (UnknownSubcmdError) Error ¶
func (usce UnknownSubcmdError) Error() string
type ValueParser ¶
ValueParser describes any function that takes a string and returns some value or an error. This is the signature of any input value parser. See ParseBool, ParseInt, and the other provided parsers for some examples.
func NewFileParser ¶
func NewFileParser(vp ValueParser) ValueParser
NewFileParser returns a ValueParser that will treat an input string as a file path and use given parser to parse the content of the file at that path.
Example ¶
package main
import (
"fmt"
"github.com/steverusso/cli"
)
func main() {
in := cli.New().
Opt(cli.NewOpt("i").WithParser(cli.NewFileParser(cli.ParseInt))).
Opt(cli.NewOpt("s").WithParser(cli.NewFileParser(nil)))
c, _ := in.ParseThese(
"-i", "testdata/sample_int",
"-s", "testdata/sample_int",
)
fmt.Println(cli.Get[int](c, "i"))
fmt.Printf("%q\n", cli.Get[string](c, "s"))
_, err := in.ParseThese("-i", "testdata/sample_empty")
fmt.Println(err)
_, err = in.ParseThese("-i", "path_that_doesnt_exist")
fmt.Println(err)
}
Output: 12345 "12345" parsing option 'i': invalid syntax parsing option 'i': open path_that_doesnt_exist: no such file or directory
func NewTimeParser ¶
func NewTimeParser(layout string) ValueParser
NewTimeParser returns a ValueParser that will use the standard library time.Parse function with the given layout string to parse and return a time.Time from a given string.
Example ¶
package main
import (
"fmt"
"time"
"github.com/steverusso/cli"
)
func main() {
in := cli.New().
Opt(cli.NewOpt("t").WithParser(cli.NewTimeParser("2006-01-02")))
c := in.ParseTheseOrExit("-t", "2025-04-12")
fmt.Println(cli.Get[time.Time](c, "t"))
_, err := in.ParseThese("-t", "hello")
fmt.Println(err)
}
Output: 2025-04-12 00:00:00 +0000 UTC parsing option 't': parsing time "hello" as "2006-01-02": cannot parse "hello" as "2006"
type VersionOptConfig ¶ added in v0.5.0
VersionOptConfig is used to pass customization values to NewVersionOpt.