CLI

is a simple CLI library for Carp.

(load "git@github.com:carpentry-org/cli.carp@0.2.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.2.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

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.

Dispatch

module

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 a Pair of the chosen subcommand name and its parsed value Map.
  • AppHelp — top-level --help/-h was given before any subcommand; respond with App.usage.
  • CommandHelp — a subcommand’s own --help/-h was given; carries that subcommand’s name, so respond with App.usage-for.
  • Failure — carries a human-readable error message (a missing, unknown, or option-shaped leading token, or the subcommand’s own parse error).

Option

module

Module

is the option type. To construct an Option, please use int, float, or str.

Parser

module

Module

is the parser type. To construct a Parser, please use new.

Positional

module

Module

is the positional argument type. To construct a Positional, please use pos-str, pos-int, or pos-float.

add

defn

(Fn [CLI.Parser, (Ref CLI.Option a)] CLI.Parser)

                        (add p opt)
                    

adds an Option opt to the Parser p.

add-pos

defn

(Fn [CLI.Parser, (Ref CLI.Positional a)] CLI.Parser)

                        (add-pos p pos)
                    

adds a Positional argument pos to the Parser p.

bool

macro

Macro

                        (bool long short description)
                    

creates a boolean option.

float

macro

Macro

                        (float long short description required :rest default-options)
                    

creates a floating point option. The actual type is a Double.

int

macro

Macro

                        (int long short description required :rest default-options)
                    

creates an integer option. The actual type is a Long.

new

defn

(Fn [String] CLI.Parser)

                        (new descr)
                    

creates a new Parser with a program description descr.

parse

defn

(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) is a positional, not an unknown option.

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.

pos-float

macro

Macro

                        (pos-float n desc req)
                    

creates a positional floating point argument.

pos-int

macro

Macro

                        (pos-int n desc req)
                    

creates a positional integer argument.

pos-str

macro

Macro

                        (pos-str n desc req)
                    

creates a positional string argument.

str

macro

Macro

                        (str long short description required :rest default-options)
                    

creates a string option.

usage

defn

(Fn [(Ref CLI.Parser a)] ())

                        (usage p)
                    

takes a Parser p and prints its usage information.