The command-line-parser Library#
The command-line-parser library provides a facility to parse the command line. It exports two modules:
command-line-parser - Main API module
option-parser-protocol - For extending the API
Here’s a quick list of features to get a sense of what’s available:
Various option types
<repeated-parameter-option>options may be repeated:
-r a -r b
<optional-parameter-option>in which the value is optional:
<keyed-option>fills a table with key/value pairs, for example:
<choice-option>the value may be chosen from a predefined set.
<positional-option>to receive positional arguments.
Automatic and extensible conversion of arguments to other types. For example, an option with
type: <integer>is automatically converted to integer by the parser.
Automatic usage and
A convenient and readable syntax for creating the command line.
Extensibility. Add your own argument converters with
parse-option-valueor create entirely new option types.
The best way to build a command line parser is with
command-line-definer, since it is far more concise and readable than
building one “by hand” with
make(<command-line-parser>, options: ...). It
also provides convenient methods to retrieve command-line option values rather
than accessing them by name, with strings.
command-line-definer does not currently support subcommands.
If you need subcommands you will have to build the parser by hand for
Let’s say you want to parse a command line that looks like this:
frob --name=zoo --debug -r a -r b -r c --choice=foo one two three
The “frob” command accepts a
--name option that takes a value, a boolean
--nodebug) a repeatable
-r option, a
option that accepts one of several values, and then at least one positional
argument (here “one”, “two”, and “three”). Here’s what that parser looks like:
define command-line <frob-command-line> () option frob-name :: <string>, names: #("name"), help: "Name of the frob", kind: <parameter-option>; option frob-debug? :: <boolean>, names: #("debug"), negative-names: #("nodebug"), help: "Enable or disable debugging", kind: <flag-option>; // This is the default. option frob-radicals :: <sequence>, names: #("r"), kind: <repeated-parameter-option>, variable: "RAD", // Makes --help show "-r RAD" help: "Free radicals"; option frob-choice :: <string>, names: #("choice"), choices: #("foo", "bar", "baz"), default: "foo", help: "Your choice"; option frob-filenames :: <sequence>, names: #("filenames"), kind: <positional-option>, repeated?: #t, help: "One or more filenames"; end command-line;
Now parse the command line:
block () let cmd = make(<frob-command-line>, help: "frob things"); parse-command-line(cmd, application-arguments()); // Now execute your main program code with cmd containing // the parsed argument values. frob(cmd); exception (err :: <abort-command-error>) // This condition is signaled by parse-command-line and also if // your own code calls abort-command(). format-err("%s", err); exit-application(err.exit-status); end;
To access the option values simply read the
cmd is the command parsed above:
for (file in cmd.frob-filenames) if (cmd.frob-debug?) format-out(...); end; ...more... end;
Of course, it is also possible to make a command line parser without the macro
above, but doing so is much more verbose and requires accessing the option
values by calling
get-option-value(cmd, "option-name"). Briefly, just call
make, like this:
let cmd = make(<command-line-parser>, help: "a most excellent program", options: list(make(<flag-option>, names: #("name"), help: "provide a name"), ..., make(<positional-option>, names: #("filenames"), repeated?: #t, help: "one or more filenames")), subcommands: list(make(<my-subcommand>, ...))); parse-command-line(cmd, application-arguments()); let filenames = get-option-value(cmd, "filenames"); ...etc...
- <command> Abstract Sealed Class#
options – A sequence of
<option>instances. Note that
<positional-option>instances must follow all other options, and there may be only a single
repeated?: #tand it must be the last option in the sequence.
help – Required. A
<string>to display when help is requested via the
--helpoption or the
- <subcommand> Open Abstract Class#
A named subcommand. Subcommands have their own set of command-line options. They may not contain other subcommands.
- <command-line-parser> Open Class#
Encapsulates a set of command-line options. May optionally contain a set of subcommands, each of which has its own set of options.
help-option? – A boolean specifying whether the parser should automatically add the default help option. By default, help can be requested via
-h. If false, no help option will be added to the parser, and you must explicitly handle any request for help yourself. The default is true. See
help-subcommand? – A boolean specifying whether the parser should automatically add the default help subcommand. The default is true if the command-line has any subcommands. Set to false if you prefer to call the subcommand something else (e.g., non-English). See
subcommands – A sequence of
- <help-subcommand> Class#
helpsubcommand. Normally there is no need to use this since the command line parser implements the
helpsubcommand itself. However, if you wanted to implement the
helpsubcommand differently, or just give it a different (or an additional) name, this is how to do it:
define class <my-help-subcommand> (<help-subcommand>) end; let p = make(<command-line-parser>, help-subcommand?: #f, ... subcommands: list(make(<my-help-subcommand>, names: #("ayuda")) ...)); define method execute-subcommand (parser, sub :: <my-help-subcommand>) => (s :: false-or(<integer>)) ...etc... end
- <command-line-parser-error> Open Class#
Superclass of all errors signaled by this library.
- <abort-command-error> Sealed Class#
Provides a standard way for program code to indicate that the application should exit. Signaled by the command line parser itself after the standard
helpsubcommand have completed, so programs should always handle this at top level.
- exit-status Function#
Returns the exit status associated with an error.
- <usage-error> Open Class#
Signaled when a command-line cannot be parsed.
- add-option Function#
Add an option to a command-line parser.
- parse-command-line Function#
Parses the command line in
parse-command-line (parser argv) => ()
argvisn’t a valid set of options as described by the
See Quick Start for an example.
- execute-command Generic function#
When using subcommands, call this to execute the parsed command line.
execute-command (parser) => (false-or(<integer>))
parser – An instance of
Call this after calling
parse-command-line, if your command-line has subcommands. (If not using subcommands there is no need to call this; just read option values from parser directly.) It determines the subcommand indicated by the user and invokes
execute-subcommandon it. The
helpsubcommand is handled specially.
- execute-subcommand Generic function#
Implement a method on this generic for each subclass of
execute-subcommand (parser subcommand) => (false-or(<integer>))
This is the implementation of your subcommand. Read command-line options from
subcommandand read global options (if any) from
- print-synopsis Open Generic function#
Display a synopsis of the command line options.
print-synopsis (parser subcommand #key stream) => ()
It is not normally necessary to call this function since the
helpsubcommand are handled automatically by the parser.
- option-present? Function#
#tif this option was supplied on the command line.
option-present? (option) => (present?)
option – An instance of
present? – An instance of
#tif this option was supplied on the command line. Returns
#fif called before
parse-command-linehas been called on the associated parser, or if the option wasn’t supplied on the command line.
- option-value Function#
Returns the parsed value of the option supplied on the command line.
option-value (option) => (value)
option – An instance of
value – An instance of
Returns the parsed value of the option supplied on the command line. If no value was supplied on the command line it returns the value specified with
default:when the option was created, which in turn defaults to
Note that the type of the return value is specified by the
type:keyword argument when the option was created and the string supplied on the command line is converted to that type by a method on
- get-option-value Function#
Retrieves an option from a
- parse-option-value Open Generic function#
parse-option-value (argument, type) => (value)
value – An instance of
Convert a command-line argument (a string) to the type specified in the corresponding
<option>instance. For example, given the following code, the “version” option’s
option-valueslot would be set to an instance of
<version>by the command line parser so that you don’t have to manually do it in your application.
make(<parameter-option>, names: #("version"), help: "A version specifier. Ex: v1.2.3", type: <version>) define method parse-option-value (arg :: <string>, type == <version>) => (v :: <version>) parse-version(arg) end;
There are predefined methods that convert to
<boolean>, valid values are yes/no, on/off, true/false. For
<sequence>, strings are simply split around commas, without any attempt to be smart about quoting.
- <option> Open Abstract Class#
Superclass of all other option types.
Names for this option; a sequence of strings. For convenience a single string may be given if the option only has one name. Strings of length 1 are considered to be short options, i.e., they are prefixed by a single dash on the command line.
The first name in the list is considered the “canonical” name of the option and is used in various parts of the auto-generated
The kind of value represented by this option. That is, the string passed on the command line will be coerced to this type via
parse-option-valueif a relevant method exists. Clients may implement methods on that function for their own types to extend the parser.
Predefined types include
A string documenting the option. Displayed in
--helpoutput. Some automatic substitutions are performed:
”%default%” => The string representation of the default value for the option.
”%app%” => The basename of the executable program.
For example, given this option specification:
make(<parameter-option>, names: #("v", "version"), help: "Package version [%default%]", default: "latest")
it will be displayed as:
--version V Package version [latest]
A string to stand in for the option value in
--helpoutput. For example, if the option name is
--databasethis might be “URL”, which would display as:
--database URL A database URL.
When not specified, the first name of the option is used. For example:
make(<parameter-option>, names: #("n", "name"), help: "A name")
And on the command-line this will be displayed as:
-n, --name N A name
default – A default value for the option that will be used if the option isn’t specified by the user. The default value should be a member of the type specified with the
#fis the default default value.
- <flag-option> Sealed Class#
Defines a simple flag option, i.e., one that specifies a boolean value.
negative-names – Same as
names, but specifies the negative forms.
They default to
#fand may exist in both positive and negative forms:
--no-foo. In the case of conflicting options, the rightmost takes precedence to allow for abuse of the shell’s “alias” command.
For example, a single instance of this class could be used to specify all of the following command-line options:
-q, -v, --quiet, --verbose
- <parameter-option> Sealed Class#
Defines an option that requires a value be specified.
If the option appears more than once, the rightmost value takes precedence. If the option never appears, these will default to
-cred, -c=red, -c = red, --color red, --color=red
- <optional-parameter-option> Sealed Class#
<parameter-option>, but the parameter is optional.
The parameter must directly follow the option with no intervening whitespace, or follow an “=” token. The value is
#fif the option never appears,
#tif the option appears but the parameter does not, and the value of the parameter otherwise.
-z, -z3, -z=3, -z = 3, --zip, --zip=3, --zip = 3
-z 3, --zip 3, --zip3
- <repeated-parameter-option> Sealed Class#
<parameter-option>, but may appear more than once.
The final value is a deque of parameter values in the order they appeared on the command line. It defaults to the empty deque.
-wall, -w=all, -w = all, --warnings all, --warnings=all
- <choice-option> Sealed Class#
<parameter-option>, but provides a restricted set of values to choose from.
choices – A sequence of objects (usually strings). If the value supplied on the command line isn’t one of these objects then
<usage-error>is signaled. If you supply a sequence of non-string choices you will also need to supply the
test:init keyword since all command-line arguments are strings and won’t compare equal with the default test,
test – A function to test whether the value supplied on the command line is the same as one of the choices. The default is
=. Another commonly used value is
string-equal-ic?, to ignore case in the comparison.
make(<choice-option>, names: #("foo"), help: "a or b", choices: #("a", "b"), test: string-equal-ic?)
- <keyed-option> Sealed Class#
Each occurrence of this type of option defines a key => value mapping.
These are a bit obscure. The best example is gcc’s
-Doption. The final value is a
<string-table>containing each specified key, with one of the following values:
#t: The user specified “-Dkey”
a string: The user specified “-Dkey=value”
You can read this with
element(table, key, default: #f)to get a handy lookup table.
-Dkey, -Dkey=value, -D key = value, --define key = value
- <positional-option> Sealed Class#
Accepts an argument that is passed by possition on the command line.
If you want your command-line parser to accept positional arguments you must add
<positional-option>instances to it. Positional options must come after all non-positional options.
By default, positional options are marked as required but you may pass
required?: #fto make them optional. Note that it is an error to add a required positional option after an optional positional option since there is no way to parse that unambiguously.
<positional-option>may be marked as accepting any number of arguments by passing
repeated?: #twhen calling
make. An option marked as repeated must be the last option in the parser’s list of options.
In this example the command line requires one filename to be passed on the command line, and one or more words after that:
add-option(parser, make(<positional-option>, names: #("filename"), help: "A filename")); add-option(parser, make(<positional-option>, names: #("words"), help: "One or more words", repeated?: #t)); // Usage: app [options] FILENAME WORDS...
This module exports an API that can be used to extend the existing command line parser without modifying the source in this library. It shouldn’t be common to need this and it is likely to be incomplete. See the source code for details.