CLI
is a simple CLI library for Carp.
(load "git@github.com:carpentry-org/cli.carp@0.4.0")
(defn main []
(let [p (=> (CLI.new @"My super cool tool!")
(CLI.add &(CLI.int "flag" "f" "my flag" true))
(CLI.add &(CLI.str "thing" "t" "my thing" false @"hi" &[@"a" @"b" @"hi"])))]
(match (CLI.parse &p)
(Result.Success flags)
(println* &(str &(Map.get &flags "flag")) " " &(str &(Map.get &flags "thing")))
(Result.Error msg) (do (IO.errorln &msg) (CLI.usage &p)))))
Installation
(load "git@github.com:carpentry-org/cli.carp@0.4.0")
Usage
CLI should be built using combinators, as in the example above. It has, as of
now, three option types: integrals (longs), floating point numbers (doubles),
and strings. They can be built using CLI.int, CLI.float, CLI.bool, and
CLI.str, respectively. Their structure is always the same, except for
booleans:
(CLI.int <long> <short> <description> <required?>)
; or
(CLI.int <long> <short> <description> <required?> <default>)
; or
(CLI.int <long> <short> <description> <required?> <default> <options-array>)
You’ll have to set a default if you want to specify options, although you can
set it to (Maybe.Nothing) if you want to make sure that it has to be set
manually.
Booleans neither take defaults nor options. If a boolean flag receives a value,
it will be read as true unless it’s the string false.
Positional Arguments
Positional arguments are non-flag tokens matched by position. Build them with
CLI.pos-str, CLI.pos-int, or CLI.pos-float:
(CLI.pos-str <name> <description> <required?>)
Add them to the parser with CLI.add-pos. Flags and positionals can be
interleaved freely on the command line.
Once you’re done building your flag structure, you can run CLI.parse. It
will not abort the program on error, instead it will tell you what went wrong
in a Result.Error. If it succeeds, the Result.Success contains a Map from
the long flag name (or positional argument name) to the value. The values are
not in the map if they are unset.
App
Module
bundles a program description with a set of named subcommands, each
its own Parser — the shape of a tool like git or docker, where
git commit and git push are independent parsers with their own options and
positionals. Build one with App.new and App.add, then
dispatch with App.parse. Adding subcommands is purely additive: a
plain Parser still works exactly as before.
Completion
Module
generates shell completion scripts from the same
Parser or App that does the parsing, so the completions
cannot drift from the flags the program actually accepts.
(IO.println &(CLI.Completion.bash &p "mytool"))
(IO.println &(CLI.Completion.App.zsh &app "mytool"))
bash, zsh and fish are supported, for a Parser and — under
Completion.App — for an App. Descriptions, flag names and
declared value sets are quoted and escaped for the target shell, so a
description containing quotes, backslashes or dollar signs cannot break (or
escape from) the generated script.
Dispatch
Module
is what dispatching an App yields. It answers not just
whether parsing succeeded, but whether help was requested and for what, so a
caller can show the right usage:
Parsed— success. Holds aPairof the chosen subcommand name and its parsed valueMap.AppHelp— top-level--help/-hwas given before any subcommand; respond withApp.usage.CommandHelp— a subcommand’s own--help/-hwas given; carries that subcommand’s name, so respond withApp.usage-for.Failure— carries a human-readable error message (a missing, unknown, or option-shaped leading token, or the subcommand’s own parse error).
Positional
Module
is the positional argument type. To construct a Positional,
please use pos-str, pos-int, or
pos-float.
add
(Fn [CLI.Parser, (Ref CLI.Option a)] CLI.Parser)
(add p opt)
adds an Option opt to the Parser p.
add-pos
(Fn [CLI.Parser, (Ref CLI.Positional a)] CLI.Parser)
(add-pos p pos)
adds a Positional argument pos to the Parser p.
float
Macro
(float long short description required :rest default-options)
creates a floating point option. The actual type is a Double.
int
Macro
(int long short description required :rest default-options)
creates an integer option. The actual type is a Long.
new
(Fn [String] CLI.Parser)
(new descr)
creates a new Parser with a program description descr.
parse
(Fn [(Ref CLI.Parser a)] (Result (Map String CLI.Type) String))
(parse p)
parses the process arguments as specified by the parser p,
skipping the program name.
On success it returns a Success holding a Map from each long option (and
positional argument name) to its value; unset values are absent from the map.
Non-flag tokens fill positional arguments in the order they were added, and
flags and positionals can be interleaved freely. A bare -- ends option
parsing — every following token becomes a positional even if it starts with -
— and a token shaped like a negative number (-5, -3.14), or a lone -
(conventionally standard input), is a positional, not an unknown option.
An option can carry its value in the same token, as --name=value or
-n=value; only the first = separates them, so --define=x=1 sets define
to x=1.
A single-dash token that matches no option exactly is decomposed into
single-character short options, so -av is -a -v. Booleans continue the
bundle; the first option that takes a value ends it and reads the rest of the
token as its value, or the next token if nothing is left (-n5, -avn5,
-avn 5). If any letter is not a known short option the whole token is
rejected.
On failure it returns an Error with a message — except that an empty error
message means --help (or -h) was requested. Override that flag if you don’t
want the built-in help behaviour.
str
Macro
(str long short description required :rest default-options)
creates a string option.
usage
(Fn [(Ref CLI.Parser a)] ())
(usage p)
takes a Parser p and prints its usage information.