cli

package module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2025 License: 0BSD Imports: 11 Imported by: 0

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:

  1. Options: arguments that begin with "-" or "--" and may or may not require a value.
  2. Positional Arguments: arguments that are identified by the order in which they appear among other positional arguments.
  3. 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:

  1. 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.
  2. 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

Examples

Constants

This section is empty.

Variables

View Source
var DefaultHelpInput = NewBoolOpt("help").
	Short('h').
	Help("Show this help message and exit.").
	WithHelpGen(DefaultHelpGenerator)
View Source
var DefaultVersionOpt = NewVersionOpt('v', "version", VersionOptConfig{
	HelpBlurb: "Print the build info version and exit",
})
View Source
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

func Fatal(code int, v any)

Fatal logs the given value to Stderr prefixed by "error: " and then exits the program with the given code.

func Get

func Get[T any](c *Command, id string) T

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. To check whether the value is found instead of panicking, 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

func GetAll[T any](c *Command, id string) []T

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

func GetAllSeq[T any](c *Command, id string) iter.Seq[T]

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

func GetOr[T any](c *Command, id string, fallback T) T

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

func GetOrFunc[T any](c *Command, id string, fn func() T) T

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.GetOr(c, "a", "")
	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

func Lookup[T any](c *Command, id string) (T, bool)

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

func ParseBool(s string) (any, error)

ParseBool returns the boolean value represented by the given string. See strconv.ParseBool for more info.

func ParseDuration

func ParseDuration(s string) (any, error)

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

func ParseFloat32(s string) (any, error)

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

func ParseFloat64(s string) (any, error)

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

func ParseInt(s string) (any, error)

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

func ParseURL(s string) (any, error)

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", "b@d://.com")
	fmt.Println(err)
}
Output:

https://pkg.go.dev/github.com/steverusso/cli#ParseURL
parsing option 'u': parse "b@d://.com": first path segment in URL cannot contain colon

func ParseUint

func ParseUint(s string) (any, error)

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 Command

type Command struct {
	Name    string
	Inputs  []Input
	Surplus []string
	Subcmd  *Command
}

Command is a parsed command structure.

type CommandInfo

type CommandInfo struct {
	Name      string
	Path      []string
	HelpUsage []string
	HelpBlurb string
	HelpExtra string
	Opts      []InputInfo
	Args      []InputInfo
	Subcmds   []CommandInfo
	// contains filtered or unexported fields
}

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

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

func (CommandInfo) Opt

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)

ParseOrExit will parse input based on this CommandInfo. If no function arguments are provided, the os.Args will be used.

func (CommandInfo) ParseOrExit

func (in CommandInfo) ParseOrExit() *Command

ParseOrExit will parse input based on this CommandInfo. If help was requested, it will print the help message and exit the program successfully (status code 0). If there is any other error, it will print the error and exit the program with failure (status code 1). The input parameter semantics are the same as CommandInfo.Parse.

func (*CommandInfo) ParseThese added in v0.5.0

func (in *CommandInfo) ParseThese(args ...string) (*Command, error)

func (CommandInfo) ParseTheseOrExit added in v0.5.0

func (in CommandInfo) ParseTheseOrExit(args ...string) *Command

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) 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
}

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

	HelpGen   HelpGenerator
	Versioner Versioner
}

func NewArg

func NewArg(id string) InputInfo

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

func NewBoolOpt(id string) InputInfo

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

func NewFloat32Opt(id string) InputInfo

NewFloat32Opt returns a new option that uses the ParseFloat32 value parser.

func NewFloat64Opt

func NewFloat64Opt(id string) InputInfo

NewFloat64Opt returns a new option that uses the ParseFloat64 value parser.

func NewIntOpt

func NewIntOpt(id string) InputInfo

NewIntOpt returns a new option that uses the ParseInt value parser.

func NewOpt

func NewOpt(id string) InputInfo

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

func NewUintOpt(id string) InputInfo

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

func (in InputInfo) Default(v string) InputInfo

func (InputInfo) Env

func (in InputInfo) Env(e string) InputInfo

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

func (in InputInfo) Help(blurb string) InputInfo

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

func (in InputInfo) Long(name string) InputInfo

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

func (in InputInfo) Required() InputInfo

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
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
missing the following required arguments: a

func (InputInfo) Short

func (in InputInfo) Short(c byte) InputInfo

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

func (in InputInfo) ShortOnly(c byte) InputInfo

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
unknown option '--flag'

func (InputInfo) WithHelpGen

func (in InputInfo) WithHelpGen(hg HelpGenerator) InputInfo

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() {
	pointParser := func(s string) (any, error) {
		comma := strings.IndexByte(s, ',')
		x, _ := strconv.Atoi(s[:comma])
		y, _ := strconv.Atoi(s[comma+1:])
		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

func (in InputInfo) WithValueName(name string) InputInfo

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

func (in InputInfo) WithVersioner(ver Versioner) InputInfo

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{ 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{ Name string }

func (MissingOptionValueError) Error

func (mov MissingOptionValueError) Error() string

type MissingOptionsError

type MissingOptionsError struct{ 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{ Name string }

func (UnknownOptionError) Error

func (uoe UnknownOptionError) Error() string

type UnknownSubcmdError

type UnknownSubcmdError struct{ Name string }

func (UnknownSubcmdError) Error

func (usce UnknownSubcmdError) Error() string

type ValueParser

type ValueParser = func(string) (any, error)

ValueParser describes any function that takes a string and returns some type 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

type VersionOptConfig struct {
	HelpBlurb        string
	IncludeGoVersion bool
}

VersionOptConfig is used to pass customization values to NewVersionOpt.

type Versioner added in v0.5.0

type Versioner = func(Input) string

Versioner describes any function that will return a version string based on the Input that triggered it. See DefaultHelpGenerator for an example.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL