mirror of
https://github.com/c-cube/linol.git
synced 2025-12-06 03:05:31 -05:00
28 lines
25 KiB
HTML
28 lines
25 KiB
HTML
<!DOCTYPE html>
|
||
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>cli (cmdliner.cli)</title><meta charset="utf-8"/><link rel="stylesheet" href="../_odoc-theme/odoc.css"/><meta name="generator" content="odoc 3.1.0"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/><script src="../highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body class="odoc"><nav class="odoc-nav"><a href="index.html">Up</a> – <a href="../index.html">Index</a> » <a href="index.html">cmdliner</a> » cli</nav><header class="odoc-preamble"><h1 id="cmdline"><a href="#cmdline" class="anchor"></a>Command line interface</h1><p>This manual describes how your tool ends up interacting with shells when you use Cmdliner.</p></header><div class="odoc-tocs"><nav class="odoc-toc odoc-local-toc"><ul><li><a href="#invocation">Tool invocation</a></li><li><a href="#args">Arguments</a><ul><li><a href="#optargs">Optional arguments</a></li><li><a href="#posargs">Positional arguments</a></li><li><a href="#constraints">Constraints on option names</a></li></ul></li><li><a href="#envlookup">Environment variables</a></li><li><a href="#help">Help and man pages</a><ul><li><a href="#paging">Paging</a></li><li><a href="#install_tool_manpages">Install</a></li></ul></li><li><a href="#cli_completion">Command line completion</a><ul><li><a href="#user_configuration">End-user configuration</a><ul><li><a href="#user_zsh">For <code>zsh</code></a></li><li><a href="#user_bash">For <code>bash</code></a></li></ul></li><li><a href="#install_completion">Install</a><ul><li><a href="#install_generic_completion">Generic completion scripts</a></li><li><a href="#install_tool_completion">Tool completion scripts</a></li></ul></li><li><a href="#completion_protocol">Completion protocol</a></li></ul></li><li><a href="#error_message_styling">Error message ANSI styling</a></li><li><a href="#legacy_prefix_specification">Legacy prefix specification</a></li></ul></nav></div><div class="odoc-content"><h2 id="invocation"><a href="#invocation" class="anchor"></a>Tool invocation</h2><p>For tools evaluating a command without subcommands the most general form of invocation is:</p><pre>tool [OPTION]… [ARG]…</pre><p>The tool automatically reponds to the <code>--help</code> option by printing <a href="#help" title="help">the help</a>. If a version string is provided in the <a href="Cmdliner/Cmd/index.html#val-info" title="Cmdliner.Cmd.info">command information</a>, it also automatically responds to the <code>--version</code> option by printing this string on standard output.</p><p>Command line arguments are either <a href="#optargs" title="optargs"><em>optional</em></a> or <a href="#posargs" title="posargs"><em>positional</em></a>. Both can be freely interleaved but since <code>Cmdliner</code> accepts many optional forms this may result in ambiguities. The special <a href="#posargs" title="posargs">token <code>--</code></a> can be used to resolve them: anything that follows it is treated as a positional argument.</p><p>Tools evaluating commands with subcommands have this form of invocation</p><pre>tool [COMMAND]… [OPTION]… [ARG]…</pre><p>Commands automatically respond to the <code>--help</code> option by printing <a href="#help" title="help">their help</a>. The sequence of <code>COMMAND</code> strings must be the first strings following the tool name – as soon as an optional argument is seen the search for a subcommand stops.</p><h2 id="args"><a href="#args" class="anchor"></a>Arguments</h2><h3 id="optargs"><a href="#optargs" class="anchor"></a>Optional arguments</h3><p>An optional argument is specified on the command line by a <em>name</em> possibly followed by a <em>value</em>.</p><p>The name of an option can be short or long.</p><ul><li>A <em>short</em> name is a dash followed by a single alphanumeric character: <code>-h</code>, <code>-q</code>, <code>-I</code>.</li><li>A <em>long</em> name is two dashes followed by alphanumeric characters and dashes: <code>--help</code>, <code>--silent</code>, <code>--ignore-case</code>.</li></ul><p>More than one name may refer to the same optional argument. For example in a given program the names <code>-q</code>, <code>--quiet</code> and <code>--silent</code> may all stand for the same boolean argument indicating the program to be quiet.</p><p>The value of an option can be specified in three different ways.</p><ul><li>As the next token on the command line: <code>-o a.out</code>, <code>--output a.out</code>.</li><li>Glued to a short name: <code>-oa.out</code>.</li><li>Glued to a long name after an equal character: <code>--output=a.out</code>.</li></ul><p>Glued forms are especially useful if the value itself starts with a dash as is the case for negative numbers, <code>--min=-10</code>.</p><p>An optional argument without a value is either a <em>flag</em> (see <a href="Cmdliner/Arg/index.html#val-flag"><code>Cmdliner.Arg.flag</code></a>, <a href="Cmdliner/Arg/index.html#val-vflag"><code>Cmdliner.Arg.vflag</code></a>) or an optional argument with an optional value (see the <code>~vopt</code> argument of <a href="Cmdliner/Arg/index.html#val-opt"><code>Cmdliner.Arg.opt</code></a>).</p><p>Short flags can be grouped together to share a single dash and the group can end with a short option. For example assuming <code>-v</code> and <code>-x</code> are flags and <code>-f</code> is a short option:</p><ul><li><code>-vx</code> will be parsed as <code>-v -x</code>.</li><li><code>-vxfopt</code> will be parsed as <code>-v -x -fopt</code>.</li><li><code>-vxf opt</code> will be parsed as <code>-v -x -fopt</code>.</li><li><code>-fvx</code> will be parsed as <code>-f=vx</code>.</li></ul><h3 id="posargs"><a href="#posargs" class="anchor"></a>Positional arguments</h3><p>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.</p><p>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 <code>"--"</code> on the command line is considered to be a positional argument:</p><pre>tool --option -- but --now we -are --all positional --argu=ments</pre><h3 id="constraints"><a href="#constraints" class="anchor"></a>Constraints on option names</h3><p>Using the cmdliner library puts the following constraints on your command line interface:</p><ul><li>The option names <code>--cmdliner</code> and <code>--__complete</code> are reserved by the library.</li><li>The option name <code>--help</code>, (and <code>--version</code> if you specify a version string) is reserved by the library. Using it as a term or option name may result in undefined behaviour.</li><li>Defining the same option or command name via two different arguments or terms is illegal and raises <code>Invalid_argument</code>.</li></ul><h2 id="envlookup"><a href="#envlookup" class="anchor"></a>Environment variables</h2><p>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.</p><p>For <a href="Cmdliner/Arg/index.html#val-flag"><code>Cmdliner.Arg.flag</code></a> and <a href="Cmdliner/Arg/index.html#val-flag_all"><code>Cmdliner.Arg.flag_all</code></a> that do not have an argument converter a boolean is parsed from the lowercased variable value as follows:</p><ul><li><code>""</code>, <code>"false"</code>, <code>"no"</code>, <code>"n"</code> or <code>"0"</code> is <code>false</code>.</li><li><code>"true"</code>, <code>"yes"</code>, <code>"y"</code> or <code>"1"</code> is <code>true</code>.</li><li>Any other string is an error.</li></ul><p>Note that environment variables are not supported for <a href="Cmdliner/Arg/index.html#val-vflag"><code>Cmdliner.Arg.vflag</code></a> and <a href="Cmdliner/Arg/index.html#val-vflag_all"><code>Cmdliner.Arg.vflag_all</code></a>.</p><h2 id="help"><a href="#help" class="anchor"></a>Help and man pages</h2><p>Help and man pages are are generated when you call your tool or a subcommand with <code>--help</code>. By default, if the <code>TERM</code> environment variable is not <code>dumb</code> or unset, the tool tries to <a href="#paging" title="paging">page</a> the manual so that you can directly search it. Otherwise it outputs the manual as plain text.</p><p>Alternative help formats can be specified with the optional argument of <code>--help</code>, see your own <code>tool --help</code> for more information.</p><pre class="language-sh"><code>tool --help
|
||
tool cmd --help
|
||
tool --help=groff > tool.1</code></pre><h3 id="paging"><a href="#paging" class="anchor"></a>Paging</h3><p>The pager is selected by looking up, in order:</p><ol><li>The <code>MANPAGER</code> variable.</li><li>The <code>PAGER</code> variable.</li><li>The tool <code>less</code>.</li><li>The tool <code>more</code>.</li></ol><p>Regardless of the pager, it is invoked with <code>LESS=FRX</code> set in the environment unless, the <code>LESS</code> environment variable is set in your environment.</p><h3 id="install_tool_manpages"><a href="#install_tool_manpages" class="anchor"></a>Install</h3><p>The manpages of a tool and its subcommands can be installed to a root <code>man</code> directory <code>$MANDIR</code> by invoking:</p><pre class="language-shell"><code>cmdliner install tool-manpages thetool $MANDIR</code></pre><p>This looks up <code>thetool</code> in the <code>PATH</code>. Use an explicit file path like <code>./thetool</code> to directly specify an executable.</p><p>If you are also <a href="#install_tool_completion" title="install_tool_completion">installing completions</a> rather use the <code>install tool-support</code> command, see this <a href="cookbook.html#tip_tool_support" title="tip_tool_support">cookbook tip</a> which also has instructions on how to install if you are using <code>opam</code>.</p><h2 id="cli_completion"><a href="#cli_completion" class="anchor"></a>Command line completion</h2><p>Cmdliner programs automatically get support for shell command line completion.</p><p>The completion process happens via a <a href="#completion_protocol" title="completion_protocol">protocol</a> which is interpreted by generic shell completion scripts that are installed by the library. For now the <code>zsh</code> and <code>bash</code> shells are supported.</p><p>Tool developers can easily <a href="#install_tool_completion" title="install_tool_completion">install</a> completion definitions that invoke these completion scripts. Tool end-users need to <a href="#user_configuration" title="user_configuration">make sure</a> these definitions are looked up by their shell.</p><h3 id="user_configuration"><a href="#user_configuration" class="anchor"></a>End-user configuration</h3><p>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.</p><h4 id="user_zsh"><a href="#user_zsh" class="anchor"></a>For <code>zsh</code></h4><p>The <code>FPATH</code> environment variable must be setup to include the directory where the generic cmdliner completion function is <a href="#install_completion" title="install_completion">installed</a> <b>before</b> properly initializing the completion system.</p><p>For example, <a href="https://github.com/ocaml/opam/issues/6427">for now</a>, if you are using <code>opam</code>. You should add something like this to your <code>.zshrc</code>:</p><pre class="language-sh"><code>FPATH="$(opam var share)/zsh/site-functions:${FPATH}"
|
||
autoload -Uz compinit
|
||
compinit -u</code></pre><p>Also make sure this <b>happens before</b> <code>opam</code>'s <code>zsh</code> init script inclusion, see <a href="https://github.com/ocaml/opam/issues/6428">this issue</a>. Note that these instruction do not react dynamically to <code>opam</code> switches changes so you may see odd completion behaviours when you do so, see this <a href="https://github.com/ocaml/opam/issues/6427">this opam issue</a>.</p><p>After this, to test everything is right, check that the <code>_cmdliner_generic</code> function can be looked by invoking it (this will result in an error).</p><pre class="language-sh"><code>> autoload _cmdliner_generic
|
||
> _cmdliner_generic
|
||
_cmdliner_generic:1: words: assignment to invalid subscript range</code></pre><p>If the function cannnot be found make sure the <code>cmdliner</code> library is installed, that the generic scripts were <a href="#install_generic_completion" title="install_generic_completion">installed</a> and that the <code>_cmdliner_generic</code> file can be found in one of the directories mentioned in the <code>FPATH</code> variable.</p><p>With this setup, if you are using a cmdliner based tool named <code>thetool</code> that did not <a href="#install_tool_completion" title="install_tool_completion">install</a> a completion definition. You can always do it yourself by invoking:</p><pre class="language-sh"><code>autoload _cmdliner_generic
|
||
compdef _cmdliner_generic thetool</code></pre><h4 id="user_bash"><a href="#user_bash" class="anchor"></a>For <code>bash</code></h4><p>These instructions assume that you have <a href="https://repology.org/project/bash-completion/versions"><code>bash-completion</code></a> installed and setup in some way in your <code>.bashrc</code>.</p><p>The <code>XDG_DATA_DIRS</code> environment variable must be setup to include the <code>share</code> directory where the generic cmdliner completion function is <a href="#install_completion" title="install_completion">installed</a>.</p><p>For example, <a href="https://github.com/ocaml/opam/issues/6427">for now</a>, if you are using <code>opam</code>. You should add something like this to your <code>.bashrc</code>:</p><pre class="language-sh"><code>XDG_DATA_DIRS="$(opam var share):${XDG_DATA_DIRS}"</code></pre><p>Note that these instruction do not react dynamically to <code>opam</code> switches changes so you may see odd completion behaviours when you do so, see this <a href="https://github.com/ocaml/opam/issues/6427">this opam issue</a>.</p><p>After this, to test everything is right, check that the <code>_cmdliner_generic</code> function can be looked up:</p><pre class="language-sh"><code>> _completion_loader _cmdliner_generic
|
||
> declare -F _cmdliner_generic &>/dev/null && echo "Found" || echo "Not found"
|
||
Found!</code></pre><p>If the function cannot be found make sure the <code>cmdliner</code> library is installed, that the generic scripts were <a href="#install_generic_completion" title="install_generic_completion">installed</a> and that the <code>_cmdliner_generic</code> file can be looked up by <code>_completion_loader</code>.</p><p>With this setup, if you are using a cmdliner based tool named <code>thetool</code> that did not <a href="#install_tool_completion" title="install_tool_completion">install</a> a completion definition. You can always do it yourself by invoking:</p><pre class="language-sh"><code>_completion_loader _cmdliner_generic
|
||
complete -F _cmdliner_generic thetool</code></pre><p><b>Note.</b> <a href="https://github.com/scop/bash-completion/commit/9efc596735c4509001178f0cf28e02f66d1f7703">It seems</a> <code>_completion_loader</code> was deprecated in bash-completion <code>2.12</code> in favour of <code>_comp_load</code> but many distributions are on <code>< 2.12</code> and in <code>2.12</code> <code>_completion_loader</code> simply calls <code>_comp_load</code>.</p><h3 id="install_completion"><a href="#install_completion" class="anchor"></a>Install</h3><p>Completion scripts need to be installed in subdirectories of a <a href="https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch04s11.html"><code>share</code></a> directory which we denote by the <code>$SHAREDIR</code> variable below. In a package installation script this variable is typically defined by:</p><pre class="language-sh"><code>SHAREDIR="$DESTDIR/$PREFIX/share"</code></pre><p>The final destination directory in <code>share</code> depends on the shell:</p><ul><li>For <code>zsh</code> it is <code>$SHAREDIR/zsh/site-functions</code></li><li>For <code>bash</code> it is <code>$SHAREDIR/bash-completion/completions</code></li></ul><p>If that is unsatisfying you can output the completion scripts directly where you want with the <code>cmdliner generic-completion</code> and <code>cmdliner tool-completion</code> commands.</p><h4 id="install_generic_completion"><a href="#install_generic_completion" class="anchor"></a>Generic completion scripts</h4><p>The generic completion scripts must be installed by the <code>cmdliner</code> 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 <code>--help</code> for more information.</p><pre class="language-sh"><code>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</code></pre><p>Directories are created as needed. Use option <code>--dry-run</code> to see which paths would be written by an <code>install</code> invocation.</p><h4 id="install_tool_completion"><a href="#install_tool_completion" class="anchor"></a>Tool completion scripts</h4><p>If your tool named <code>thetool</code> uses Cmdliner you should install completion definitions for them. They rely on the <a href="#install_generic_completion" title="install_generic_completion">generic scripts</a> to be installed. These tool specific scripts can be inspected and installed via these invocations:</p><pre class="language-sh"><code>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</code></pre><p>Directories are created as needed. Use option <code>--dry-run</code> to see which paths would be written by an <code>install</code> invocation.</p><p>If you are also <a href="#install_tool_manpages" title="install_tool_manpages">installing manpages</a> rather use the <code>install tool-support</code> command, see this <a href="cookbook.html#tip_tool_support" title="tip_tool_support">cookbook tip</a> which also has instructions on how to install if you are using <code>opam</code>.</p><h3 id="completion_protocol"><a href="#completion_protocol" class="anchor"></a>Completion protocol</h3><p>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.</p><p>To alleviate 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 <code>cmdliner generic-completion</code> command.</p><p>The protocol betwen the shell completion <em>script</em> and a cmdliner based <em>tool</em> is as follows:</p><ol><li><p>When completion is requested the script invokes the tool with a modified command line:</p><ul><li>The first argument to the tool (<code>Sys.argv.(1)</code>) must be the option <code>--__complete</code>.</li><li>The (possibly empty) argument <code>ARG</code> on which the completion is requested must be replaced by <em>exactly</em> <code>--__complete=ARG</code>. Note that this can happen after the <code>--</code> token, this is the reason why we have an explicit <code>--__complete</code> argument in <code>Sys.argv.(1)</code>: it indicates the command line parser must operate in a special mode.</li></ul></li><li>The tool responds by writing on standard output a list of completion directives which match the <code>completions</code> rule of the grammar given below.</li><li>The script interprets the completion directives according to the given semantics below so that the shell can display the completions. The script is free to ignore directives or data that it is unable to present.</li></ol><p>The following ABNF grammar is described using the notations of <a href="https://www.rfc-editor.org/rfc/rfc5234">RFC 5234</a> and <a href="https://www.rfc-editor.org/rfc/rfc7405">RFC 7405</a>. A few constraints are not expressed by the grammar:</p><ul><li>Except in the <code>completion</code> rule, the byte stream may contain ANSI escape sequences introduced by the byte <code>0x1B</code>.</li><li>After stripping the ANSI escape sequences, the resulting byte stream must be valid UTF-8 text.</li></ul><pre class="language-abnf"><code>completions = version nl directives
|
||
version = "1"
|
||
directives = *(directive nl)
|
||
directive = message / group / %s"files" / %s"dirs" / %"restart"
|
||
message = %s"message" nl text nl %s"message-end"
|
||
group = %s"group" nl group_name nl *item
|
||
group_name = *pchar
|
||
item = %s"item" nl completion nl item_doc nl %s"item-end"
|
||
completion = *pchar
|
||
item_doc = text
|
||
text = *(pchar / nl)
|
||
nl = %0A
|
||
pchar = %20-%7E / %8A-%FF</code></pre><p>The semantics of directives is as follows:</p><ul><li>A <code>message</code> directive defines a message to be reported to the user. It is multi-line ANSI styled text which cannot have a line that is exactly made of the text <code>message-end</code> as it is used to signal the end of the message. Messages should be reported in the order they are received.</li><li>A <code>group</code> directive defines an informational <code>group_name</code> followed by a possibly empty list of completion items that are part of the group. An item provides a <code>completion</code> value, this is a string that defines what the requested <code>ARG</code> value can be replaced with. It is followed by an <code>item_doc</code>, multi-line ANSI styled text which cannot have a line that is exactly made of the text <code>item-end</code> as it is used to signal the end of the item.</li><li>A <code>file</code> directive indicates that the script should add existing files staring with <code>ARG</code> to completion values.</li><li>A <code>dir</code> directive indicates that the script should add existing directories starting with <code>ARG</code> to completion values.</li><li>A <code>restart</code> directive indicates that the script should restart shell completion as if the command line was starting after the leftmost <code>--</code> disambiguation token. The directive never gets emited if there is no <code>--</code> on the command line.</li></ul><p>You can easily inspect the completions of any cmdliner based tool by invoking it like the protocol suggests. For example for the <code>cmdliner</code> tool itself:</p><pre class="language-shell"><code>cmdliner --__complete --__complete=</code></pre><h2 id="error_message_styling"><a href="#error_message_styling" class="anchor"></a>Error message ANSI styling</h2><p>Since Cmdliner 2.0 error messages printed on <code>stderr</code> use styled text with ANSI escapes unless one of the following conditions is met:</p><ul><li>The <code>NO_COLOR</code> environment variable is set and different from the empty string. Yes, even if you have <code>NO_COLOR=false</code>, that's what the particularly dumb <a href="https://no-color.org">https://no-color.org</a> standard says.</li><li>The <code>TERM</code> environment variable is <code>dumb</code>.</li><li>The <code>TERM</code> environment variable is unset and <code>Sys.backend_type</code> is not <code>Other "js_of_ocaml"</code>. Yes, browser consoles support ANSI escapes. Yes, you can run Cmdliner in your browser.</li></ul><h2 id="legacy_prefix_specification"><a href="#legacy_prefix_specification" class="anchor"></a>Legacy prefix specification</h2><p>Before Cmdliner 2.0, command names, long option names and <a href="Cmdliner/Arg/index.html#val-enum"><code>Cmdliner.Arg.enum</code></a> values could be specified by a prefix as long as the prefix was not ambiguous.</p><p>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.</p><p>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 <code>CMDLINER_LEGACY_PREFIXES=true</code> set in the environment to recover the old behaviour. <b>However the scripts should be fixed: this escape hatch will be removed in the future.</b></p><p>The <code>CMDLINER_LEGACY_PREFIX=true</code> escape hatch should not be used for interactive tool interaction. In particular the behaviour of Cmdliner completion support under this setting is undefined.</p></div></body></html>
|