This manual describes how your tool ends up interacting with shells when you use Cmdliner.
For tools evaluating a command without sub commands the most general form of invocation is:
tool [OPTION]… [ARG]…
The tool automatically reponds to the --help
option by printing the help. If a version string is provided in the command information, it also automatically responds to the --version
option by printing this string on standard output.
Command line arguments are either optional or positional. Both can be freely interleaved but since Cmdliner
accepts many optional forms this may result in ambiguities. The special token --
can be used to resolve them: anything that follows it is treated as a positional argument.
Tools evaluating commands with sub commands have this form of invocation
tool [COMMAND]… [OPTION]… [ARG]…
Commands automatically respond to the --help
option by printing their help. The sequence of COMMAND
strings must be the first strings following the tool name – as soon as an optional argument is seen the search for a sub command stops.
An optional argument is specified on the command line by a name possibly followed by a value.
The name of an option can be short or long.
-h
, -q
, -I
.--help
, --silent
, --ignore-case
.More than one name may refer to the same optional argument. For example in a given program the names -q
, --quiet
and --silent
may all stand for the same boolean argument indicating the program to be quiet.
The value of an option can be specified in three different ways.
-o a.out
, --output a.out
.-oa.out
.--output=a.out
.Glued forms are especially useful if the value itself starts with a dash as is the case for negative numbers, --min=-10
.
An optional argument without a value is either a flag (see Cmdliner.Arg.flag
, Cmdliner.Arg.vflag
) or an optional argument with an optional value (see the ~vopt
argument of Cmdliner.Arg.opt
).
Short flags can be grouped together to share a single dash and the group can end with a short option. For example assuming -v
and -x
are flags and -f
is a short option:
-vx
will be parsed as -v -x
.-vxfopt
will be parsed as -v -x -fopt
.-vxf opt
will be parsed as -v -x -fopt
.-fvx
will be parsed as -f=vx
.Positional arguments are tokens on the command line that are not option names and are not the value of an optional argument. They are numbered from left to right starting with zero.
Since positional arguments may be mistaken as the optional value of an optional argument or they may need to look like option names, anything that follows the special token "--"
on the command line is considered to be a positional argument:
tool --option -- but --now we -are --all positional --argu=ments
Using the cmdliner library puts the following constraints on your command line interface:
--cmdliner
is reserved by the library.--help
, (and --version
if you specify a version string) is reserved by the library. Using it as a term or option name may result in undefined behaviour.Invalid_argument
.Non-required command line arguments can be backed up by an environment variable. If the argument is absent from the command line and the environment variable is defined, its value is parsed using the argument converter and defines the value of the argument.
For Cmdliner.Arg.flag
and Cmdliner.Arg.flag_all
that do not have an argument converter a boolean is parsed from the lowercased variable value as follows:
""
, "false"
, "no"
, "n"
or "0"
is false
."true"
, "yes"
, "y"
or "1"
is true
.Note that environment variables are not supported for Cmdliner.Arg.vflag
and Cmdliner.Arg.vflag_all
.
Help and man pages are are generated when you call your tool or a sub command with --help
. By default, if the TERM
environment variable is not dumb
or unset, the tool tries to page the manual so that you can directly search it. Otherwise it outputs the manual as plain text.
Alternative help formats can be specified with the optional argument of --help
, see your own tool --help
for more information.
tool --help
tool cmd --help
tool --help=groff > tool.1
The pager is selected by looking up, in order:
MANPAGER
variable.PAGER
variable.less
.more
.Regardless of the pager, it is invoked with LESS=FRX
set in the environment unless, the LESS
environment variable is set in your environment.
Cmdliner programs automatically get support for shell command line completion.
The completion process happens via a protocol which is interpreted by generic shell completion scripts that are installed by the library. For now the zsh
and bash
shells are supported.
Tool developers can easily install completion definitions that invoke these completion scripts. Tool end-users need to make sure these definitions are looked up by their shell.
If you are the user of a cmdliner based tool, the following shell-dependent steps need to be performed in order to benefit from command line completion.
zsh
The FPATH
environment variable must be setup to include the directory where the generic cmdliner completion function is installed before properly initializing the completion system.
For example, for now, if you are using opam
. You should add something like this to your .zshrc
:
FPATH="$(opam var share)/zsh/site-functions:${FPATH}"
autoload -Uz compinit
compinit -u
Also make sure this happens before opam
's zsh
init script inclusion, see this issue.
After this, to test everything is right, check that the _cmdliner_generic
function can be looked by invoking it (this will result in an error).
> autoload _cmdliner_generic
> _cmdliner_generic
_cmdliner_generic:1: words: assignment to invalid subscript range
If the function cannnot be found make sure the cmdliner
library is installed, that the generic scripts were installed and that the _cmdliner_generic
file can be found in one of the directories mentioned in the FPATH
variable.
With this setup, if you are using a cmdliner based tool named thetool
that did not install a completion definition. You can always do it yourself by invoking:
autoload _cmdliner_generic
compdef _cmdliner_generic thetool
bash
These instructions assume that you have bash-completion
installed and setup in some way in your .bashrc
.
The XDG_DATA_DIRS
environment variable must be setup to include the share
directory where the generic cmdliner completion function is installed.
For example, for now, if you are using opam
. You should add something like this to your .bashrc
:
XDG_DATA_DIRS="$(opam var share):${XDG_DATA_DIRS}"
After this, to test everything is right, check that the _cmdliner_generic
function can be looked up:
> _comp_load _cmdliner_generic
> declare -F _cmdliner_generic &>/dev/null && echo "Found" || echo "Not found"
Found!
If the function cannot be found make sure the cmdliner
library is installed, that the generic scripts were installed and that the _cmdliner_generic
file can be looked up by _comp_load
.
With this setup, if you are using a cmdliner based tool named thetool
that did not install a completion definition. You can always do it yourself by invoking:
_comp_load _cmdliner_generic
complete -F _cmdliner_generic thetool
Completion scripts need to be installed in subdirectories of a share
directory which we denote by the $SHAREDIR
variable below. In a package installation script this variable is typically defined by:
SHAREDIR="$DESTDIR/$PREFIX/share"
The final destination directory in share
depends on the shell:
zsh
it is $SHAREDIR/zsh/site-functions
bash
it is $SHAREDIR/bash-completion/completions
If that is unsatisfying you can output the completion scripts directly where you want with the cmdliner generic-completion
and cmdliner tool-completion
commands.
The generic completion scripts must be installed by the cmdliner
library. They should not be part of your tool install. If they are not installed you can inspect and install them with the following invocations, invoke with --help
for more information.
cmdliner generic-completion zsh # Output generic zsh script on stdout
cmdliner install generic-completion $SHAREDIR # All shells
cmdliner install generic-completion --shell zsh $SHAREDIR # Only zsh
Directories are created as needed. Use option --dry-run
to see which paths would be written by an install
invocation.
If your tool named thetool
uses Cmdliner you should install completion definitions for them. They rely on the generic scripts to be installed. These tool specific scripts can be inspected and installed via these invocations:
cmdliner tool-completion zsh thetool # Output tool zsh script on stdout.
cmdliner install tool-completion thetool $SHAREDIR # All shells
cmdliner install tool-completion --shell zsh thetool $SHAREDIR # Only zsh
Directories are created as needed. Use option --dry-run
to see which paths would be written by an install
invocation.
If you are installing your package for thetool
with opam
and have cmdliner
as a direct dependency you can add the following to your install:
instructions. It will install completion support for all shells supported by cmdliner
(also works if your build system is using a .install
file):
install: [ "cmdliner" "install" "tool-completion" "thetool" "%{share}%"]
If cmdliner
is only an optional dependency use:
install: [ "cmdliner" "install" "tool-completion" "thetool" "%{share}%"
{cmdliner:installed} ]
There is no standard that allows tools and shells to interact to perform shell command line completion. Completion is supposed to happen through idiosyncratic, ad-hoc, obscure and brain damaging shell-specific completion scripts.
To aleviate this, Cmdliner defines one generic script per shell and interacts with it using the protocol described below. The protocol can be used to implement generic completion scripts for other shells. The protocol is versioned but can change even between minor versions of Cmdliner. Generic scripts for popular shells can be inspected via the cmdliner shell-completion generic
command.
The protocol betwen the shell completion script and a cmdliner based tool is as follows:
ARG
on which completion is requested with the special argument +cmdliner-complete:ARG
.completions
rule of the grammar given below.The following ABNF grammar is described using the notations of RFC 5234 and RFC 7405. A few constraints are not expressed by the grammar:
completion
rule, the byte stream may contain ANSI escape sequences introduced by the byte 0x1B
.completions = version nl directives
version = "1"
directives = *(directive nl)
directive = group / %s"file" / %s"dir"
group = %s"group" nl group_name nl *item
group_name = *pchar
item = %s"item" nl completion nl description
completion = *pchar
description = *pchar
nl = %0A
pchar = %20-%7E / %8A-%FF
The semantics of directives is as follows:
group
directive defines an informational group_name
followed by a possibly empty list of completion items that are part of the group. An item provides a completion
value followed by a single line description
which can include ANSI escapes.file
directive indicates that the script should add existing files staring with ARG
to completion values.dir
directive indicates that the script should add existing directories starting with ARG
to completion values.Before Cmdliner 2.0, command names, long option names and Cmdliner.Arg.enum
values could be specified by a prefix as long as the prefix was not ambiguous.
This turned out to be a mistake. It makes the user experience of the tool unstable as it evolves: former user established shortcuts or invocations in scripts may be broken by new command, option and enumerant additions.
Therefore this behaviour was unconditionally removed in Cmdliner 2.0. If you happen to have scripts that rely on it, you can invoke them with CMDLINER_LEGACY_PREFIXES=true
set in the environment to recover the old behaviour. However the scripts should be fixed: this escape hatch will be removed in the future.