Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 97 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,82 +24,135 @@ or add the following to your `project.clj` ([Leiningen](https://leiningen.org/))
```
<!-- /installation -->

## Rationale

This is an opinionated CLI argument handling library. It is meant for command
line tools with subcommands (for example git, which has `git commit`, `git log`
and so forth). It works exactly how we like it, which mostly means it sticks to
common conventions (in particular the prominent GNU conventions), needs little
ceremony, and provides your tool with built-in help facilities automagically.

It is Babashka compatible, and in fact pairs really nicely with `bb` for making
home-grown or general purpose tools.
## Getting Started

It scales from extremely low ceremony basic scripts, to fairly complex setups.
Here, we will explain how to use `com.lambdaisland/cli` to create a simple script that can print out the options it receives and handle basic help.

This library helps you write [Well-behaved Command Line
Tools](https://lambdaisland.com/blog/2020-07-28-well-behaved-command-line-tools)
### Step 1: Create the Basic Command

## Usage
Init the `bb.edn` with

The main entrypoint is `lambdaisland.cli/dispatch`, usually you're fine with the
single-argument version, which defaults to consuming `*command-line-args*`.
```
{:deps {com.lambdaisland/cli {:mvn/version "0.24.97"}}}
```

At its simplest you just pass it a var of a function named the same as your
script (this matters for the help text, as well see below).
Create a file (e.g., `cli-test.bb`):

```clj
```
#!/usr/bin/env bb

(require '[lambdaisland.cli :as cli]
'[clojure.pprint :as pprint])

;; 1. Define your main function.
(defn cli-test
"Ground breaking tool breaks new ground."
[flags]
(pprint/pprint flags))

;; 2. Dispatch the function (using its var).
(cli/dispatch #'cli-test)
```

This is enough to get a basic `--help` output.
Run it:

``` shell
$ cli-test --help
Usage: cli-test [<args>]
```
$ bb cli-test.bb --help
NAME
cli-test —— Ground breaking tool breaks new ground.

Ground breaking tool breaks new ground.
SYNOPSIS
cli-test [<args>...]
```

And you can start passing positional arguments and basic flags to your script,
your function will receive these all as a single map.
By passing a function var (`#'cli-test`), the library automatically infers the name and docstring for help output.

### Step 2: Pass Arguments and Flags

Your command function receives all parsed input as a single map argument, conventionally named flags or opts.

Run it with some input

```shell
$ cli-test --abc hello world --format=txt
{:abc 1, :format "txt", :lambdaisland.cli/argv ["hello" "world"]}
```
$ bb cli-test.bb --abc hello world --format=txt
{:lambdaisland.cli/sources {},
:lambdaisland.cli/argv ["hello" "world"],
:abc 1,
:format "txt"}
```

To do more interesting things we first wrap the var in a map.
Flags beginning with `--` become map keys; remaining values are collected in `:lambdaisland.cli/argv`.

```clj
(cli/dispatch {:command #'cli-test})
### Step 3: Define Custom Flags

To gain control over how flags are parsed and to provide richer help text, we wrap the command var in a configuration map.

Modify your `cli-test.bb` to include a `:flags` configuration:

```
(cli/dispatch
{:command #'cli-test ; The function to call
:flags ["-v, --verbose" "Increases verbosity"
"--input FILE" "Specify the input file"]})
```

`:command` doesn't have to be a var, it can be a simple function, but with a var
the docstring will still be used, as well as the var name, so this is equivalent
to:
Run the updated help:

```
$ bb cli-test.bb --help
NAME
cli-test —— Ground breaking tool breaks new ground.

SYNOPSIS
cli-test [-v | --verbose] [--input FILE] [<args>...]

FLAGS
-v, --verbose Increases verbosity
--input FILE Specify the input file
```

Run the tool with the new flags:

```clj
(cli/dispatch
{:command #'cli-test
:doc "Ground breaking tool breaks new ground."
:name "cli-test"})
```
$ bb cli-test.bb -vvv --input=world.txt
{:lambdaisland.cli/sources
{:verbose "-v command line flag", :input "--input command line flag"},
:lambdaisland.cli/argv [],
:verbose 3,
:input "world.txt"}
```

Multiple short flags like `-vvv` are counted automatically, producing `:verbose 3`.

### Summary

- Step 1: Start with a single command using `cli/dispatch`.
- Step 2: Pass arguments and flags; everything becomes a map.
- Step 3: Add `:flags` for option parsing and richer help.

You now have a solid foundation for building more advanced multi-command tools.

## Rationale

This is an opinionated CLI argument handling library. It is meant for command
line tools with subcommands (for example git, which has `git commit`, `git log`
and so forth). It works exactly how we like it, which mostly means it sticks to
common conventions (in particular the prominent GNU conventions), needs little
ceremony, and provides your tool with built-in help facilities automagically.

It is Babashka compatible, and in fact pairs really nicely with `bb` for making
home-grown or general purpose tools.

It scales from extremely low ceremony basic scripts, to fairly complex setups.

This library helps you write [Well-behaved Command Line
Tools](https://lambdaisland.com/blog/2020-07-28-well-behaved-command-line-tools)

## How-to Guides

### Flags
We can add extra things to the dispatch configuration map, notably `:flags` and `:commands`. We'll explain flags first.

Now we can add extra things to the dispatch configuration map, notably `:flags`
and `:commands`. We'll explain flags first.
### How to Configure Flags for Type Conversion and Defaults

Because you haven't told lambdaisland/cli about the flags your script
understands, it has to guess how to handle them. If you have arguments like
Expand Down Expand Up @@ -286,7 +339,7 @@ must always be passed:
- `:coll?` flag can be specified multiple times, will result in a vector
- `:parse` function used to coerce the flag argument

### Commands
### How to Build a Multi-Command CLI Tool

`lambdaisland/cli` is specifically meant for CLI tools with multiple subcommands
(and sub-sub-commands, and so forth). In this way it forms an appealing
Expand Down