This module implements a fast and lightweight declarative command line parser, aiming to simplify the creation of user-friendly command-line interfaces.
Key features:
- Arbitrary command nesting.
- Type-safe, declarative parsing.
- Automatic generation of help output.
Examples
Greeting program
Example:
import experimental/cmdline import std/sugar type Args = object count: Natural name: string var cli = commandBuilder(Args) .name("hello") .describe("simple greeting program") .initCli() cli.addHelpFlag() cli.flagBuilder() .name("count") .parser(Natural, (opt, val, var args) => (args.count = val)) .describe("number of greetings") .addTo(cli) cli.flagBuilder() .name("name") .parser(string, (opt, val, var args) => (args.name = val)) .describe("the person to greet") .addTo(cli) let args = cli.run(defaults = Args(count: 1)) for _ in 1..args.count: if args.name == "": echo "Hello!" else: echo "Hello ", args.name, "!"
What this looks like when run:
$ ./hello --count 3 Hello! Hello! Hello!
The help page is generated for you:
$ ./hello --help simple greeting program Usage: hello [OPTIONS] Options: --help display help message --count <VALUE> number of greetings --name <VALUE> the person to greet
Comes with error handling, too:
$ ./hello --count=no error: invalid value for '--count <VALUE>': invalid integer: no Usage: hello [OPTIONS]
Program with subcommands
Example: cmd: -r:off
import experimental/cmdline import std/setutils import std/sugar type Operation = enum Ls Rm LsArgs = object paths: seq[string] RmOpt {.pure.} = enum Force Recursive RmArgs = object opts: set[RmOpt] paths: seq[string] Config = object case op: Operation of Ls: ls: LsArgs of Rm: rm: RmArgs var cli = commandBuilder(Config) .name("cmd") .describe("multi tool") .initCli() cli.addHelpFlag(RootCommand, "help", "h") let lsCmd = cli.commandBuilder() .name("ls") .describe("list paths") .parser((_, var cfg) => (cfg = Config(op: Ls))) .addTo(cli, RootCommand) cli.addHelpFlag(lsCmd) cli.positionalBuilder() .name("PATH") .describe("path(s) to list, default to current directory") .optional() .catchAll() .parser(string, (val, var cfg) => cfg.ls.paths.add val) .addTo(cli, lsCmd) let rmCmd = cli.commandBuilder() .name("rm") .describe("remove files") .parser((_, var cfg) => (cfg = Config(op: Rm))) .addTo(cli, RootCommand) cli.addHelpFlag(rmCmd) cli.flagBuilder() .name("force") .alias("f") .describe("force removal") .parser(bool, (_, val, var cfg) => (cfg.rm.opts[Force] = val)) .addTo(cli, rmCmd) cli.flagBuilder() .name("recursive") .alias("r") .describe("recursively remove files") .parser(bool, (_, val, var cfg) => (cfg.rm.opts[Recursive] = val)) .addTo(cli, rmCmd) cli.positionalBuilder() .name("PATH") .describe("path(s) to remove") .catchAll() .parser(string, (val, var cfg) => cfg.rm.paths.add val) .addTo(cli, rmCmd) let config = cli.run() case config.op of Ls: echo "list files at: ", config.ls.paths of Rm: echo "remove flags: ", config.rm.opts echo "remove paths: ", config.rm.paths
What this looks like when run:
$ ./cmd ls / list files at: @["/"] $ ./cmd rm -rf secret remove flags: {Force, Recursive} remove paths: @["secret"]
Generated help pages:
$ ./cmd --help multi tool Usage: cmd [OPTIONS] <COMMAND> Commands: ls list paths rm remove files Options: -h, --help display help message $ ./cmd ls --help list paths Usage: cmd ls [OPTIONS] [PATH]... Arguments: [PATH]... path(s) to list, default to current directory Options: --help display help message $ ./cmd rm --help remove files Usage: cmd rm [OPTIONS] <PATH>... Arguments: <PATH>... path(s) to remove Options: --help display help message -f, --force force removal -r, --recursive recursively remove files
Interacting with the parsing process
cmdline allows registered parsers to interact with the command-line parsing process via a few mechanisms:
Parsers may signal errors in value interpretation by raising a ValueError, which will be processed automatically by the library. Any other exceptions are considered internal errors, and will be propagated directly to caller.
Example:
import experimental/cmdline proc errorParser(key, value: string, acc: var string) = raise newException(ValueError, "some error with: " & value) proc faultyParser(key, value: string, acc: var string) = raise newException(IOError, "something unexpected") var cli = commandBuilder(string).initCli() cli.flagBuilder() .name("error") .parser(errorParser) .addTo(cli) cli.flagBuilder() .name("fault") .parser(faultyParser) .addTo(cli) doAssertRaises(InvalidValueError): discard cli.parse(@["--error=value"]) doAssertRaises(IOError): discard cli.parse(@["--fault=value"])Parsers may control parsing behavior following its parameter by returning an Action. The default action taken if not specified is Action.Continue.
Example:
import experimental/cmdline import std/sugar proc actionParser(key, value: string, acc: var seq[string]): Action = case value of "help": Action.ShowHelp of "noflag": Action.DisableFlagProcessing else: Action.Continue var cli = commandBuilder(seq[string]).initCli() cli.flagBuilder() .name("action") .parser(actionParser) .addTo(cli) # To collect anything that's not a flag cli.positionalBuilder() .name("ANY") .catchAll() .optional() .parser((v, var s) => s.add v) .addTo(cli) doAssertRaises(HelpError): discard cli.parse(@["--action=help", "--invalid-flag"]) doAssert cli.parse( @["start", "--action=none", "--action=noflag", "--action=help"] ) == ["start", "--action=help"]
Types
Action {.pure.} = enum Continue, ## Continue parameter parsing. ShowHelp, ## Abort and show help message. DisableFlagProcessing ## Parameters following this will no longer be ## interpreted as flags.
- Action to be taken after parsing. Source Edit
Cli[T] {.requiresInit.} = object commands: Table[CommandId, CliCommand] ## Lookup mapping of command to lookup tables. parsers: Store[ParameterId, ParserAny[T]] ## Parser to process input for ParameterId. names: Store[ParameterId, string] ## Canonical names for all ParameterIds. aliases: Table[ParameterId, seq[string]] ## Mapping of ParameterId to aliases. parents: Store[ParameterId, ParameterId] ## Mapping of ParameterId to their parent. usages: Store[ParameterId, string] ## Canonical usage for ParameterIds. placeholders: Store[ParameterId, string] ## Canonical placeholder for ParameterIds. Only used for flags.
-
A command line interface description.
See also:
Source Edit CommandBuilder[T] = object cmdParser: CommandParser[T, Action] cmdName: string aliases: seq[string] usage: string isDefault: bool
-
Builder for command line subcommands.
See also:
Source Edit CommandError = object of ParseError commandName*: string ## Input value causing the error.
- An error parsing command. Source Edit
CommandId = distinct ParameterId
- A command line subcommand. Values of this type are tied to the originating Cli instance. Source Edit
CommandParser[T; R] = proc (command: CommandId; accumulator: var T): R
-
A parser for command parameter with command command. The accumulator passed to run or parse can be accessed and modified via accumulator.
See also:
Source Edit FlagBuilder[T] = object flagParser: ParserAny[T] flagName: string aliases: seq[string] usage: string placeholder: string
-
Builder for command line flags.
See also:
Source Edit FlagError = object of ParseError flagName*: string ## Name of the flag causing the error, as specified by ## input
- An error parsing flags. Source Edit
FlagId = distinct ParameterId
- A command line flag. Values of this type are tied to the originating Cli instance. Source Edit
FlagOptionalParser[T; R] = proc (name: string; value: Option[string]; accumulator: var T): R
-
A parser for flag with name and optional value. The accumulator passed to run or parse can be accessed and modified via accumulator.
See also:
Source Edit FlagOptionalTypedParser[T; U; R] = proc (name: string; value: Option[U]; accumulator: var T): R
- Typed variant of FlagOptionalParser. Source Edit
FlagParser[T; R] = proc (name, value: string; accumulator: var T): R
-
A parser for flag with option and value. The accumulator passed to run or parse can be accessed and modified via accumulator.
See also:
Source Edit FlagTypedParser[T; U; R] = proc (name: string; value: U; accumulator: var T): R
- Typed variant of FlagParser. Source Edit
HelpError = object of ParseError paramName*: string ## Name of the parameter triggering help, as specified by ## input. param*: ParameterId ## Handle to the parameter triggering help.
- Help was requested using Action.ShowHelp. Source Edit
InvalidCommandError = object of CommandError targetCommand*: CommandId ## Handle to the target command
-
The command parsed was rejected by parser.
The ValueError causing this can be found in the parent field.
Source Edit InvalidPositionalError = object of PositionalError positional*: PositionalId ## Handle to the positional
-
The positional parsed was invalid.
The ValueError causing this can be found in the parent field.
Source Edit InvalidValueError = object of FlagError flagValue*: Option[string] ## The string value received. This should always ## be `some(string)` for flags with non-optional ## value. flag*: FlagId ## Handle to the flag.
-
Invalid value passed to a flag.
The ValueError causing this can be found in the parent field.
Source Edit MaybeAction = Action | void
- Typeclass to support parsers returning either Action or nothing. Source Edit
MissingCommandError = object of CommandError
- A required command is missing from input. Source Edit
MissingPositionalError = object of PositionalError positional*: PositionalId ## Handle to the positional
- A required positional parameter is missing from input. Source Edit
MissingValueError = object of FlagError flag*: FlagId ## Handle to the flag
- The flag parsed requires a value but was not provided. Source Edit
ParameterId = distinct uint32
-
A command line parameter. Values of this type are tied to the originating Cli instance.
A ParameterId might be a CommandId, FlagId, or PositionalId. The classify function can be used to distinguish between them.
Source Edit ParameterKind {.pure.} = enum Command, Flag, Positional
- Source Edit
ParseError = object of CatchableError command*: CommandId ## Active command during error. remaining*: seq[string] ## ParameterIds that were not parsed.
- An error during command line parsing. Source Edit
PositionalBuilder[T] = object posParser: PositionalParser[T, Action] posName: string usage: string isOptional: bool isCatchAll: bool
-
Builder for command line positional parameters.
See also:
Source Edit PositionalError = object of ParseError positionalValue*: string ## Input value causing the error
- An error parsing positional parameters. Source Edit
PositionalId = distinct ParameterId
- A command line positional parameter. Values of this type are tied to the originating Cli instance. Source Edit
PositionalParser[T; R] = proc (value: string; accumulator: var T): R
-
A parser for positional parameter with value value. The accumulator passed to run or parse can be accessed and modified via accumulator.
See also:
Source Edit TypedPositionalParser[T; U; R] = proc (value: U; accumulator: var T): R
- Typed variant of PositionalParser. Source Edit
UnknownCommandError = object of CommandError
- The command parsed was not recognized. Source Edit
UnknownFlagError = object of FlagError flagValue*: Option[string] ## Inline value of flag causing error
- The flag parsed was not recognized. Source Edit
UnknownPositionalError = object of PositionalError
- The positional parsed was not recognized. Source Edit
Consts
RootCommand = 0'u32
- The top-level command of Cli Source Edit
Procs
proc `==`(a, b: ParameterId): bool {.borrow, ...raises: [], tags: [].}
- Source Edit
proc `==`(a, b: PositionalId): bool {.borrow, ...raises: [], tags: [].}
- Source Edit
proc addHelpFlag[T](cli: var Cli[T]; command: CommandId = RootCommand; name: sink string = "help"; aliases: varargs[string] = []): FlagId {. discardable.}
-
Adds a flag triggering Action.ShowHelp with the given name and aliases.
See also:
Source Edit func addTo[T](b: sink CommandBuilder[T]; cli: var Cli[T]; command: CommandId): CommandId {. discardable.}
-
Adds the command specified by b as a subcommand of command.
A subcommand can only be added to command if:
- command has no positional parameters.
- The subcommand has a non-empty name.
- Neither the name nor aliases are used by previously added subcommands.
ValueError will be raised if any of the specified constraints are violated.
See also:
Source Edit func addTo[T](b: sink FlagBuilder[T]; cli: var Cli[T]; command: CommandId = RootCommand): FlagId {.discardable.}
-
Adds the flag specified by b to command.
A flag can only be added to command if:
- The flag has a non-empty name.
- Neither the name nor aliases are used by previously added flags.
- A parser or optional parser as set for the flag.
ValueError will be raised if any of the specified constraints are violated.
See also:
Source Edit func addTo[T](b: sink PositionalBuilder[T]; cli: var Cli[T]; command: CommandId = RootCommand): PositionalId {.discardable.}
-
Adds the positional parameter specified by b to command.
A positional parameter can only be added to command if:
- command does not contain any subcommands.
- The parameter has a non-empty name.
- The name is not used by any previously added positional parameters.
- A parser was set for the parameter.
- No catch-all parameter have been added yet.
- For non-optional positionals, no optional parameters have been added yet.
ValueError will be raised if any of the specified constraints are violated.
See also:
Source Edit func alias[T](b: sink CommandBuilder[T]; names: varargs[string]): CommandBuilder[ T]
-
Sets aliases for this command.
This command can then be matched using any of the provided names in addition to its canonical name.
See also:
Example:
import std/sugar var cli = commandBuilder(string) .initCli() cli.commandBuilder() .name("act") .alias("a", "do") .parser((_, var s) => (s = "acted")) .addTo(cli, RootCommand) doAssert cli.parse(@["act"]) == "acted" doAssert cli.parse(@["a"]) == "acted" doAssert cli.parse(@["do"]) == "acted"
Source Edit func alias[T](b: sink FlagBuilder[T]; names: varargs[string]): FlagBuilder[T]
-
Sets aliases for this flag.
The flag can be matched using any of the provided names in addition to its canonical name.
See also:
Example:
import std/sugar var cli = commandBuilder(string) .initCli() cli.flagBuilder() .name("string") .alias("str", "s") .parser(string, (_, val, var str) => (str = val)) .addTo(cli) doAssert cli.parse(@["--string=str"]) == "str" doAssert cli.parse(@["--str=str"]) == "str" doAssert cli.parse(@["-s=str"]) == "str"
Source Edit func catchAll[T](b: sink PositionalBuilder[T]): PositionalBuilder[T]
-
Marks this positional as "catch all". All positional parameters encountered starting at this positional will be handled by the associated parser.
A catch all positional can only be added as the last parameter of a command. No other positional parameters might be added after this.
Example:
import std/sugar var cli = commandBuilder(seq[string]) .initCli() cli.positionalBuilder() .name("STR") .catchAll() .parser((v, var s) => s.add v) .addTo(cli) doAssert cli.parse(@["a", "b", "c"]) == ["a", "b", "c"]
Source Edit func classify(cli: Cli; param: ParameterId): ParameterKind
-
Returns the type of param.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() let strFlag = cli.flagBuilder() .name("str") .parser((_, v, var s) => (s = v)) .addTo(cli) let strPos = cli.positionalBuilder() .name("STR") .parser((v, var s) => (s = v)) .addTo(cli) doAssert cli.classify(ParameterId RootCommand) == ParameterKind.Command doAssert cli.classify(ParameterId strFlag) == ParameterKind.Flag doAssert cli.classify(ParameterId strPos) == ParameterKind.Positional
Source Edit func commandBuilder(T: typedesc): CommandBuilder[T]
- Creates a new CommandBuilder. Source Edit
func commandBuilder[T](cli: Cli[T]): CommandBuilder[T]
- Creates a new CommandBuilder. Source Edit
func commandUsage(cli: Cli; command: CommandId; rootName: string = cli.nameOf(RootCommand)): string
-
Produces a usage message for the given command. The message is meant to convey the general shape of the command line.
The name of the root command can be set for this message using rootName.
Refer to the code sample for example outputs.
Example:
func noop(v: auto, a: var auto): Action = discard ## A parser that does nothing var cli = commandBuilder(string) .name("cmd") .initCli() let joinCmd = cli.commandBuilder() .name("join") .addTo(cli, RootCommand) cli.positionalBuilder() .name("FIRST") .describe("first value") .parser(noop) .addTo(cli, joinCmd) cli.positionalBuilder() .name("SEPARATOR") .describe("value separator") .optional() .parser(noop) .addTo(cli, joinCmd) cli.positionalBuilder() .name("VALUE") .describe("extra values to join") .optional() .catchAll() .parser(noop) .addTo(cli, joinCmd) doAssert cli.commandUsage(RootCommand) == "cmd [OPTIONS] <COMMAND>" doAssert cli.commandUsage(joinCmd) == "cmd join [OPTIONS] <FIRST> [SEPARATOR] [VALUE]..." doAssert cli.commandUsage(joinCmd, "cmdbox.exe") == "cmdbox.exe join [OPTIONS] <FIRST> [SEPARATOR] [VALUE]..."
Source Edit func commandWithName(cli: Cli; command: CommandId; name: string): Option[ CommandId]
-
Returns the CommandId handle for the subcommand identifiable by name registered for command.
Example:
import std/options var cli = commandBuilder(string) .initCli() let actCmd = cli.commandBuilder() .name("act") .alias("a", "do") .addTo(cli, RootCommand) doAssert cli.commandWithName(RootCommand, "a") == some(actCmd) doAssert cli.commandWithName(RootCommand, "act") == some(actCmd) doAssert cli.commandWithName(RootCommand, "not-found") == none(CommandId)
Source Edit func default[T](b: sink CommandBuilder[T]): CommandBuilder[T]
-
Marks this command as the default subcommand of its parent. When no subcommand is present on the command line, this command will be selected.
Only one default subcommand is permitted per command. Attempting to add another default subcommand to a command will cause an error.
This attribute is ignored for the root command.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() cli.commandBuilder() .name("act") .default() .parser((_, var s) => (s = "acted")) .addTo(cli, RootCommand) doAssert cli.parse(@[]) == "acted"
Source Edit func defaultCommandOf(cli: Cli; command: CommandId): Option[CommandId]
-
Returns the default subcommand of command.
Example:
import std/options var cli = commandBuilder(string) .initCli() let actCmd = cli.commandBuilder() .name("act") .addTo(cli, RootCommand) let defCmd = cli.commandBuilder() .name("def") .default() .addTo(cli, actCmd) doAssert cli.defaultCommandOf(RootCommand) == none(CommandId) doAssert cli.defaultCommandOf(actCmd) == some(defCmd)
Source Edit func describe[T](b: sink CommandBuilder[T]; usage: sink string): CommandBuilder[ T]
-
Sets a short usage description for this command.Note: usage should only be one-line long. This is not enforced, but the built-in documentation renderer assumes this and might not produce satisfactory results with multi-line usage.Source Edit
func describe[T](b: sink FlagBuilder[T]; usage: sink string; placeholder: sink string = ""): FlagBuilder[T]
-
Sets a short usage description and a value placeholder for this flag.
For required flags, an empty placeholder defaults to VALUE. For optional flags, an empty placeholder will be omitted from documentation rendering.
Note: usage should only be one-line long. This is not enforced, but the built-in documentation renderer assumes this and might not produce satisfactory results with multi-line usage.Source Edit func describe[T](b: sink PositionalBuilder[T]; usage: sink string): PositionalBuilder[ T]
-
Sets a short usage description for this positional.Note: usage should only be one-line long. This is not enforced, but the built-in documentation renderer assumes this and might not produce satisfactory results with multi-line usage.Source Edit
func flagBuilder[T](cli: Cli[T]): FlagBuilder[T]
- Creates a new FlagBuilder. Source Edit
func flagsUsage(cli: Cli; command: CommandId): string
-
Produces a usage message for all flags registered for command.
For each flag, the rendered message contains the first short and long name, a placeholder and the described usage.
The output is separated into two columns: how to specify the flag on the command line and its associated usage.
Refer to the code sample for an example output.
Example:
func noop(k, v: auto, a: var auto): Action = discard ## A parser that does nothing var cli = commandBuilder(string) .initCli() cli.flagBuilder() .name("x") .alias("exclude") .describe("exclude strings") .parser(noop) .addTo(cli, RootCommand) cli.flagBuilder() .name("s") .describe("silence output") .optionalParser(noop) .addTo(cli, RootCommand) cli.flagBuilder() .name("color") .describe("whether to show color", "MODE") .optionalParser(noop) .addTo(cli, RootCommand) doAssert cli.flagsUsage(RootCommand) == """ -x, --exclude <VALUE> exclude strings -s silence output --color[=<MODE>] whether to show color"""
Source Edit func flagWithName(cli: Cli; command: CommandId; name: string): Option[FlagId]
-
Returns the FlagId handle for the flag identifiable by name registered for command.
Example:
import std/options import std/sugar var cli = commandBuilder(string) .initCli() let strFlag = cli.flagBuilder() .name("string") .alias("str", "s") .parser(string, (_, val, var str) => (str = val)) .addTo(cli) doAssert cli.flagWithName(RootCommand, "string") == some(strFlag) doAssert cli.flagWithName(RootCommand, "str") == some(strFlag) doAssert cli.flagWithName(RootCommand, "not-found") == none(FlagId)
Source Edit func hasDefaultSubcommand(cli: Cli; command: CommandId): bool
-
Returns whether command has a default subcommand.
Example:
var cli = commandBuilder(string) .initCli() let actCmd = cli.commandBuilder() .name("act") .addTo(cli, RootCommand) cli.commandBuilder() .name("def") .default() .addTo(cli, actCmd) doAssert not cli.hasDefaultSubcommand(RootCommand) doAssert cli.hasDefaultSubcommand(actCmd)
Source Edit func hasSubcommand(cli: Cli; command: CommandId): bool
-
Returns whether command contains subcommands.
Example:
var cli = commandBuilder(string) .initCli() let actCmd = cli.commandBuilder() .name("act") .addTo(cli, RootCommand) doAssert cli.hasSubcommand(RootCommand) doAssert not cli.hasSubcommand(actCmd)
Source Edit func help(cli: Cli; command: CommandId; rootName: string = cli.nameOf(RootCommand)): string
-
Produces the help message for a command.
See the code example for sample outputs.
Example:
func noop(v: auto, a: var auto): Action = discard ## A parser that does nothing var cli = commandBuilder(string) .name("cmd") .initCli() cli.addHelpFlag(RootCommand, "help", "h") let joinCmd = cli.commandBuilder() .name("join") .describe("join value(s)") .addTo(cli, RootCommand) cli.addHelpFlag(joinCmd, "help", "h") cli.positionalBuilder() .name("FIRST") .describe("first value") .parser(noop) .addTo(cli, joinCmd) cli.positionalBuilder() .name("SEPARATOR") .describe("value separator") .optional() .parser(noop) .addTo(cli, joinCmd) cli.positionalBuilder() .name("VALUE") .describe("extra values to join") .optional() .catchAll() .parser(noop) .addTo(cli, joinCmd) cli.commandBuilder() .name("cat") .describe("concatenate file(s)") .addTo(cli, RootCommand) cli.commandBuilder() .name("install") .describe("install file(s) to a given destination") .addTo(cli, RootCommand) doAssert cli.help(RootCommand) == """ Usage: cmd [OPTIONS] <COMMAND> Commands: join join value(s) cat concatenate file(s) install install file(s) to a given destination Options: -h, --help display help message""" doAssert cli.help(joinCmd) == """ join value(s) Usage: cmd join [OPTIONS] <FIRST> [SEPARATOR] [VALUE]... Arguments: <FIRST> first value [SEPARATOR] value separator [VALUE]... extra values to join Options: -h, --help display help message"""
Source Edit proc helpFlagBuilder[T](cli: Cli[T]; name: sink string = "help"): FlagBuilder[T]
-
Builds a simple flag that triggers Action.ShowHelp when specified on the command line.
The flag can be added directly to a cli or further customized.
See also:
Source Edit func initCli[T: not void](b: sink CommandBuilder[T]): Cli[T]
-
Creates a new Cli, with b used to construct the root command.
The root command must:
- Have no parser set.
- Have no aliases.
Unlike subcommands, the root command may:
- Have an empty (or unset) name, since the name is not used during parsing. A name, if specified, will be used in documentation generation.
The root command can be referred to using the RootCommand constant.
See also:
Source Edit func isCatchAll(cli: Cli; positional: PositionalId): bool
-
Returns whether positional is a catch all parameter.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() let reqPos = cli.positionalBuilder() .name("REQ") .parser((v, var s) => (s = v)) .addTo(cli) let anyPos = cli.positionalBuilder() .name("ANY") .catchAll() .parser((v, var s) => Action.Continue) .addTo(cli) doAssert not cli.isCatchAll(reqPos) doAssert cli.isCatchAll(anyPos)
Source Edit func isDefault(cli: Cli; command: CommandId): bool
-
Returns whether command is the default subcommand of its parent.Note: This is always false for RootCommand.
Example:
var cli = commandBuilder(string) .initCli() let actCmd = cli.commandBuilder() .name("act") .addTo(cli, RootCommand) let defCmd = cli.commandBuilder() .name("def") .default() .addTo(cli, actCmd) doAssert not cli.isDefault(actCmd) doAssert cli.isDefault(defCmd)
Source Edit func isOptional(cli: Cli; positional: PositionalId): bool
-
Returns whether a value for positional is optional on the command line.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() let reqPos = cli.positionalBuilder() .name("REQ") .parser((v, var s) => (s = v)) .addTo(cli) let optPos = cli.positionalBuilder() .name("OPT") .optional() .parser((v, var s) => (s = v)) .addTo(cli) doAssert not cli.isOptional(reqPos) doAssert cli.isOptional(optPos)
Source Edit func isValueOptional(cli: Cli; flag: FlagId): bool
-
Returns whether a value for flag is optional on the command line.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() let strFlag = cli.flagBuilder() .name("str") .optionalParser((_, v, var s) => Action.Continue) .addTo(cli) let strReqFlag = cli.flagBuilder() .name("str-req") .parser((_, v, var s) => Action.Continue) .addTo(cli) let switchFlag = cli.flagBuilder() .name("switch") .parser(bool, (_, v, var s) => Action.Continue) .addTo(cli) doAssert cli.isValueOptional(strFlag) doAssert not cli.isValueOptional(strReqFlag) doAssert cli.isValueOptional(switchFlag)
Source Edit func longNameOf(cli: Cli; flag: FlagId): Option[string]
-
Returns the first long name of flag, if one exists.
A long name is defined as a name longer than one character.
Example:
import std/options import std/sugar var cli = commandBuilder(string) .initCli() let strFlag = cli.flagBuilder() .name("s") .alias("str", "string") .parser(string, (_, val, var str) => (str = val)) .addTo(cli) doAssert cli.longNameOf(strFlag) == some("str")
Source Edit func name[T](b: sink CommandBuilder[T]; name: string): CommandBuilder[T]
-
Sets the canonical name of this command, which is used to identify this command on the command line.Note: A name is optional for the root command.
See also:
Example:
import std/sugar var cli = commandBuilder(string) .initCli() cli.commandBuilder() .name("act") .parser((_, var s) => (s = "acted")) .addTo(cli, RootCommand) doAssert cli.parse(@["act"]) == "acted"
Source Edit func name[T](b: sink FlagBuilder[T]; name: string): FlagBuilder[T]
-
Sets the canonical name of this flag, which is used to identify this flag on the command line.
If name is only one ASCII character long, it may use the short form syntax (e.g. -n).
See also:
Example:
import std/sugar type Args = object str: string i: int var cli = commandBuilder(Args) .initCli() cli.flagBuilder() .name("string") .parser(string, (_, val, var args) => (args.str = val)) .addTo(cli) cli.flagBuilder() .name("i") .parser(int, (_, val, var args) => (args.i = val)) .addTo(cli) doAssert cli.parse(@["--string=str"]) == Args(str: "str") doAssert cli.parse(@["-i=10"]) == Args(i: 10)
Source Edit func name[T](b: sink PositionalBuilder[T]; name: string): PositionalBuilder[T]
- Sets the canonical name of this positional, which is used when providing diagnostics and help message. Source Edit
func nameOf(cli: Cli; command: CommandId): lent string
-
Returns the canonical name for command.
Example:
var cli = commandBuilder(string) .initCli() let actCmd = cli.commandBuilder() .name("act") .addTo(cli, RootCommand) doAssert cli.nameOf(actCmd) == "act"
Source Edit func nameOf(cli: Cli; flag: FlagId): lent string
-
Returns the canonical name for flag.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() let strFlag = cli.flagBuilder() .name("string") .parser(string, (_, val, var str) => (str = val)) .addTo(cli) doAssert cli.nameOf(strFlag) == "string"
Source Edit func nameOf(cli: Cli; positional: PositionalId): lent string
-
Returns the canonical name for positional.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() let strPos = cli.positionalBuilder() .name("STR") .parser((v, var s) => (s = v)) .addTo(cli) doAssert cli.nameOf(strPos) == "STR"
Source Edit func optional[T](b: sink PositionalBuilder[T]): PositionalBuilder[T]
-
Marks this positional as optional. When not specified on the command line, the associated parser will not be called.
No non-optional positional parameters might be added to a command after the first optional.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() cli.positionalBuilder() .name("STR") .optional() .parser((v, var s) => (s = v)) .addTo(cli) doAssert cli.parse(@[]) == "" doAssert cli.parse(@["a"]) == "a"
Source Edit func optionalParser[T, U; R: MaybeAction](b: sink FlagBuilder[T]; _: typedesc[U]; parser: sink FlagOptionalTypedParser[T, U, R]): FlagBuilder[ T]
-
Sets the parser for this flag, and marks the flag as not requiring any value.
Input string values from the command line will first be parsed using parseCli before handing off to the parser. See parsers module for more information.
Flags with optional value will only receive their value when it is specified inline, for example: --flag=value or --flag:value.
See also:
Example:
import std/options import std/sugar var cli = commandBuilder(int) .initCli() cli.flagBuilder() .name("int") .optionalParser(int, (_, val, var i) => (i = val.get(42))) .addTo(cli) doAssert cli.parse(@["--int"]) == 42 doAssert cli.parse(@["--int", "--int"]) == 42 doAssertRaises(InvalidValueError): discard cli.parse(@["--int=--int"]) doAssert cli.parse(@["--int=1000"]) == 1000
Source Edit func optionalParser[T](b: sink FlagBuilder[T]; p: sink FlagOptionalParser[T, Action]): FlagBuilder[T]
-
Sets the parser for this flag, and marks the flag as not requiring any value.
For flags with an optional value, their parser will only be called when the value is specified inline, for example: --flag=value or --flag:value.
See also:
Example:
import std/options proc parser(opt: string, val: Option[string], str: var string): Action = if val == some("help"): Action.ShowHelp else: str = val.get(otherwise = "default") Action.Continue var cli = commandBuilder(string) .initCli() cli.flagBuilder() .name("string") .optionalParser(parser) .addTo(cli) doAssert cli.parse(@["--string"]) == "default" doAssert cli.parse(@["--string", "--string"]) == "default" doAssert cli.parse(@["--string=--string"]) == "--string" doAssertRaises(HelpError): discard cli.parse(@["--string:help"])
Source Edit func optionalParser[T](b: sink FlagBuilder[T]; p: sink FlagOptionalParser[T, void]): FlagBuilder[T]
-
Sets the parser for this flag with Action.Continue as the default action, and marks the flag as not requiring any value.
Flags with optional value will only receive their value when it is specified inline, for example: --flag=value or --flag:value.
See also:
Example:
import std/options import std/sugar var cli = commandBuilder(string) .initCli() cli.flagBuilder() .name("string") .optionalParser((_, val, var str) => (str = val.get("default"))) .addTo(cli) doAssert cli.parse(@["--string"]) == "default" doAssert cli.parse(@["--string", "--string"]) == "default" doAssert cli.parse(@["--string=--string"]) == "--string" doAssert cli.parse(@["--string:help"]) == "help"
Source Edit func parentOf(cli: Cli; command: CommandId): Option[CommandId]
-
Returns the parent command of command.
none(CommandId) is only returned for RootCommand.
Example:
import std/options var cli = commandBuilder(string) .initCli() let actCmd = cli.commandBuilder() .name("act") .addTo(cli, RootCommand) doAssert cli.parentOf(actCmd) == some(RootCommand) doAssert cli.parentOf(RootCommand) == none(CommandId)
Source Edit func parse[T](cli: Cli[T]; accumulator: var T; args: sink seq[string]) {. ...raises: [ParseError].}
-
Parses the given args list based on the description in cli, with configured parsers updating values in the accumulator.
See also:
Source Edit func parse[T](cli: Cli[T]; args: sink seq[string]; defaults: sink T = default(T)): T {. inline, ...raises: [ParseError].}
-
Parses the given args list based on the description in cli, returning accumulated changes from configured parsers.
An initial value for the internal accumulator can be specified using defaults.
See also:
Source Edit proc parser[T, U; R: MaybeAction](b: sink FlagBuilder[T]; _: typedesc[U]; parser: sink FlagTypedParser[T, U, R]): FlagBuilder[ T]
-
Sets the parser for this flag, and marks the flag as requiring values.
Input string values from the command line will first be parsed using parseCli before handing off to the parser. See parsers module for more information.
When U is bool, this flag behaves like a switch and does not require a value to be passed. If values are to be passed, it must be inlined (i.e. --flag=false).
Flags with a required value can receive any of the following forms:
- --flag=value
- --flag:value
- --flag value (only when U is not bool)
See also:
Example:
import std/options import std/sugar type Args = object i: int b: bool var cli = commandBuilder(Args) .initCli() cli.flagBuilder() .name("int") .parser(int, (_, val, var args) => (args.i = val)) .addTo(cli) cli.flagBuilder() .name("switch") .parser(bool, (_, val, var args) => (args.b = val)) .addTo(cli) doAssertRaises(MissingValueError): discard cli.parse(@["--int"]) doAssertRaises(InvalidValueError): discard cli.parse(@["--int", "string"]) doAssert cli.parse(@["--int", "1000"]) == Args(i: 1000) doAssert cli.parse(@["--switch"]) == Args(b: true) doAssert cli.parse(@["--switch", "--switch:false"]) == Args(b: false)
Source Edit proc parser[T, U; R: MaybeAction](b: sink PositionalBuilder[T]; _: typedesc[U]; parser: sink TypedPositionalParser[T, U, R]): PositionalBuilder[ T]
-
Sets the parser for this positional parameter.
Input string values from the command line will first be parsed using parseCli before handing off to the parser. See parsers module for more information.
Example:
import std/sugar type Args = object a, b: int var cli = commandBuilder(Args) .initCli() cli.positionalBuilder() .name("A") .parser(int, (v, var args) => (args.a = v; Action.DisableFlagProcessing)) .addTo(cli) cli.positionalBuilder() .name("B") .parser(int, (v, var args) => (args.b = v)) .addTo(cli) doAssert cli.parse(@["10", "-10"]) == Args(a: 10, b: -10)
Source Edit func parser[T](b: sink CommandBuilder[T]; p: sink CommandParser[T, Action]): CommandBuilder[ T]
-
Sets the parser for this command. This is called when the command is matched on the command line.Note: A parser is optional for commands.Warning: It is an error to set a parser for the root command.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() cli.commandBuilder() .name("help") .parser((_, var s) => Action.ShowHelp) .addTo(cli, RootCommand) doAssertRaises(HelpError): discard cli.parse(@["help"])
Source Edit func parser[T](b: sink CommandBuilder[T]; p: sink CommandParser[T, void]): CommandBuilder[ T] {.inline.}
-
Sets the parser for this command with Action.Continue as the default action.Note: A parser is optional for commands.Warning: It is an error to set a parser for the root command.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() cli.commandBuilder() .name("act") .parser((_, var s) => (s = "acted")) .addTo(cli, RootCommand) doAssert cli.parse(@["act"]) == "acted"
Source Edit func parser[T](b: sink FlagBuilder[T]; p: sink FlagParser[T, Action]): FlagBuilder[ T]
-
Sets the parser for this flag, and marks the flag as requiring values.
Flags with a required value can receive any of the following forms:
- --flag=value
- --flag:value
- --flag value
See also:
Example:
proc parser(opt: string, val: string, str: var string): Action = if val == "help": Action.ShowHelp else: str = val Action.Continue var cli = commandBuilder(string) .initCli() cli.flagBuilder() .name("string") .parser(parser) .addTo(cli) doAssertRaises(MissingValueError): discard cli.parse(@["--string"]) doAssert cli.parse(@["--string", "--string"]) == "--string" doAssert cli.parse(@["--string=--string"]) == "--string" doAssertRaises(HelpError): discard cli.parse(@["--string", "help"])
Source Edit func parser[T](b: sink FlagBuilder[T]; p: sink FlagParser[T, void]): FlagBuilder[ T]
-
Sets the parser for this flag with Action.Continue as the default action, and marks the flag as requiring values.
Flags with a required value can receive any of the following forms:
- --flag=value
- --flag:value
- --flag value
See also:
Example:
import std/sugar var cli = commandBuilder(string) .initCli() cli.flagBuilder() .name("string") .parser((_, val, var str) => (str = val)) .addTo(cli) doAssertRaises(MissingValueError): discard cli.parse(@["--string"]) doAssert cli.parse(@["--string", "--string"]) == "--string" doAssert cli.parse(@["--string=--string"]) == "--string" doAssert cli.parse(@["--string", "help"]) == "help"
Source Edit func parser[T](b: sink PositionalBuilder[T]; p: sink PositionalParser[T, Action]): PositionalBuilder[ T]
-
Set the parser for this positional parameter.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() cli.positionalBuilder() .name("NO-FLAGS") .parser((_, var s) => Action.DisableFlagProcessing) .addTo(cli) cli.positionalBuilder() .name("STR") .parser((v, var s) => (s = v; Action.Continue)) .addTo(cli) doAssert cli.parse(@["a", "-b"]) == "-b"
Source Edit func parser[T](b: sink PositionalBuilder[T]; p: sink PositionalParser[T, void]): PositionalBuilder[ T]
-
Sets the parser for this positional parameter. On successful parse, Action.Continue is taken as the default action.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() cli.positionalBuilder() .name("STR") .parser((v, var s) => (s = v)) .addTo(cli) doAssert cli.parse(@["a"]) == "a"
Source Edit func pathOf(cli: Cli; command: CommandId): seq[CommandId]
-
Returns the path leading to command.
Example:
var cli = commandBuilder(string) .initCli() let actCmd = cli.commandBuilder() .name("act") .addTo(cli, RootCommand) doAssert cli.pathOf(actCmd) == [RootCommand, actCmd] doAssert cli.pathOf(RootCommand) == [RootCommand]
Source Edit func placeholderOf(cli: Cli; flag: FlagId): string
-
Returns the placeholder for flag, as described with describe.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() let strFlag = cli.flagBuilder() .name("string") .describe("a string", "STR") .parser((_, v, var s) => (s = v)) .addTo(cli) let str2Flag = cli.flagBuilder() .name("string2") .describe("a string") .parser((_, v, var s) => (s = v)) .addTo(cli) doAssert cli.placeholderOf(strFlag) == "STR" doAssert cli.placeholderOf(str2Flag) == ""
Source Edit func positionalBuilder[T](cli: Cli[T]): PositionalBuilder[T]
- Creates a new PositionalBuilder. Source Edit
func positionalsUsage(cli: Cli; command: CommandId): string
-
Produces a usage message for all positionals registered for command.
For each positional, the rendered message contains the name and the usage as described by describe. The name is wrapped in either <> or [] to signify its requirement with ... suffix added for catch all parameters.
The output is separated into two columns: the positional display form and its associated usage.
Refer to the code sample for an example output.
Example:
func noop(v: auto, a: var auto): Action = discard ## A parser that does nothing var cli = commandBuilder(string) .initCli() cli.positionalBuilder() .name("FIRST") .describe("first value") .parser(noop) .addTo(cli, RootCommand) cli.positionalBuilder() .name("SEPARATOR") .describe("value separator") .optional() .parser(noop) .addTo(cli, RootCommand) cli.positionalBuilder() .name("VALUE") .describe("extra values to join") .optional() .catchAll() .parser(noop) .addTo(cli, RootCommand) doAssert cli.positionalsUsage(RootCommand) == """ <FIRST> first value [SEPARATOR] value separator [VALUE]... extra values to join"""
Source Edit func prettifyError[T](cli: Cli[T]; error: ref ParseError): string
- Produces a pretty error message for error. The provided error must have been raised by parse(cli). Source Edit
proc run[T](cli: Cli[T]; accumulator: var T; args: sink seq[string] = commandLineParams(); messageOutput: File = stdmsg)
-
Parses the command line args based on the description in cli, with configured parsers updating values in the accumulator.
If an error occurs during parsing, the error message will be printed to messageOutput alongside helpful information and the command will terminate with a failure exit code automatically. The only exception to this is when HelpError occurs, of which the command will terminate with a successful exit code.
See also:
Source Edit proc run[T](cli: Cli[T]; args: sink seq[string] = commandLineParams(); messageOutput: File = stdmsg; defaults: sink T = default(T)): T
-
Parses the command line args based on the description in cli, returning accumulated changes from configured parsers.
An initial value for the internal accumulator can be specified using defaults.
See run proc for more information.
See also:
Source Edit func shortNameOf(cli: Cli; flag: FlagId): Option[string]
-
Returns the first short name of flag, if one exists.
A short name is defined as a one-character long name.
Example:
import std/options import std/sugar var cli = commandBuilder(string) .initCli() let strFlag = cli.flagBuilder() .name("string") .alias("str", "s") .parser(string, (_, val, var str) => (str = val)) .addTo(cli) doAssert cli.shortNameOf(strFlag) == some("s")
Source Edit func subcommandsUsage(cli: Cli; command: CommandId): string
-
Produces a usage message for all subcommands registered for command.
The output is separated into two columns: the subcommand canonical name and its associated usage. A [default] suffix is added to the usage message for default subcommand.
Refer to the code sample for an example output.
Example:
func noop(v: auto, a: var auto): Action = discard ## A parser that does nothing var cli = commandBuilder(string) .name("cmd") .initCli() cli.commandBuilder() .name("join") .describe("join value(s)") .addTo(cli, RootCommand) cli.commandBuilder() .name("cat") .describe("concatenate file(s)") .addTo(cli, RootCommand) cli.commandBuilder() .name("install") .describe("install file(s) to a given destination") .addTo(cli, RootCommand) doAssert cli.subcommandsUsage(RootCommand) == """ join join value(s) cat concatenate file(s) install install file(s) to a given destination"""
Source Edit func usageOf(cli: Cli; command: CommandId): lent string
-
Returns the usage for command, as described with describe.
Example:
import std/sugar let cli = commandBuilder(string) .describe("some usage") .initCli() doAssert cli.usageOf(RootCommand) == "some usage"
Source Edit func usageOf(cli: Cli; flag: FlagId): lent string
-
Returns the usage for flag, as described with describe.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() let strFlag = cli.flagBuilder() .name("string") .describe("a string") .parser((_, v, var s) => (s = v)) .addTo(cli) doAssert cli.usageOf(strFlag) == "a string"
Source Edit func usageOf(cli: Cli; positional: PositionalId): lent string
-
Returns the usage for positional, as described with describe.
Example:
import std/sugar var cli = commandBuilder(string) .initCli() let strPos = cli.positionalBuilder() .name("STR") .describe("a string") .parser((v, var s) => (s = v)) .addTo(cli) doAssert cli.usageOf(strPos) == "a string"
Source Edit
Iterators
iterator namesOf(cli: Cli; command: CommandId): lent string
-
Returns all names that can be used to refer to command. The canonical name is always returned first.
Example:
import std/sequtils var cli = commandBuilder(string) .initCli() let actCmd = cli.commandBuilder() .name("act") .alias("a", "do") .addTo(cli, RootCommand) doAssert toSeq(cli.namesOf(actCmd)) == ["act", "a", "do"]
Source Edit iterator namesOf(cli: Cli; flag: FlagId): lent string
-
Returns all names that can be used to refer to flag. The canonical name is always returned first.
Example:
import std/sequtils import std/sugar var cli = commandBuilder(string) .initCli() let strFlag = cli.flagBuilder() .name("string") .alias("str", "s") .parser(string, (_, val, var str) => (str = val)) .addTo(cli) doAssert toSeq(cli.namesOf(strFlag)) == ["string", "str", "s"]
Source Edit iterator positionals(cli: Cli; command: CommandId): PositionalId
- Returns all positional parameters for command. Source Edit