package climate
Install
Dune Dependency
Authors
Maintainers
Sources
sha256=cf48ceef18975a26c1986a547dd2f86f47833264fcd29d1f3759fc7b6d20aa6f
sha512=fe46184cb8613ce84155d7c82b141da2ab9cbcc6205b25c1dc10d98660ded2eec1768bbcb67394f72b3706d0337f141adf18c8550bd0392ae87143d1229de6f3
Description
Published: 29 Nov 2024
README
Climate
A declarative command-line parser for OCaml.
Rationale
Programs written in OCaml should conform to existing UX conventions so as to match the expectations of users coming from other tools. For command-line programs which wish to parse their arguments in a declarative style, existing solutions all seem to deviate from the conventions established by common Unix tools. The two popular libraries for declarative command-line argument parsing in OCaml arecmdliner
and base
's Command
module. Both of these libraries present unconventional behaviour in that non-ambiguous prefixes of arguments are treated as the full argument names. Additionally, cmdliner
lacks support for generating shell autocompletion scripts, and base
only supports arguments beginning with a single -
.
This library aims to be an alternative to cmdliner
and Base.Command
with support for generating autocompletion scripts and which behaves as conventionally as possible.
Example
Here's a complete example program with built-in support for generating its own completion script.
open Climate
module Color = struct
type t =
| Red
| Green
| Blue
(* Tell climate how to handle colours *)
let conv =
let open Arg_parser in
enum ~default_value_name:"COLOR" [ "red", Red; "green", Green; "blue", Blue ]
;;
end
(* Ansi escape sequence to reset the termminal style *)
let ansi_reset = "\x1b[0m"
(* Returns the escape sequence to set the terminal style *)
let ansi_style ~bold ~underline ~color =
let effects =
List.append (if bold then [ ";1" ] else []) (if underline then [ ";4" ] else [])
in
let color_code =
match (color : Color.t option) with
| None -> 0
| Some Red -> 31
| Some Green -> 32
| Some Blue -> 34
in
Printf.sprintf "\x1b[%d%sm" color_code (String.concat "" effects)
;;
(* Print the words in the given style *)
let main ~bold ~underline ~color words =
print_string (ansi_style ~bold ~underline ~color);
print_string (String.concat " " words);
print_string ansi_reset;
print_newline ()
;;
let () =
let command =
Command.singleton ~desc:"Echo with style!"
@@
let open Arg_parser in
(* Describe and parse the command line arguments:*)
let+ bold = flag [ "bold" ] ~desc:"Make the text bold"
and+ underline = flag [ "underline" ] ~desc:"Underline the text"
and+ color = named_opt [ "color" ] Color.conv ~desc:"Set the text color"
and+ words = pos_all string
and+ completion =
flag [ "completion" ] ~desc:"Print this program's completion script and exit"
in
if completion
then `Completion
else `Main (fun () -> main ~bold ~underline ~color words)
in
(* Run the parser yielding either a main function to call or an indication
that we should print the completion script. *)
match Command.run command with
| `Completion -> print_endline (Command.completion_script_bash command)
| `Main main -> main ()
;
This program lives in examples/echo_ansi.ml
. Run it with dune exec examples/echo_ansi.exe -- <ARGS>
. E.g.
$ dune exec examples/echo_ansi.exe -- --help
Usage: _build/default/examples/echo_ansi.exe [OPTIONS] [STRING]...
Echo with style!
Options:
--bold Make the text bold
--underline Underline the text
--color <COLOR> Set the text color
--completion Print this program's completion script and exit
--help, -h Print help
The easiest way to setup the completion script is to first put the executable in a directory in your PATH. E.g.
$ mkdir -p ~/bin
$ export PATH=$HOME/bin:$PATH
$ dune build
$ cp _build/default/examples/echo_ansi.exe ~/bin/echo_ansi
You can ask echo_ansi
to print out its own completion script with:
$ echo_ansi --completion
#!/usr/bin/env bash
# Completion script for echo_ansi. Generated by climate.
__climate_complete_1184462387__complete() {
__climate_complete_1184462387__comp_words_traverse_init
if [ "$COMP_CWORD" == "0" ]; then
...
Put the completion script in a file and then source
that file in your shell to enable completions for echo_ansi
:
$ echo_ansi --completion > /tmp/echo_ansi_completions.sh
$ source /tmp/echo_ansi_completions.sh
$ echo_ansi --color <TAB>
blue green red
Currently only bash is supported, though it also works in zsh if bash compatibility is enabled:
# put this in your ~/.zshrc
autoload -Uz compinit bashcompinit
compinit
bashcompinit
Manual
Terminology
Term will refer to each space-delimited string on the command line after the program name. The command ls -l --color=always /etc/
has 3 terms. The program name is ls
(not a term), and the terms are -l
, --color=always
, and /etc/
.
Argument will refer to each distinct piece of information passed to the program on the command line. The command make -td --jobs 4 all
has 4 arguments. The -td
term is made up of two arguments combined into a single term: -t
and -d
(more on this later). --jobs 4
is a single argument comprising two terms, where 4
is a parameter to the argument --jobs
. The final term all
is also an argument.
Arguments may be positional or named. Positional arguments are identified by their position in the argument list rather than by name. Named arguments may have two forms: short and long. Short named arguments begin with a single -
followed by a single non -
character, such as -l
. Long named arguments begin with --
followed by one or more non -
characters, such as --jobs
. A collection of short named arguments may be combined together with a single leading -
followed by each short argument name. For example in ls -la
, the -la
is an alternative way of writing -l -a
.
A named argument may take a parameter. A parameter is a single value which follows the argument on the command line. Using make
's --jobs
argument as an example, here are the different ways of passing a parameter to a named argument on the command line:
make --jobs=4 # long name with equals sign
make --jobs 4 # long name space delimited
make -j 4 # short name space delimited
make -j4 # short name without space
If multiple short arguments are combined into a single term then only one of those arguments may take a parameter. If the parameterized argument appears as the final argument in the sequence then the following term will be treated as its parameter, such as in make -dj 4
, which is equivalent to make -d -j 4
. If the parameterized argument appears in a non-final position within the sequence then the remainder of the sequence is treated as its parameter, such as in make -dj4
which is also equivalent to make -d -j 4
.