A small, declarative argument parser for console commands, in the shape of Python's argparse.
A parser both reads a command's arguments and offers completions for them,
from one declaration. Every command written with trx.console.register has
one; a command shapes it through the trx.console.register.spec.args function
it hands over, and trx.console.register.spec.run then receives a table of
parsed values. A command that shapes nothing takes no arguments, and is told so
when given one.
Every parser answers -h and --help on its own, printing what it accepts.
How a positional reads a token is its matcher: a type to coerce to, a set of
choices, or a function of its own. These do not combine on one positional; a
value that is a number or a name is two matchers, declared with
trx.argparse.Parser:any_of.
Positionals are read in order, and an optional one a token does not fit is passed over: the token goes to the next positional, and the one skipped stays nil. That is what lets a command take a leading argument it can also be used without - a verb before a value, a count before a name. Completion follows the same path, so a slot offers what every argument reachable from it takes. A token nothing takes is reported against the first argument that refused it.
A choice is either a bare string, where the key and value are the same, or a
{ key, value } pair, where the key is matched and shown and the value is what
trx.argparse.Parser:parse gives back. Matching is forgiving, through
trx.strings.fuzzy_match.
An argument parser, built up a call at a time. Every method hands the parser back, so the calls chain.
Methods:
parser:any_of(name, alternatives, [opts])
Adds a positional whose value is the first of several matchers to take the token, for an argument that is a number or a name.
Parameters:
alternatives (a list of table). The ways the token may read, tried in order.
Each entry:
type (string, optional). As for positional.choices (any, optional). As for positional.match (function, optional). As for positional.metavar (string, optional). Names this alternative, which earns it a line of its own in the help.help (string, optional). What this alternative is for.opts (table, optional). How the argument behaves.
Keys:
optional (boolean, optional). Lets the argument be left out.greedy (boolean, optional). Reads the rest of the line as one token, so a value with spaces in it still arrives whole.metavar (string, optional). What the argument is called in messages and in the synopsis. Its own name by default.suggest (function, optional). Completions to offer, without restricting what is accepted or being shown in errors. For a free value with a long list behind it, like a setting name.help (string, optional). What the argument is for, shown in the help.Returns: trx.argparse.Parser. The same parser, so declarations chain.
parser:complete([text], [caret])
The candidate completions for the token the caret sits in. Matching is against the text before the caret.
Parameters:
text (string, optional). The line so far.caret (integer, optional). Where the caret sits, as a byte offset. The end of the line by default.Returns:
parser:flag(name, [opts])
Adds a boolean flag, which may sit anywhere in the line.
Parameters:
name (string). What the parsed value is keyed by. help is reserved.
opts (table, optional). How it is spelled and what it is for.
Keys:
Returns: trx.argparse.Parser. The same parser, so declarations chain.
parser:format_error(err)
Turns what a refused line reported into a localized line naming what was wrong and what was expected.
Parameters:
err (table). What parse handed back.Returns: string. The line, ready to print.
parser:parse([args])
Reads an argument line. A value carried by a { key, value } choice comes back as its value, and -h/--help comes back as { help = true }.
Parameters:
Returns:
nil. The values, keyed by argument name, or nil where the line was refused.nil. What was wrong, for format_error to put into words.parser:positional(name, [opts])
Adds a positional argument, read one way.
Parameters:
opts (table, optional). How it reads its token, and how it behaves. It reads a token one way: name at most one of opts.type, opts.choices and opts.match, and use any_of for several.
Keys:
type (string, optional). Coerce the token: "integer", "number", "string" or "boolean".choices (any, optional). The allowed set: a list of values, or a function of the values parsed so far returning one. The token must match one; the set is shown in errors and completes.match (function, optional). A function of the token and the values parsed so far, returning the value and whether it took, for a shape of its own.optional (boolean, optional). Lets the argument be left out.greedy (boolean, optional). Reads the rest of the line as one token, so a value with spaces in it still arrives whole.metavar (string, optional). What the argument is called in messages and in the synopsis. Its own name by default.suggest (function, optional). Completions to offer, without restricting what is accepted or being shown in errors. For a free value with a long list behind it, like a setting name.help (string, optional). What the argument is for, shown in the help.Returns: trx.argparse.Parser. The same parser, so declarations chain.
parser:rest(name, [opts])
Adds an argument taking the rest of the line from here on, verbatim as one string, or nil where an optional one is absent. Always the last argument.
Parameters:
opts (table, optional). How the argument behaves.
Keys:
optional (boolean, optional). Lets the argument be left out.greedy (boolean, optional). Reads the rest of the line as one token, so a value with spaces in it still arrives whole.metavar (string, optional). What the argument is called in messages and in the synopsis. Its own name by default.suggest (function, optional). Completions to offer, without restricting what is accepted or being shown in errors. For a free value with a long list behind it, like a setting name.help (string, optional). What the argument is for, shown in the help.Returns: trx.argparse.Parser. The same parser, so declarations chain.
parser:usage()
A short description of what the command accepts.
Returns: string. The synopsis, and a line per argument.
trx.argparse.new([spec])
Creates an argument parser.
Parameters:
Returns: trx.argparse.Parser. A parser, with no arguments declared on it yet.
Example:
local p = trx.argparse.new({ prog = "weather" })
p:positional("state", { choices = { "snow", "rain", "none" } })
local parsed = p:parse("snow") -- { state = "snow" }