From 247371f99016d1b4e7947f0383edfe297fd0a489 Mon Sep 17 00:00:00 2001 From: c-cube Date: Wed, 26 Nov 2025 00:50:10 +0000 Subject: [PATCH] deploy: fb49472f3461d806c097e17487c31325478740dc --- _odoc-theme/manual.css | 6 +- _odoc-theme/odoc.css | 6 +- cmdliner/Cmdliner/Arg/Completion/index.html | 5 + cmdliner/Cmdliner/Arg/Conv/index.html | 14 + cmdliner/Cmdliner/Arg/index.html | 31 +- cmdliner/Cmdliner/Cmd/Env/index.html | 7 +- cmdliner/Cmdliner/Cmd/Exit/index.html | 7 +- cmdliner/Cmdliner/Cmd/index.html | 16 +- cmdliner/Cmdliner/Manpage/index.html | 5 +- cmdliner/Cmdliner/Term/Syntax/index.html | 2 +- cmdliner/Cmdliner/Term/index.html | 32 +- cmdliner/Cmdliner/index.html | 2 +- cmdliner/Cmdliner_arg/index.html | 2 + cmdliner/Cmdliner_base/index.html | 2 + cmdliner/Cmdliner_cline/index.html | 2 + cmdliner/Cmdliner_cmd/index.html | 2 + cmdliner/Cmdliner_completion/index.html | 2 + cmdliner/Cmdliner_def/index.html | 2 + cmdliner/Cmdliner_docgen/index.html | 2 + cmdliner/Cmdliner_eval/index.html | 2 + cmdliner/Cmdliner_manpage/index.html | 2 + cmdliner/Cmdliner_msg/index.html | 2 + cmdliner/Cmdliner_term/index.html | 2 + cmdliner/Cmdliner_trie/index.html | 2 + cmdliner/_doc-dir/CHANGES.md | 142 +++- cmdliner/_doc-dir/LICENSE.md | 0 cmdliner/_doc-dir/README.md | 36 +- cmdliner/_doc-dir/odoc-pages/cli.mld | 421 +++++++++++- cmdliner/_doc-dir/odoc-pages/cookbook.mld | 720 ++++++++++++++++++++ cmdliner/_doc-dir/odoc-pages/examples.mld | 158 +++-- cmdliner/_doc-dir/odoc-pages/index.mld | 44 +- cmdliner/_doc-dir/odoc-pages/tool_man.mld | 37 +- cmdliner/_doc-dir/odoc-pages/tutorial.mld | 147 ++-- cmdliner/cli.html | 28 +- cmdliner/cookbook.html | 173 +++++ cmdliner/examples.html | 124 ++-- cmdliner/index.html | 2 +- cmdliner/tool_man.html | 2 +- cmdliner/tutorial.html | 38 +- index.html | 2 +- linol-lwt/_doc-dir/CHANGES.md | 5 + linol/_doc-dir/CHANGES.md | 5 + logs/Logs_cli/index.html | 23 +- logs/_doc-dir/CHANGES.md | 8 +- logs/_doc-dir/odoc-pages/index.mld | 2 +- lwt/_doc-dir/CHANGES | 24 + ocaml/index.html | 2 +- 47 files changed, 1921 insertions(+), 379 deletions(-) create mode 100644 cmdliner/Cmdliner/Arg/Completion/index.html create mode 100644 cmdliner/Cmdliner/Arg/Conv/index.html create mode 100644 cmdliner/Cmdliner_arg/index.html create mode 100644 cmdliner/Cmdliner_base/index.html create mode 100644 cmdliner/Cmdliner_cline/index.html create mode 100644 cmdliner/Cmdliner_cmd/index.html create mode 100644 cmdliner/Cmdliner_completion/index.html create mode 100644 cmdliner/Cmdliner_def/index.html create mode 100644 cmdliner/Cmdliner_docgen/index.html create mode 100644 cmdliner/Cmdliner_eval/index.html create mode 100644 cmdliner/Cmdliner_manpage/index.html create mode 100644 cmdliner/Cmdliner_msg/index.html create mode 100644 cmdliner/Cmdliner_term/index.html create mode 100644 cmdliner/Cmdliner_trie/index.html mode change 100755 => 100644 cmdliner/_doc-dir/CHANGES.md mode change 100755 => 100644 cmdliner/_doc-dir/LICENSE.md mode change 100755 => 100644 cmdliner/_doc-dir/README.md mode change 100755 => 100644 cmdliner/_doc-dir/odoc-pages/cli.mld create mode 100644 cmdliner/_doc-dir/odoc-pages/cookbook.mld mode change 100755 => 100644 cmdliner/_doc-dir/odoc-pages/examples.mld mode change 100755 => 100644 cmdliner/_doc-dir/odoc-pages/index.mld mode change 100755 => 100644 cmdliner/_doc-dir/odoc-pages/tool_man.mld mode change 100755 => 100644 cmdliner/_doc-dir/odoc-pages/tutorial.mld create mode 100644 cmdliner/cookbook.html diff --git a/_odoc-theme/manual.css b/_odoc-theme/manual.css index 92a1b438..5e17c4d3 100644 --- a/_odoc-theme/manual.css +++ b/_odoc-theme/manual.css @@ -3,8 +3,8 @@ @import url("theme.css"); /* Copyright (c) 2019 The odig programmers. All rights reserved. - Distributed under the ISC license, see terms at the end of the file. - odig v0.0.9 */ + SPDX-License-Identifier: ISC + odig v0.1.0 */ :root { --font-headings: "PT-Sans-Caption"; --font-body: "PT-Sans"; @@ -373,4 +373,4 @@ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +*/ \ No newline at end of file diff --git a/_odoc-theme/odoc.css b/_odoc-theme/odoc.css index 1dbc9da2..c6362b73 100644 --- a/_odoc-theme/odoc.css +++ b/_odoc-theme/odoc.css @@ -3,7 +3,7 @@ @import url("theme.css"); /* Copyright (c) 2019 The odig programmers. All rights reserved. - Distributed under the ISC license, see terms at the end of the file. */ + SPDX-License-Identifier: ISC */ /* Reset a few things. */ @@ -62,7 +62,7 @@ table { border-collapse: collapse; border-spacing: 0; } .odoc-nav { grid-area: nav; } .odoc-preamble { grid-area: header; } .odoc-content { grid-area: content; margin: 0 } -.odoc-toc +.odoc-tocs { grid-area: toc; margin-top: var(--size-line); border-top: solid thin var(--color-rule); } @@ -331,4 +331,4 @@ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +*/ \ No newline at end of file diff --git a/cmdliner/Cmdliner/Arg/Completion/index.html b/cmdliner/Cmdliner/Arg/Completion/index.html new file mode 100644 index 00000000..9d887053 --- /dev/null +++ b/cmdliner/Cmdliner/Arg/Completion/index.html @@ -0,0 +1,5 @@ + +Completion (cmdliner.Cmdliner.Arg.Completion)

Module Arg.Completion

Argument completion.

This module provides a type to describe how positional and optional argument values of argument converters can be completed. It defines which completion directives from the protocol get emitted by your tool for the argument.

Note. Subcommand and option name are completed automatically by the library itself and prefined argument converters already have completions built-in whenever appropriate.

Completion directives

type 'a directive

The type for a completion directive for values of type 'a.

val value : ?doc:string -> 'a -> 'a directive

value v ~doc indicates that the token to complete could be replaced by the value v as serialized by the argument's formatter Conv.pp. doc is ANSI styled UTF-8 text documenting the value, defaults to "".

val string : ?doc:string -> string -> 'a directive

string s ~doc indicates that the token to complete could be replaced by the string s. doc is ANSI styled UTF-8 text documenting the value, defaults to "".

val files : 'a directive

files indicates that the token to complete could be replaced with files that the shell deems suitable.

val dirs : 'a directive

dirs indicates that the token to complete could be replaced with directories that the shell deems suitable.

val restart : 'a directive

restart indicates that the shell should restart the completion after the positional disambiguation token --.

This is typically used for tools that end-up invoking other tools like sudo -- TOOL [ARG]…. For the latter a restart completion should be added on all positional arguments. If you allow TOOL to be only a restricted set of tools known to your program you'd eschew restart on the first postional argument but add it to the remaining ones.

Warning. A restart directive is eventually emited only if the completion is requested after a -- token. In this case other completions returned alongside by func are ignored. Educate your users to use the --, for example mention them in user defined synopses, it is good cli specification hygiene as it properly delineates argument scopes.

val message : string -> 'a directive

message s is a multi-line, ANSI styled, UTF-8 message reported to end users.

val raw : string -> 'a directive

raw s takes over the whole protocol output (including subcommand and option name completion) with s, you are in charge. Any other directive in the result of func is ignored.

Warning. The protocol is unstable, it is not advised to output it yourself. However this can be useful to invoke another tool according to the protocol in the completion function and treat its result as the requested completion.

Completion

type ('ctx, 'a) func = + 'ctx option -> + token:string -> + ('a directive list, string) result

The type for completion functions.

Given an optional context determined from a partial command line parse and a token to complete it returns a list of completion directives or an error which is reported to end-users by using a protocol message.

The context is None if no context was given to make or if the context failed to parse on the current command line.

type 'a complete =
  1. | Complete : 'ctx Term.t option * ('ctx, 'a) func -> 'a complete

The type for completing.

A completion context specification which captures a partial command line parse (for example the path to a configuration file) and a completion function.

type 'a t

The type for completing values parsed into values of type 'a.

val make : ?context:'ctx Term.t -> ('ctx, 'a) func -> 'a t

make ~context func uses func to complete.

context defines a commmand line fragment that is evaluated before performing the completion. It the evaluation is successful the result is given to the completion function. Otherwise None is given.

Warning. context must be part of the term of the command in which you use the completion otherwise the context will always be None in the function.

val complete : 'a t -> 'a complete

complete c completes with c.

val complete_files : 'a t

complete_files holds a context insensitive function that always returns Ok [files].

val complete_dirs : 'a t

complete_dirs holds a context insensitive function that always returns Ok [dirs].

val complete_paths : 'a t

complete_paths holds a context insensitive function that always returns Ok [files;dirs].

val complete_restart : 'a t

complete_dirs holds a context insensitive function that always returns Ok [restart].

diff --git a/cmdliner/Cmdliner/Arg/Conv/index.html b/cmdliner/Cmdliner/Arg/Conv/index.html new file mode 100644 index 00000000..899873ee --- /dev/null +++ b/cmdliner/Cmdliner/Arg/Conv/index.html @@ -0,0 +1,14 @@ + +Conv (cmdliner.Cmdliner.Arg.Conv)

Module Arg.Conv

Argument converters.

An argument converter transforms a string argument of the command line to an OCaml value. Predefined converters are provided for many types of the standard library.

Converters

type 'a parser = string -> ('a, string) result

The type for parsing arguments to values of type 'a.

type 'a fmt = Stdlib.Format.formatter -> 'a -> unit

The type for formatting values of type 'a.

type 'a t

The type for converting arguments to values of type 'a.

val make : + ?completion:'a Completion.t -> + docv:string -> + parser:'a parser -> + pp:'a fmt -> + unit -> + 'a t

make ~docv ~parser ~pp () is an argument converter with given properties. See corresponding accessors for semantics.

val of_conv : + ?completion:'a Completion.t -> + ?docv:string -> + ?parser:'a parser -> + ?pp:'a fmt -> + 'a t -> + 'a t

of_conv conv () is a new converter with given unspecified properties defaulting to those of conv.

Properties

val docv : 'a t -> string

docv c is c's documentation meta-variable. This value can be refered to as $(docv) in the documentation strings of arguments. It can be overriden by the info value of an argument.

val parser : 'a t -> 'a parser

parser c is c's argument parser.

val pp : 'a t -> 'a fmt

pp c is c's argument formatter.

val completion : 'a t -> 'a Completion.t

completion c is c's completion.

diff --git a/cmdliner/Cmdliner/Arg/index.html b/cmdliner/Cmdliner/Arg/index.html index 41b041d4..eea4761e 100644 --- a/cmdliner/Cmdliner/Arg/index.html +++ b/cmdliner/Cmdliner/Arg/index.html @@ -1,31 +1,24 @@ -Arg (cmdliner.Cmdliner.Arg)

Module Cmdliner.Arg

Terms for command line arguments.

This module provides functions to define terms that evaluate to the arguments provided on the command line.

Basic constraints, like the argument type or repeatability, are specified by defining a value of type Arg.t. Further constraints can be specified during the conversion to a term.

Argument converters

An argument converter transforms a string argument of the command line to an OCaml value. Predefined converters are provided for many types of the standard library.

type 'a parser = string -> [ `Ok of 'a | `Error of string ]

The type for argument parsers.

Deprecated. Use parser signatures of conv or conv'.

  • deprecated Use Arg.conv or Arg.conv' instead.
type 'a printer = Stdlib.Format.formatter -> 'a -> unit

The type for converted argument printers.

type 'a conv = 'a parser * 'a printer

The type for argument converters.

Warning. Do not use directly, use conv or conv'. This type will become abstract in the next major version of cmdliner.

val conv : - ?docv:string -> - ((string -> ('a, [ `Msg of string ]) result) * 'a printer) -> - 'a conv

conv ~docv (parse, print) is an argument converter parsing values with parse and printing them with print. docv is a documentation meta-variable used in the documentation to stand for the argument value, defaults to "VALUE".

val conv' : - ?docv:string -> - ((string -> ('a, string) result) * 'a printer) -> - 'a conv

conv' is like conv but the Error case has an unlabelled string.

val conv_parser : 'a conv -> string -> ('a, [ `Msg of string ]) result

conv_parser c is the parser of c.

val conv_printer : 'a conv -> 'a printer

conv_printer c is the printer of c.

val conv_docv : 'a conv -> string

conv_docv c is c's documentation meta-variable.

Warning. Currently always returns "VALUE" in the future will return the value given to conv or conv'.

val parser_of_kind_of_string : - kind:string -> - (string -> 'a option) -> - string -> - ('a, [ `Msg of string ]) result

parser_of_kind_of_string ~kind kind_of_string is an argument parser using the kind_of_string function for parsing and kind to report errors (e.g. could be "an integer" for an int parser.).

val some' : ?none:'a -> 'a conv -> 'a option conv

some' ?none c is like the converter c except it returns Some value. It is used for command line arguments that default to None when absent. If provided, none is used with conv's printer to document the value taken on absence; to document a more complex behaviour use the absent argument of info.

val some : ?none:string -> 'a conv -> 'a option conv

some ?none c is like some' but none is described as a string that will be rendered in bold.

Arguments and their information

Argument information defines the man page information of an argument and, for optional arguments, its names. An environment variable can also be specified to read the argument value from if the argument is absent from the command line and the variable is defined.

type 'a t

The type for arguments holding data of type 'a.

type info

The type for information about command line arguments.

val info : +Arg (cmdliner.Cmdliner.Arg)

Module Cmdliner.Arg

Terms for command line arguments.

This module provides functions to define terms that evaluate to the arguments provided on the command line.

Basic constraints, like the argument type or repeatability, are specified by defining a value of type Arg.t. Further constraints can be specified during the conversion to a term.

Argument converters

module Completion : sig ... end

Argument completion.

module Conv : sig ... end

Argument converters.

type 'a conv = 'a Conv.t

The type for argument converters. See the predefined converters.

val some' : ?none:'a -> 'a conv -> 'a option conv

some' ?none c is like the converter c except it returns Some value. It is used for command line arguments that default to None when absent. If provided, none is used with c's formatter to document the value taken on absence; to document a more complex behaviour use the absent argument of info. If you cannot construct an 'a value use some.

val some : ?none:string -> 'a conv -> 'a option conv

some ?none c is like some' but none is described as a string that will be rendered in bold. Use the absent argument of info to document more complex behaviours.

Arguments

type 'a t

The type for arguments holding data of type 'a.

type info

The type for information about command line arguments.

Argument information defines the man page information of an argument and, for optional arguments, its names. An environment variable can also be specified to read get the argument value from if the argument is absent from the command line and the variable is defined.

val info : ?deprecated:string -> ?absent:string -> - ?docs:string -> + ?docs:Manpage.section_name -> + ?doc_envs:Cmd.Env.info list -> ?docv:string -> ?doc:string -> ?env:Cmd.Env.info -> string list -> - info

info docs docv doc env names defines information for an argument.

  • names defines the names under which an optional argument can be referred to. Strings of length 1 ("c") define short option names ("-c"), longer strings ("count") define long option names ("--count"). names must be empty for positional arguments.
  • env defines the name of an environment variable which is looked up for defining the argument if it is absent from the command line. See environment variables for details.
  • doc is the man page information of the argument. The documentation language can be used and the following variables are recognized:

    • "$(docv)" the value of docv (see below).
    • "$(opt)", one of the options of names, preference is given to a long one.
    • "$(env)", the environment var specified by env (if any).

    These functions can help with formatting argument values.

  • docv is for positional and non-flag optional arguments. It is a variable name used in the man page to stand for their value.
  • docs is the title of the man page section in which the argument will be listed. For optional arguments this defaults to Manpage.s_options. For positional arguments this defaults to Manpage.s_arguments. However a positional argument is only listed if it has both a doc and docv specified.
  • deprecated, if specified the argument is deprecated and the string is a message output on standard error when the argument is used.
  • absent, if specified a documentation string that indicates what happens when the argument is absent. The document language can be used like in doc. This overrides the automatic default value rendering that is performed by the combinators.
val (&) : ('a -> 'b) -> 'a -> 'b

f & v is f v, a right associative composition operator for specifying argument terms.

Optional arguments

The information of an optional argument must have at least one name or Invalid_argument is raised.

val flag : info -> bool t

flag i is a bool argument defined by an optional flag that may appear at most once on the command line under one of the names specified by i. The argument holds true if the flag is present on the command line and false otherwise.

val flag_all : info -> bool list t

flag_all is like flag except the flag may appear more than once. The argument holds a list that contains one true value per occurrence of the flag. It holds the empty list if the flag is absent from the command line.

val vflag : 'a -> ('a * info) list -> 'a t

vflag v [v0,i0;…] is an 'a argument defined by an optional flag that may appear at most once on the command line under one of the names specified in the ik values. The argument holds v if the flag is absent from the command line and the value vk if the name under which it appears is in ik.

Note. Environment variable lookup is unsupported for for these arguments.

val vflag_all : 'a list -> ('a * info) list -> 'a list t

vflag_all v l is like vflag except the flag may appear more than once. The argument holds the list v if the flag is absent from the command line. Otherwise it holds a list that contains one corresponding value per occurrence of the flag, in the order found on the command line.

Note. Environment variable lookup is unsupported for for these arguments.

val opt : ?vopt:'a -> 'a conv -> 'a -> info -> 'a t

opt vopt c v i is an 'a argument defined by the value of an optional argument that may appear at most once on the command line under one of the names specified by i. The argument holds v if the option is absent from the command line. Otherwise it has the value of the option as converted by c.

If vopt is provided the value of the optional argument is itself optional, taking the value vopt if unspecified on the command line.

val opt_all : ?vopt:'a -> 'a conv -> 'a list -> info -> 'a list t

opt_all vopt c v i is like opt except the optional argument may appear more than once. The argument holds a list that contains one value per occurrence of the flag in the order found on the command line. It holds the list v if the flag is absent from the command line.

Positional arguments

The information of a positional argument must have no name or Invalid_argument is raised. Positional arguments indexing is zero-based.

Warning. The following combinators allow to specify and extract a given positional argument with more than one term. This should not be done as it will likely confuse end users and documentation generation. These over-specifications may be prevented by raising Invalid_argument in the future. But for now it is the client's duty to make sure this doesn't happen.

val pos : ?rev:bool -> int -> 'a conv -> 'a -> info -> 'a t

pos rev n c v i is an 'a argument defined by the nth positional argument of the command line as converted by c. If the positional argument is absent from the command line the argument is v.

If rev is true (defaults to false), the computed position is max-n where max is the position of the last positional argument present on the command line.

val pos_all : 'a conv -> 'a list -> info -> 'a list t

pos_all c v i is an 'a list argument that holds all the positional arguments of the command line as converted by c or v if there are none.

val pos_left : ?rev:bool -> int -> 'a conv -> 'a list -> info -> 'a list t

pos_left rev n c v i is an 'a list argument that holds all the positional arguments as converted by c found on the left of the nth positional argument or v if there are none.

If rev is true (defaults to false), the computed position is max-n where max is the position of the last positional argument present on the command line.

val pos_right : ?rev:bool -> int -> 'a conv -> 'a list -> info -> 'a list t

pos_right is like pos_left except it holds all the positional arguments found on the right of the specified positional argument.

Arguments as terms

val value : 'a t -> 'a Term.t

value a is a term that evaluates to a's value.

val required : 'a option t -> 'a Term.t

required a is a term that fails if a's value is None and evaluates to the value of Some otherwise. Use this for required positional arguments (it can also be used for defining required optional arguments, but from a user interface perspective this shouldn't be done, it is a contradiction in terms).

val non_empty : 'a list t -> 'a list Term.t

non_empty a is term that fails if a's list is empty and evaluates to a's list otherwise. Use this for non empty lists of positional arguments.

val last : 'a list t -> 'a Term.t

last a is a term that fails if a's list is empty and evaluates to the value of the last element of the list otherwise. Use this for lists of flags or options where the last occurrence takes precedence over the others.

Predefined arguments

val man_format : Manpage.format Term.t

man_format is a term that defines a --man-format option and evaluates to a value that can be used with Manpage.print.

Predefined converters

val bool : bool conv

bool converts values with bool_of_string.

val char : char conv

char converts values by ensuring the argument has a single char.

val int : int conv

int converts values with int_of_string.

val nativeint : nativeint conv

nativeint converts values with Nativeint.of_string.

val int32 : int32 conv

int32 converts values with Int32.of_string.

val int64 : int64 conv

int64 converts values with Int64.of_string.

val float : float conv

float converts values with float_of_string.

val string : string conv

string converts values with the identity function.

val enum : (string * 'a) list -> 'a conv

enum l p converts values such that unambiguous prefixes of string names in l map to the corresponding value of type 'a.

Warning. The type 'a must be comparable with Stdlib.compare.

  • raises Invalid_argument

    if l is empty.

val file : string conv

file converts a value with the identity function and checks with Sys.file_exists that a file with that name exists.

val dir : string conv

dir converts a value with the identity function and checks with Sys.file_exists and Sys.is_directory that a directory with that name exists.

val non_dir_file : string conv

non_dir_file converts a value with the identity function and checks with Sys.file_exists and Sys.is_directory that a non directory file with that name exists.

val list : ?sep:char -> 'a conv -> 'a list conv

list sep c splits the argument at each sep (defaults to ',') character and converts each substrings with c.

val array : ?sep:char -> 'a conv -> 'a array conv

array sep c splits the argument at each sep (defaults to ',') character and converts each substring with c.

val pair : ?sep:char -> 'a conv -> 'b conv -> ('a * 'b) conv

pair sep c0 c1 splits the argument at the first sep character (defaults to ',') and respectively converts the substrings with c0 and c1.

val t2 : ?sep:char -> 'a conv -> 'b conv -> ('a * 'b) conv

t2 is pair.

val t3 : ?sep:char -> 'a conv -> 'b conv -> 'c conv -> ('a * 'b * 'c) conv

t3 sep c0 c1 c2 splits the argument at the first two sep characters (defaults to ',') and respectively converts the substrings with c0, c1 and c2.

val t4 : + info

info docs docv doc env names defines information for an argument.

  • names defines the names under which an optional argument can be referred to. Strings of length 1 like "c") define short option names "-c", longer strings like "count") define long option names "--count". names must be empty for positional arguments.
  • env defines the name of an environment variable which is looked up for defining the argument if it is absent from the command line. See environment variables for details.
  • doc is the man page information of the argument. These functions can help with formatting argument values.
  • docv is for positional and non-flag optional arguments. It is a variable name used in the man page to stand for their value. If unspecified is taken from the argument converter's, see Conv.docv.
  • doc_envs is a list of environment variable that are added to the manual of the command when the argument is used.
  • docs is the title of the man page section in which the argument will be listed. For optional arguments this defaults to Manpage.s_options. For positional arguments this defaults to Manpage.s_arguments. However a positional argument is only listed if it has both a doc and docv specified.
  • deprecated, if specified the argument is deprecated. Use of the variable warns on stderr. This message which should be a capitalized sentence is preprended to doc and output on standard error when the environment variable ends up being used.
  • absent, if specified a documentation string that indicates what happens when the argument is absent. The document language can be used like in doc. This overrides the automatic default value rendering that is performed by the combinators.

In doc, deprecated, absent the documentation markup language can be used with following variables:

  • "$(docv)" the value of docv (see below).
  • "$(opt)", one of the options of names, preference is given to a long one.
  • "$(env)", the environment var specified by env (if any).
val (&) : ('a -> 'b) -> 'a -> 'b

f & v is f v, a right associative composition operator for specifying argument terms.

Optional arguments

The information of an optional argument must have at least one name or Invalid_argument is raised.

val flag : info -> bool t

flag i is a bool argument defined by an optional flag that may appear at most once on the command line under one of the names specified by i. The argument holds true if the flag is present on the command line and false otherwise.

val flag_all : info -> bool list t

flag_all is like flag except the flag may appear more than once. The argument holds a list that contains one true value per occurrence of the flag. It holds the empty list if the flag is absent from the command line.

val vflag : 'a -> ('a * info) list -> 'a t

vflag v [v0,i0;…] is an 'a argument defined by an optional flag that may appear at most once on the command line under one of the names specified in the ik values. The argument holds v if the flag is absent from the command line and the value vk if the name under which it appears is in ik.

Note. Automatic environment variable lookup is unsupported for for these arguments but an env in an info will be documented. Use an option and Term.env for manually looking something up.

val vflag_all : 'a list -> ('a * info) list -> 'a list t

vflag_all v l is like vflag except the flag may appear more than once. The argument holds the list v if the flag is absent from the command line. Otherwise it holds a list that contains one corresponding value per occurrence of the flag, in the order found on the command line.

Note. Automatic environment variable lookup is unsupported for for these arguments but an env in an info will be documented. Use an option and Term.env for manually looking something up.

val opt : ?vopt:'a -> 'a conv -> 'a -> info -> 'a t

opt vopt c v i is an 'a argument defined by the value of an optional argument that may appear at most once on the command line under one of the names specified by i. The argument holds v if the option is absent from the command line. Otherwise it has the value of the option as converted by c.

If vopt is provided the value of the optional argument is itself optional, taking the value vopt if unspecified on the command line. Warning using vopt is not recommended.

val opt_all : ?vopt:'a -> 'a conv -> 'a list -> info -> 'a list t

opt_all vopt c v i is like opt except the optional argument may appear more than once. The argument holds a list that contains one value per occurrence of the flag in the order found on the command line. It holds the list v if the flag is absent from the command line.

Positional arguments

The information of a positional argument must have no name or Invalid_argument is raised. Positional arguments indexing is zero-based.

Warning. The following combinators allow to specify and extract a given positional argument with more than one term. This should not be done as it will likely confuse end users and documentation generation. These over-specifications may be prevented by raising Invalid_argument in the future. But for now it is the client's duty to make sure this doesn't happen.

val pos : ?rev:bool -> int -> 'a conv -> 'a -> info -> 'a t

pos rev n c v i is an 'a argument defined by the nth positional argument of the command line as converted by c. If the positional argument is absent from the command line the argument is v.

If rev is true (defaults to false), the computed position is max-n where max is the position of the last positional argument present on the command line.

val pos_all : 'a conv -> 'a list -> info -> 'a list t

pos_all c v i is an 'a list argument that holds all the positional arguments of the command line as converted by c or v if there are none.

val pos_left : ?rev:bool -> int -> 'a conv -> 'a list -> info -> 'a list t

pos_left rev n c v i is an 'a list argument that holds all the positional arguments as converted by c found on the left of the nth positional argument or v if there are none.

If rev is true (defaults to false), the computed position is max-n where max is the position of the last positional argument present on the command line.

val pos_right : ?rev:bool -> int -> 'a conv -> 'a list -> info -> 'a list t

pos_right is like pos_left except it holds all the positional arguments found on the right of the specified positional argument.

Converting to terms

val value : 'a t -> 'a Term.t

value a is a term that evaluates to a's value.

val required : 'a option t -> 'a Term.t

required a is a term that fails if a's value is None and evaluates to the value of Some otherwise. Use this in combination with Arg.some' for required positional arguments. Warning using this on optional arguments is not recommended.

val non_empty : 'a list t -> 'a list Term.t

non_empty a is term that fails if a's list is empty and evaluates to a's list otherwise. Use this for non empty lists of positional arguments.

val last : 'a list t -> 'a Term.t

last a is a term that fails if a's list is empty and evaluates to the value of the last element of the list otherwise. Use this for lists of flags or options where the last occurrence takes precedence over the others.

Predefined arguments

val man_format : Manpage.format Term.t

man_format is a term that defines a --man-format option and evaluates to a value that can be used with Manpage.print.

Predefined converters

val bool : bool conv

bool converts values with bool_of_string.

val char : char conv

char converts values by ensuring the argument has a single char.

val int : int conv

int converts values with int_of_string.

val nativeint : nativeint conv

nativeint converts values with Nativeint.of_string.

val int32 : int32 conv

int32 converts values with Int32.of_string.

val int64 : int64 conv

int64 converts values with Int64.of_string.

val float : float conv

float converts values with float_of_string.

val string : string conv

string converts values with the identity function.

val enum : ?docv:string -> (string * 'a) list -> 'a conv

enum l p converts values such that string names in l map to the corresponding value of type 'a. docv is the converter's documentation meta-variable, it defaults to ENUM. A completion is added for the names.

Warning. The type 'a must be comparable with Stdlib.compare.

  • raises Invalid_argument

    if l is empty.

val list : ?sep:char -> 'a conv -> 'a list conv

list sep c splits the argument at each sep (defaults to ',') character and converts each substrings with c.

val array : ?sep:char -> 'a conv -> 'a array conv

array sep c splits the argument at each sep (defaults to ',') character and converts each substring with c.

val pair : ?sep:char -> 'a conv -> 'b conv -> ('a * 'b) conv

pair sep c0 c1 splits the argument at the first sep character (defaults to ',') and respectively converts the substrings with c0 and c1.

val t2 : ?sep:char -> 'a conv -> 'b conv -> ('a * 'b) conv

t2 is pair.

val t3 : ?sep:char -> 'a conv -> 'b conv -> 'c conv -> ('a * 'b * 'c) conv

t3 sep c0 c1 c2 splits the argument at the first two sep characters (defaults to ',') and respectively converts the substrings with c0, c1 and c2.

val t4 : ?sep:char -> 'a conv -> 'b conv -> 'c conv -> 'd conv -> - ('a * 'b * 'c * 'd) conv

t4 sep c0 c1 c2 c3 splits the argument at the first three sep characters (defaults to ',') respectively converts the substrings with c0, c1, c2 and c3.

Documentation formatting helpers

val doc_quote : string -> string

doc_quote s quotes the string s.

val doc_alts : ?quoted:bool -> string list -> string

doc_alts alts documents the alternative tokens alts according the number of alternatives. If quoted is:

  • None, the tokens are enclosed in manpage markup directives to render them in bold (manpage convention).
  • Some true, the tokens are quoted with doc_quote.
  • Some false, the tokens are written as is

The resulting string can be used in sentences of the form "$(docv) must be %s".

  • raises Invalid_argument

    if alts is the empty list.

val doc_alts_enum : ?quoted:bool -> (string * 'a) list -> string

doc_alts_enum quoted alts is doc_alts quoted (List.map fst alts).

Deprecated

type 'a converter = 'a conv

See Arg.conv'.

  • deprecated Use Arg.conv' function instead.
val pconv : ?docv:string -> ('a parser * 'a printer) -> 'a conv

pconv is like conv or conv', but uses a deprecated parser signature.

  • deprecated Use Arg.conv or Arg.conv' function instead.
type env = Cmd.Env.info

See Cmd.Env.info

  • deprecated Use Cmd.Env.info instead.
val env_var : - ?deprecated:string -> - ?docs:string -> - ?doc:string -> - Cmd.Env.var -> - Cmd.Env.info

See Cmd.Env.info.

  • deprecated Use Cmd.Env.info instead.
+ ('a * 'b * 'c * 'd) conv

t4 sep c0 c1 c2 c3 splits the argument at the first three sep characters (defaults to ',') respectively converts the substrings with c0, c1, c2 and c3.

Files and directories

val path : string conv

path is like string but prints using Filename.quote and completes both files and directories.

val filepath : string conv

filepath is like string but prints using Filename.quote and completes files.

val dirpath : string conv

dirpath is like string but prints using Filename.quote and completes directories.

Note. The following converters report errors whenever the requested file system object does not exist. This is only mildly useful since nothing guarantees they will still exist at the time you act upon them. So you will have to treat these error cases anyways in your tool function. It is also unhelpful if the file system object may be created by your tool. Rather use filepath and dirpath.

val file : string conv

file converts a value with the identity function and checks with Sys.file_exists that a file with that name exists. The string "-" is parsed without checking: it represents stdio. It completes both files directories.

val dir : string conv

dir converts a value with the identity function and checks with Sys.file_exists and Sys.is_directory that a directory with that name exists. It completes directories.

val non_dir_file : string conv

non_dir_file converts a value with the identity function and checks with Sys.file_exists and Sys.is_directory that a non directory file with that name exists. The string "-" is parsed without checking it represents stdio. It completes files.

Documentation formatting helpers

val doc_quote : string -> string

doc_quote s quotes the string s.

val doc_alts : ?quoted:bool -> string list -> string

doc_alts alts documents the alternative tokens alts according the number of alternatives. If quoted is:

  • None, the tokens are enclosed in manpage markup directives to render them in bold (manpage convention).
  • Some true, the tokens are quoted with doc_quote.
  • Some false, the tokens are written as is

The resulting string can be used in sentences of the form "$(docv) must be %s".

  • raises Invalid_argument

    if alts is the empty list.

val doc_alts_enum : ?quoted:bool -> (string * 'a) list -> string

doc_alts_enum quoted alts is doc_alts quoted (List.map fst alts).

Deprecated

These identifiers are silently deprecated. For now there is no plan to remove them. But you should prefer to use the Conv interface in new code.

type 'a printer = 'a Conv.fmt

Deprecated. Use Conv.fmt.

val conv' : ?docv:string -> ('a Conv.parser * 'a Conv.fmt) -> 'a conv

Deprecated. Use Conv.make instead.

val conv : + ?docv:string -> + ((string -> ('a, [ `Msg of string ]) result) * 'a Conv.fmt) -> + 'a conv

Deprecated. Use Conv.make instead.

val conv_parser : 'a conv -> string -> ('a, [ `Msg of string ]) result

Deprecated. Use Conv.parser.

val conv_printer : 'a conv -> 'a Conv.fmt

Deprecated. Use Conv.pp.

val conv_docv : 'a conv -> string

Deprecated. Use Conv.docv.

val parser_of_kind_of_string : + kind:string -> + (string -> 'a option) -> + string -> + ('a, [ `Msg of string ]) result

Deprecated. parser_of_kind_of_string ~kind kind_of_string is an argument parser using the kind_of_string function for parsing and kind to report errors (e.g. could be "an integer" for an int parser.).

diff --git a/cmdliner/Cmdliner/Cmd/Env/index.html b/cmdliner/Cmdliner/Cmd/Env/index.html index 82e91229..ba30d301 100644 --- a/cmdliner/Cmdliner/Cmd/Env/index.html +++ b/cmdliner/Cmdliner/Cmd/Env/index.html @@ -1,2 +1,7 @@ -Env (cmdliner.Cmdliner.Cmd.Env)

Module Cmd.Env

Environment variable and their information.

Environment variables

type var = string

The type for environment names.

Environment variable information

type info = Term.env_info

The type for environment variable information.

val info : ?deprecated:string -> ?docs:string -> ?doc:string -> var -> info

info ~docs ~doc var describes an environment variable var such that:

  • doc is the man page information of the environment variable, defaults to "undocumented".
  • docs is the title of the man page section in which the environment variable will be listed, it defaults to Cmdliner.Manpage.s_environment.
  • deprecated, if specified the environment is deprecated and the string is a message output on standard error when the environment variable gets used to lookup the default value of an argument.

In doc the documentation markup language can be used with following variables:

  • $(env), the value of var.
  • The variables mentioned in info.
+Env (cmdliner.Cmdliner.Cmd.Env)

Module Cmd.Env

Environment variable and their information.

Environment variables

type var = string

The type for environment variable names.

Environment variable information

type info

The type for environment variable information.

val info : + ?deprecated:string -> + ?docs:Manpage.section_name -> + ?doc:string -> + var -> + info

info ~docs ~doc var describes an environment variable var such that:

  • doc is the man page information of the environment variable, defaults to "See option $(opt).".
  • docs is the title of the man page section in which the environment variable will be listed, it defaults to Cmdliner.Manpage.s_environment.
  • deprecated, if specified the environment variable is deprecated. Use of the variable warns on depstderr This message which should be a capitalized sentence is preprended to doc and output on standard error when the environment variable ends up being used.

In doc and deprecated the documentation markup language can be used with following variables:

  • $(opt), if any the option name of the argument the variable is looked up for.
  • $(env), the value of var.
  • The variables mentioned in the doc string of Cmd.info.
val info_var : info -> var

info_var info is the variable described by info.

diff --git a/cmdliner/Cmdliner/Cmd/Exit/index.html b/cmdliner/Cmdliner/Cmd/Exit/index.html index b09df638..55eaeb02 100644 --- a/cmdliner/Cmdliner/Cmd/Exit/index.html +++ b/cmdliner/Cmdliner/Cmd/Exit/index.html @@ -1,2 +1,7 @@ -Exit (cmdliner.Cmdliner.Cmd.Exit)

Module Cmd.Exit

Exit codes and their information.

Exit codes

type code = int

The type for exit codes.

Warning. You should avoid status codes strictly greater than 125 as those may be used by some shells.

val ok : code

ok is 0, the exit status for success.

val some_error : code

some_error is 123, an exit status for indisciminate errors reported on stderr.

val cli_error : code

cli_error is 124, an exit status for command line parsing errors.

val internal_error : code

internal_error is 125, an exit status for unexpected internal errors.

Exit code information

type info

The type for exit code information.

val info : ?docs:string -> ?doc:string -> ?max:code -> code -> info

exit_info ~docs ~doc min ~max describe the range of exit statuses from min to max (defaults to min). doc is the man page information for the statuses, defaults to "undocumented". docs is the title of the man page section in which the statuses will be listed, it defaults to Manpage.s_exit_status.

In doc the documentation markup language can be used with following variables:

  • $(status), the value of min.
  • $(status_max), the value of max.
  • The variables mentioned in the Cmd.info
val info_code : info -> code

info_code i is the minimal code of i.

val defaults : info list

defaults are exit code information for ok, some_error cli_error and internal_error.

+Exit (cmdliner.Cmdliner.Cmd.Exit)

Module Cmd.Exit

Exit codes and their information.

Exit codes

type code = int

The type for exit codes.

Warning. You should avoid status codes strictly greater than 125 as those may be used by some shells.

Predefined codes

These are documented by defaults.

val ok : code

ok is 0, the exit status for success.

val some_error : code

some_error is 123, an exit status for indiscriminate errors reported on stderr.

val cli_error : code

cli_error is 124, an exit status for command line parsing errors.

val internal_error : code

internal_error is 125, an exit status for unexpected internal errors.

Exit code information

type info

The type for exit code information.

val info : + ?docs:Manpage.section_name -> + ?doc:string -> + ?max:code -> + code -> + info

info ~docs ~doc min ~max describe the range of exit statuses from min to max (defaults to min).

  • doc is the man page information for the statuses, defaults to "undocumented". The documentation markup language can be used with following variables:

    • $(status), the value of min.
    • $(status_max), the value of max.
    • The variables mentioned in the documentation of Cmd.info
  • docs is the title of the man page section in which the statuses will be listed, it defaults to Manpage.s_exit_status.
val info_code : info -> code

info_code i is the minimal code of i.

val defaults : info list

defaults are exit code information for ok, some_error, cli_error and internal_error.

diff --git a/cmdliner/Cmdliner/Cmd/index.html b/cmdliner/Cmdliner/Cmd/index.html index 49d993ea..86797374 100644 --- a/cmdliner/Cmdliner/Cmd/index.html +++ b/cmdliner/Cmdliner/Cmd/index.html @@ -1,16 +1,16 @@ -Cmd (cmdliner.Cmdliner.Cmd)

Module Cmdliner.Cmd

Commands.

Command line syntaxes are implicitely defined by Terms. A command value binds a syntax and its documentation to a command name.

A command can group a list of sub commands (and recursively). In this case your tool defines a tree of commands, each with its own command line syntax. The root of that tree is called the main command; it represents your tool and its name.

Command information

Command information defines the name and documentation of a command.

module Exit : sig ... end

Exit codes and their information.

module Env : sig ... end

Environment variable and their information.

type info

The type for information about commands.

val info : +Cmd (cmdliner.Cmdliner.Cmd)

Module Cmdliner.Cmd

Commands.

Command line syntaxes are implicitely defined by Term.t values. A command value binds a term and its documentation to a command name.

A command can group a list of subcommands (and recursively). In this case your tool defines a tree of commands, each with its own command line syntax. The root of that tree is called the main command; it represents your tool and its name.

Command information

Command information defines the name and documentation of a command.

module Exit : sig ... end

Exit codes and their information.

module Env : sig ... end

Environment variable and their information.

type info

The type for information about commands.

val info : ?deprecated:string -> ?man_xrefs:Manpage.xref list -> ?man:Manpage.block list -> ?envs:Env.info list -> ?exits:Exit.info list -> - ?sdocs:string -> - ?docs:string -> + ?sdocs:Manpage.section_name -> + ?docs:Manpage.section_name -> ?doc:string -> ?version:string -> string -> - info

info ?sdocs ?man ?docs ?doc ?version name is a term information such that:

  • name is the name of the command.
  • version is the version string of the command line tool, this is only relevant for the main command and ignored otherwise.
  • deprecated, if specified the command is deprecated and the string is a message output on standard error when the command is used.
  • doc is a one line description of the command used for the NAME section of the command's man page and in command group listings.
  • docs, for commands that are part of a group, the title of the section of the parent's command man page where it should be listed (defaults to Manpage.s_commands).
  • sdocs defines the title of the section in which the standard --help and --version arguments are listed (defaults to Manpage.s_common_options).
  • exits is a list of exit statuses that the command evaluation may produce, defaults to Exit.defaults.
  • envs is a list of environment variables that influence the command's evaluation.
  • man is the text of the man page for the command.
  • man_xrefs are cross-references to other manual pages. These are used to generate a Manpage.s_see_also section.

doc, man, envs support the documentation markup language in which the following variables are recognized:

  • $(tname) the (term's) command's name.
  • $(mname) the main command name.
  • $(iname) the command invocation from main command to the command name.

Commands

type 'a t

The type for commands whose evaluation result in a value of type 'a.

val v : info -> 'a Term.t -> 'a t

v i t is a command with information i and command line syntax parsed by t.

val group : ?default:'a Term.t -> info -> 'a t list -> 'a t

group i ?default cmds is a command with information i that groups sub commands cmds. default is the command line syntax to parse if no sub command is specified on the command line. If default is None (default), the tool errors when no sub command is specified.

val name : 'a t -> string

name c is the name of c.

Evaluation

These functions are meant to be composed with Stdlib.exit. The following exit codes may be returned by all these functions:

These exit codes are described in Exit.defaults which is the default value of the ?exits argument of function info.

val eval : + info

info ?sdocs ?man ?docs ?doc ?version name is a term information such that:

  • name is the name of the command.
  • version is the version string of the command line tool, this is only relevant for the main command and ignored otherwise.
  • deprecated, if specified the command is deprecated. Use of the variable warns on stderr. This message which should be a capitalized sentence is preprended to doc and output on standard error when the environment variable ends up being used.
  • doc is a one line description of the command used for the NAME section of the command's man page and in command group listings.
  • docs, for commands that are part of a group, the title of the section of the parent's command man page where it should be listed (defaults to Manpage.s_commands).
  • sdocs defines the title of the section in which the standard --help and --version arguments are listed (defaults to Manpage.s_common_options).
  • exits is a list of exit statuses that the command evaluation may produce, defaults to Exit.defaults.
  • envs is a list of environment variables that influence the command's evaluation.
  • man is the text of the man page for the command.
  • man_xrefs are cross-references to other manual pages. These are used to generate a Manpage.s_see_also section.

doc, deprecated, man, envs, exits support the documentation markup language in which the following variables are recognized:

  • $(tool) the main, topmost, command name.
  • $(cmd) the command invocation from main command to the command name.
  • $(cmd.name) the command's name.
  • $(cmd.parent) the command's parent or the main command if none.

Previously some of these names were refered to as $(tname), $(mname) and $(iname), they still work but do not use them, they are obscure.

Commands

type 'a t

The type for commands whose evaluation result in a value of type 'a.

val make : info -> 'a Term.t -> 'a t

make i t is a command with information i and command line syntax parsed by t.

val v : info -> 'a Term.t -> 'a t

v is an old name for make which should be preferred.

val group : ?default:'a Term.t -> info -> 'a t list -> 'a t

group i ?default cmds is a command with information i that groups subcommands cmds. default is the command line syntax to parse if no subcommand is specified on the command line. If default is None (default), the tool errors when no subcommand is specified.

val name : 'a t -> string

name c is the name of c.

Evaluation

Read Which Cmd evaluation function should I use? in the cookbook if you struggle to choose between this menagerie of evaluation functions.

These functions are meant to be composed with Stdlib.exit. The following exit codes may be returned by all these functions:

These exit codes are described in Exit.defaults which is the default value of the ?exits argument of the function info.

val eval : ?help:Stdlib.Format.formatter -> ?err:Stdlib.Format.formatter -> ?catch:bool -> @@ -42,14 +42,14 @@ ?argv:string array -> ?term_err:Exit.code -> (Exit.code, string) result t -> - Exit.code

eval_result' cmd is:

  • c if cmd evaluates to Ok c.
  • Exit.some_error if cmd evaluates to Error msg. In this case msg is printed on err.

See eval_value for other arguments.

Low level evaluation

This interface gives more information on command evaluation results and lets you choose how to map evaluation results to exit codes.

type 'a eval_ok = [
  1. | `Ok of 'a
    (*

    The term of the command evaluated to this value.

    *)
  2. | `Version
    (*

    The version of the main cmd was requested.

    *)
  3. | `Help
    (*

    Help was requested.

    *)
]

The type for successful evaluation results.

type eval_error = [
  1. | `Parse
    (*

    A parse error occurred.

    *)
  2. | `Term
    (*

    A term evaluation error occurred.

    *)
  3. | `Exn
    (*

    An uncaught exception occurred.

    *)
]

The type for erroring evaluation results.

type 'a eval_exit = [
  1. | `Ok of 'a
    (*

    The term of the command evaluated to this value.

    *)
  2. | `Exit of Exit.code
    (*

    The evaluation wants to exit with this code.

    *)
]
val eval_value : + Exit.code

eval_result' cmd is:

  • c if cmd evaluates to Ok c.
  • Exit.some_error if cmd evaluates to Error msg. In this case msg is printed on err.

See eval_value for other arguments.

Low level evaluation

This interface gives more information on command evaluation results and lets you choose how to map evaluation results to exit codes. All evaluation functions are wrappers around eval_value.

type 'a eval_ok = [
  1. | `Ok of 'a
    (*

    The term of the command evaluated to this value.

    *)
  2. | `Version
    (*

    The version of the main cmd was requested.

    *)
  3. | `Help
    (*

    Help was requested.

    *)
]

The type for successful evaluation results.

type eval_error = [
  1. | `Parse
    (*

    A parse error occurred.

    *)
  2. | `Term
    (*

    A term evaluation error occurred.

    *)
  3. | `Exn
    (*

    An uncaught exception occurred.

    *)
]

The type for erroring evaluation results.

val eval_value : ?help:Stdlib.Format.formatter -> ?err:Stdlib.Format.formatter -> ?catch:bool -> ?env:(string -> string option) -> ?argv:string array -> 'a t -> - ('a eval_ok, eval_error) result

eval ~help ~err ~catch ~env ~argv cmd is the evaluation result of cmd with:

  • argv the command line arguments to parse (defaults to Sys.argv)
  • env the function used for environment variable lookup (defaults to Sys.getenv).
  • catch if true (default) uncaught exceptions are intercepted and their stack trace is written to the err formatter
  • help is the formatter used to print help or version messages (defaults to Format.std_formatter)
  • err is the formatter used to print error messages (defaults to Format.err_formatter).
val eval_value' : + ('a eval_ok, eval_error) result

eval ~help ~err ~catch ~env ~argv cmd is the evaluation result of cmd with:

  • argv the command line arguments to parse (defaults to Sys.argv)
  • env the function used for environment variable lookup (defaults to Sys.getenv).
  • catch if true (default) uncaught exceptions are intercepted and their stack trace is written to the err formatter
  • help is the formatter used to print help, version messages or completions, (defaults to Format.std_formatter). Note that the completion protocol needs to output '\n' line ending, if you are outputing to a channel make sure it is in binary mode to avoid newline translation (this is done automatically before completion when help is Format.std_formatter).
  • err is the formatter used to print error messages (defaults to Format.err_formatter).
type 'a eval_exit = [
  1. | `Ok of 'a
    (*

    The term of the command evaluated to this value.

    *)
  2. | `Exit of Exit.code
    (*

    The evaluation wants to exit with this code.

    *)
]

The type for evaluation exits.

val eval_value' : ?help:Stdlib.Format.formatter -> ?err:Stdlib.Format.formatter -> ?catch:bool -> @@ -57,9 +57,9 @@ ?argv:string array -> ?term_err:int -> 'a t -> - 'a eval_exit

eval_value' is like eval_value, but if the command term does not evaluate, returns an exit code like the evaluation function do (which can be Exit.ok in case help or version was requested).

val eval_peek_opts : + 'a eval_exit

eval_value' is like eval_value, but if the command term does not evaluate to Ok (`Ok v), returns an exit code like the higher-level evaluation functions do (which can be Exit.ok in case help or version was requested).

val eval_peek_opts : ?version_opt:bool -> ?env:(string -> string option) -> ?argv:string array -> 'a Term.t -> - 'a option * ('a eval_ok, eval_error) result

eval_peek_opts version_opt argv t evaluates t, a term made of optional arguments only, with the command line argv (defaults to Sys.argv). In this evaluation, unknown optional arguments and positional arguments are ignored.

The evaluation returns a pair. The first component is the result of parsing the command line argv stripped from any help and version option if version_opt is true (defaults to false). It results in:

  • Some _ if the command line would be parsed correctly given the partial knowledge in t.
  • None if a parse error would occur on the options of t

The second component is the result of parsing the command line argv without stripping the help and version options. It indicates what the evaluation would result in on argv given the partial knowledge in t (for example it would return `Help if there's a help option in argv). However in contrasts to eval_value no side effects like error reporting or help output occurs.

Note. Positional arguments can't be peeked without the full specification of the command line: we can't tell apart a positional argument from the value of an unknown optional argument.

+ 'a option * ('a eval_ok, eval_error) result

WARNING. You are highly encouraged not to use this function it may be removed in the future.

eval_peek_opts version_opt argv t evaluates t, a term made of optional arguments only, with the command line argv (defaults to Sys.argv). In this evaluation, unknown optional arguments and positional arguments are ignored.

The evaluation returns a pair. The first component is the result of parsing the command line argv stripped from any help and version option if version_opt is true (defaults to false). It results in:

  • Some _ if the command line would be parsed correctly given the partial knowledge in t.
  • None if a parse error would occur on the options of t

The second component is the result of parsing the command line argv without stripping the help and version options. It indicates what the evaluation would result in on argv given the partial knowledge in t (for example it would return `Help if there's a help option in argv). However in contrasts to eval_value no side effects like error reporting or help output occurs.

Note. Positional arguments can't be peeked without the full specification of the command line: we can't tell apart a positional argument from the value of an unknown optional argument.

diff --git a/cmdliner/Cmdliner/Manpage/index.html b/cmdliner/Cmdliner/Manpage/index.html index d24c76d3..37ba0bd8 100644 --- a/cmdliner/Cmdliner/Manpage/index.html +++ b/cmdliner/Cmdliner/Manpage/index.html @@ -1,8 +1,9 @@ -Manpage (cmdliner.Cmdliner.Manpage)

Module Cmdliner.Manpage

Man page specification.

Man page generation is automatically handled by Cmdliner, consult the details.

The Manpage.block type is used to define a man page's content. It's a good idea to follow the standard manual page structure.

References.

Man pages

type block = [
  1. | `S of string
  2. | `P of string
  3. | `Pre of string
  4. | `I of string * string
  5. | `Noblank
  6. | `Blocks of block list
]

The type for a block of man page text.

  • `S s introduces a new section s, see the standard section names.
  • `P t is a new paragraph with text t.
  • `Pre t is a new preformatted paragraph with text t.
  • `I (l,t) is an indented paragraph with label l and text t.
  • `Noblank suppresses the blank line introduced between two blocks.
  • `Blocks bs splices the blocks bs.

Except in `Pre, whitespace and newlines are not significant and are all collapsed to a single space. All block strings support the documentation markup language.

val escape : string -> string

escape s escapes s so that it doesn't get interpreted by the documentation markup language.

type title = string * int * string * string * string

The type for man page titles. Describes the man page title, section, center_footer, left_footer, center_header.

type t = title * block list

The type for a man page. A title and the page text as a list of blocks.

type xref = [
  1. | `Main
  2. | `Cmd of string
  3. | `Tool of string
  4. | `Page of string * int
]

The type for man page cross-references.

  • `Main refers to the man page of the program itself.
  • `Cmd cmd refers to the man page of the program's cmd command (which must exist).
  • `Tool bin refers to the command line tool named bin.
  • `Page (name, sec) refers to the man page name(sec).

Standard section names and content

The following are standard man page section names, roughly ordered in the order they conventionally appear. See also man man-pages for more elaborations about what sections should contain.

val s_name : string

The NAME section. This section is automatically created by Cmdliner for your.

val s_synopsis : string

The SYNOPSIS section. By default this section is automatically created by Cmdliner for you, unless it is the first section of your term's man page, in which case it will replace it with yours.

val s_description : string

The DESCRIPTION section. This should be a description of what the tool does and provide a little bit of usage and documentation guidance.

val s_commands : string

The COMMANDS section. By default subcommands get listed here.

val s_arguments : string

The ARGUMENTS section. By default positional arguments get listed here.

val s_options : string

The OPTIONS section. By default optional arguments get listed here.

val s_common_options : string

The COMMON OPTIONS section. By default help and version options get listed here. For programs with multiple commands, optional arguments common to all commands can be added here.

val s_exit_status : string

The EXIT STATUS section. By default term status exit codes get listed here.

val s_environment : string

The ENVIRONMENT section. By default environment variables get listed here.

val s_environment_intro : block

s_environment_intro is the introduction content used by cmdliner when it creates the s_environment section.

val s_files : string

The FILES section.

val s_bugs : string

The BUGS section.

val s_examples : string

The EXAMPLES section.

val s_authors : string

The AUTHORS section.

val s_see_also : string

The SEE ALSO section.

val s_none : string

s_none is a special section named "cmdliner-none" that can be used whenever you do not want something to be listed.

Output

The print function can be useful if the client wants to define other man pages (e.g. to implement a help command).

type format = [
  1. | `Auto
  2. | `Pager
  3. | `Plain
  4. | `Groff
]

The type for man page output specification.

  • `Auto, formats like `Pager or `Plain whenever the TERM environment variable is dumb or unset.
  • `Pager, tries to write to a discovered pager, if that fails uses the `Plain format.
  • `Plain, formats to plain text.
  • `Groff, formats to groff commands.
val print : +Manpage (cmdliner.Cmdliner.Manpage)

Module Cmdliner.Manpage

Man pages.

Man page generation is automatically handled by Cmdliner, see the details. The Manpage.block type is used to define a man page's content. It's a good idea to follow the standard manual page structure.

References.

Man pages

type section_name = string

The type for section names (titles). See standard section names.

type block = [
  1. | `S of section_name
    (*

    Start a new section with given name.

    *)
  2. | `P of string
    (*

    Paragraph with given text.

    *)
  3. | `Pre of string
    (*

    Preformatted paragraph with given text.

    *)
  4. | `I of string * string
    (*

    Indented paragraph with given label and text.

    *)
  5. | `Noblank
    (*

    Suppress blank line introduced between two blocks.

    *)
  6. | `Blocks of block list
    (*

    Splice given blocks.

    *)
]

The type for a block of man page text.

Except in `Pre, whitespace and newlines are not significant and are all collapsed to a single space. All block strings support the documentation markup language.

val escape : string -> string

escape s escapes s so that it doesn't get interpreted by the documentation markup language.

type title = string * int * string * string * string

The type for man page titles. Describes the man page title, section, center_footer, left_footer, center_header.

type t = title * block list

The type for a man page. A title and the page text as a list of blocks.

type xref = [
  1. | `Main
    (*

    Refer to the man page of the program itself.

    *)
  2. | `Cmd of string
    (*

    Refer to the command cmd of the tool, which must exist.

    *)
  3. | `Tool of string
    (*

    Tool refer to the given command line tool.

    *)
  4. | `Page of string * int
    (*

    Refer to the manpage name(sec).

    *)
]

The type for man page cross-references.

Standard section names and content

The following are standard man page section names, roughly ordered in the order they conventionally appear. See also man man-pages for more elaborations about what sections should contain.

val s_name : section_name

The NAME section. This section is automatically created by Cmdliner for your command.

val s_synopsis : section_name

The SYNOPSIS section. By default this section is automatically created by Cmdliner for your command, unless it is the first section of your term's man page, in which case it will replace it with yours.

val s_description : section_name

The DESCRIPTION section. This should be a description of what the tool does and provide a little bit of command line usage and documentation guidance.

val s_commands : section_name

The COMMANDS section. By default subcommands get listed here.

val s_arguments : section_name

The ARGUMENTS section. By default positional arguments get listed here.

val s_options : section_name

The OPTIONS section. By default optional arguments get listed here.

val s_common_options : section_name

The COMMON OPTIONS section. By default help and version options get listed here. For programs with multiple commands, optional arguments common to all commands can be added here.

val s_exit_status : section_name

The EXIT STATUS section. By default term status exit codes get listed here.

val s_environment : section_name

The ENVIRONMENT section. By default environment variables get listed here.

val s_environment_intro : block

s_environment_intro is the introduction content used by cmdliner when it creates the s_environment section.

val s_files : section_name

The FILES section.

val s_bugs : section_name

The BUGS section.

val s_examples : section_name

The EXAMPLES section.

val s_authors : section_name

The AUTHORS section.

val s_see_also : section_name

The SEE ALSO section.

val s_none : section_name

s_none is a special section named "cmdliner-none" that can be used whenever you do not want something to be listed.

Output

The print function can be useful if the client wants to define other man pages (e.g. to implement a help command).

type format = [
  1. | `Auto
    (*

    Format like `Pager or `Plain whenever the TERM environment variable is dumb or unset.

    *)
  2. | `Pager
    (*

    Tries to use a pager or falls back to `Plain.

    *)
  3. | `Plain
    (*

    Format to plain text.

    *)
  4. | `Groff
    (*

    Format to groff commands.

    *)
]

The type for man page output specification.

val print : + ?env:(string -> string option) -> ?errs:Stdlib.Format.formatter -> ?subst:(string -> string option) -> format -> Stdlib.Format.formatter -> t -> - unit

print ~errs ~subst fmt ppf page prints page on ppf in the format fmt. subst can be used to perform variable substitution,(defaults to the identity). errs is used to print formatting errors, it defaults to Format.err_formatter.

+ unit

print ~env ~errs ~subst fmt ppf page prints page on ppf in the format fmt.

  • env is used to lookup environment for driving paging when the format is `Pager. Defaults to Sys.getenv_opt.
  • subst can be used to perform variable substitution (defaults to the identity).
  • errs is used to print formatting errors, it defaults to Format.err_formatter.
diff --git a/cmdliner/Cmdliner/Term/Syntax/index.html b/cmdliner/Cmdliner/Term/Syntax/index.html index 5105ad57..9a66f8f0 100644 --- a/cmdliner/Cmdliner/Term/Syntax/index.html +++ b/cmdliner/Cmdliner/Term/Syntax/index.html @@ -1,2 +1,2 @@ -Syntax (cmdliner.Cmdliner.Term.Syntax)

Module Term.Syntax

let operators.

val (let+) : 'a t -> ('a -> 'b) -> 'b t

( let+ ) is map.

val (and+) : 'a t -> 'b t -> ('a * 'b) t

( and* ) is product.

+Syntax (cmdliner.Cmdliner.Term.Syntax)

Module Term.Syntax

let operators.

See how to use them in the blueprints.

val (let+) : 'a t -> ('a -> 'b) -> 'b t

( let+ ) is map.

val (and+) : 'a t -> 'b t -> ('a * 'b) t

( and+ ) is product.

diff --git a/cmdliner/Cmdliner/Term/index.html b/cmdliner/Cmdliner/Term/index.html index 5094dd8e..2f49277d 100644 --- a/cmdliner/Cmdliner/Term/index.html +++ b/cmdliner/Cmdliner/Term/index.html @@ -1,32 +1,2 @@ -Term (cmdliner.Cmdliner.Term)

Module Cmdliner.Term

Terms.

A term is evaluated by a program to produce a result, which can be turned into an exit status. A term made of terms referring to command line arguments implicitly defines a command line syntax.

Terms

type +'a t

The type for terms evaluating to values of type 'a.

val const : 'a -> 'a t

const v is a term that evaluates to v.

val ($) : ('a -> 'b) t -> 'a t -> 'b t

f $ v is a term that evaluates to the result of applying the evaluation of v to the one of f.

val app : ('a -> 'b) t -> 'a t -> 'b t

app is ($).

val map : ('a -> 'b) -> 'a t -> 'b t

map f t is app (const f) t.

val product : 'a t -> 'b t -> ('a * 'b) t

product t0 t1 is app (app (map (fun x y -> (x, y)) t0) t1)

module Syntax : sig ... end

let operators.

Interacting with Cmdliner's evaluation

val term_result : ?usage:bool -> ('a, [ `Msg of string ]) result t -> 'a t

term_result ~usage t evaluates to

  • `Ok v if t evaluates to Ok v
  • `Error `Term with the error message e and usage shown according to usage (defaults to false), if t evaluates to Error (`Msg e).

See also term_result'.

val term_result' : ?usage:bool -> ('a, string) result t -> 'a t

term_result' is like term_result but with a string error case.

val cli_parse_result : ('a, [ `Msg of string ]) result t -> 'a t

cli_parse_result t is a term that evaluates to:

  • `Ok v if t evaluates to Ok v.
  • `Error `Parse with the error message e if t evaluates to Error (`Msg e).

See also cli_parse_result'.

val cli_parse_result' : ('a, string) result t -> 'a t

cli_parse_result' is like cli_parse_result but with a string error case.

val main_name : string t

main_name is a term that evaluates to the main command name; that is the name of the tool.

val choice_names : string list t

choice_names is a term that evaluates to the names of the commands that are children of the main command.

val with_used_args : 'a t -> ('a * string list) t

with_used_args t is a term that evaluates to t tupled with the arguments from the command line that where used to evaluate t.

type 'a ret = [
  1. | `Help of Manpage.format * string option
  2. | `Error of bool * string
  3. | `Ok of 'a
]

The type for command return values. See ret.

val ret : 'a ret t -> 'a t

ret v is a term whose evaluation depends on the case to which v evaluates. With :

  • `Ok v, it evaluates to v.
  • `Error (usage, e), the evaluation fails and Cmdliner prints the error e and the term's usage if usage is true.
  • `Help (format, name), the evaluation fails and Cmdliner prints a manpage in format format. If name is None this is the the main command's manpage. If name is Some c this is the man page of the sub command c of the main command.

Note. While not deprecated you are encouraged not use this API.

Deprecated Term evaluation interface

This interface is deprecated in favor of Cmdliner.Cmd. Follow the compiler deprecation warning hints to transition.

Term information

Term information defines the name and man page of a term. For simple evaluation this is the name of the program and its man page. For multiple term evaluation, this is the name of a command and its man page.

type exit_info

The type for exit status information.

  • deprecated Use Cmd.Exit.info instead.
val exit_info : ?docs:string -> ?doc:string -> ?max:int -> int -> exit_info

exit_info ~docs ~doc min ~max describe the range of exit statuses from min to max (defaults to min). doc is the man page information for the statuses, defaults to "undocumented". docs is the title of the man page section in which the statuses will be listed, it defaults to Manpage.s_exit_status.

In doc the documentation markup language can be used with following variables:

  • $(status), the value of min.
  • $(status_max), the value of max.
  • The variables mentioned in info
  • deprecated Use Cmd.Exit.info instead.
val default_exits : exit_info list

default_exits is information for exit status exit_status_success added to default_error_exits.

  • deprecated Use Cmd.Exit.defaults or Cmd.info's defaults ~exits value instead.
val default_error_exits : exit_info list

default_error_exits is information for exit statuses exit_status_cli_error and exit_status_internal_error.

  • deprecated List.filter the Cmd.Exit.defaults value instead.
type env_info

The type for environment variable information.

  • deprecated Use Cmd.Env.info instead.
val env_info : ?docs:string -> ?doc:string -> string -> env_info

env_info ~docs ~doc var describes an environment variable var. doc is the man page information of the environment variable, defaults to "undocumented". docs is the title of the man page section in which the environment variable will be listed, it defaults to Cmdliner.Manpage.s_environment.

In doc the documentation markup language can be used with following variables:

  • $(env), the value of var.
  • The variables mentioned in info
  • deprecated Use Cmd.Env.info instead.
type info

The type for term information.

  • deprecated Use Cmd.info instead.
val info : - ?man_xrefs:Manpage.xref list -> - ?man:Manpage.block list -> - ?envs:env_info list -> - ?exits:exit_info list -> - ?sdocs:string -> - ?docs:string -> - ?doc:string -> - ?version:string -> - string -> - info

info sdocs man docs doc version name is a term information such that:

  • name is the name of the program or the command.
  • version is the version string of the program, ignored for commands.
  • doc is a one line description of the program or command used for the NAME section of the term's man page. For commands this description is also used in the list of commands of the main term's man page.
  • docs, only for commands, the title of the section of the main term's man page where it should be listed (defaults to Manpage.s_commands).
  • sdocs defines the title of the section in which the standard --help and --version arguments are listed (defaults to Manpage.s_options).
  • exits is a list of exit statuses that the term evaluation may produce.
  • envs is a list of environment variables that influence the term's evaluation.
  • man is the text of the man page for the term.
  • man_xrefs are cross-references to other manual pages. These are used to generate a Manpage.s_see_also section.

doc, man, envs support the documentation markup language in which the following variables are recognized:

  • $(tname) the term's name.
  • $(mname) the main term's name.
  • deprecated Use Cmd.info instead.
val name : info -> string

name ti is the name of the term information.

  • deprecated Use Cmd.name instead.

Evaluation

type 'a result = [
  1. | `Ok of 'a
  2. | `Error of [ `Parse | `Term | `Exn ]
  3. | `Version
  4. | `Help
]

The type for evaluation results.

  • `Ok v, the term evaluated successfully and v is the result.
  • `Version, the version string of the main term was printed on the help formatter.
  • `Help, man page about the term was printed on the help formatter.
  • `Error `Parse, a command line parse error occurred and was reported on the error formatter.
  • `Error `Term, a term evaluation error occurred and was reported on the error formatter (see Term.ret').
  • `Error `Exn, an exception e was caught and reported on the error formatter (see the ~catch parameter of eval).
val eval : - ?help:Stdlib.Format.formatter -> - ?err:Stdlib.Format.formatter -> - ?catch:bool -> - ?env:(string -> string option) -> - ?argv:string array -> - ('a t * info) -> - 'a result

eval help err catch argv (t,i) is the evaluation result of t with command line arguments argv (defaults to Sys.argv).

If catch is true (default) uncaught exceptions are intercepted and their stack trace is written to the err formatter.

help is the formatter used to print help or version messages (defaults to Format.std_formatter). err is the formatter used to print error messages (defaults to Format.err_formatter).

env is used for environment variable lookup, the default uses Sys.getenv.

  • deprecated Use Cmd.v and one of Cmd.eval* instead.
val eval_choice : - ?help:Stdlib.Format.formatter -> - ?err:Stdlib.Format.formatter -> - ?catch:bool -> - ?env:(string -> string option) -> - ?argv:string array -> - ('a t * info) -> - ('a t * info) list -> - 'a result

eval_choice help err catch argv (t,i) choices is like eval except that if the first argument on the command line is not an option name it will look in choices for a term whose information has this name and evaluate it.

If the command name is unknown an error is reported. If the name is unspecified the "main" term t is evaluated. i defines the name and man page of the program.

  • deprecated Use Cmd.group and one of Cmd.eval* instead.
val eval_peek_opts : - ?version_opt:bool -> - ?env:(string -> string option) -> - ?argv:string array -> - 'a t -> - 'a option * 'a result

eval_peek_opts version_opt argv t evaluates t, a term made of optional arguments only, with the command line argv (defaults to Sys.argv). In this evaluation, unknown optional arguments and positional arguments are ignored.

The evaluation returns a pair. The first component is the result of parsing the command line argv stripped from any help and version option if version_opt is true (defaults to false). It results in:

  • Some _ if the command line would be parsed correctly given the partial knowledge in t.
  • None if a parse error would occur on the options of t

The second component is the result of parsing the command line argv without stripping the help and version options. It indicates what the evaluation would result in on argv given the partial knowledge in t (for example it would return `Help if there's a help option in argv). However in contrasts to eval and eval_choice no side effects like error reporting or help output occurs.

Note. Positional arguments can't be peeked without the full specification of the command line: we can't tell apart a positional argument from the value of an unknown optional argument.

  • deprecated Use Cmd.eval_peek_opts instead.

Turning evaluation results into exit codes

Note. If you are using the following functions to handle the evaluation result of a term you should add default_exits to the term's information ~exits argument.

WARNING. You should avoid status codes strictly greater than 125 as those may be used by some shells.

val exit_status_success : int

exit_status_success is 0, the exit status for success.

  • deprecated Use Cmd.Exit.ok instead.
val exit_status_cli_error : int

exit_status_cli_error is 124, an exit status for command line parsing errors.

  • deprecated Use Cmd.Exit.cli_error instead.
val exit_status_internal_error : int

exit_status_internal_error is 125, an exit status for unexpected internal errors.

  • deprecated Use Cmd.Exit.internal_error instead.
val exit_status_of_result : ?term_err:int -> unit result -> int

exit_status_of_result ~term_err r is an exit(3) status code determined from r as follows:

  • deprecated Use Cmd.eval instead.
val exit_status_of_status_result : ?term_err:int -> int result -> int

exit_status_of_status_result is like exit_status_of_result except for `Ok n where n is used as the status exit code.

  • deprecated Use Cmd.eval' instead.
val exit : ?term_err:int -> unit result -> unit

exit ~term_err r is Stdlib.exit @@ exit_status_of_result ~term_err r

  • deprecated Use Stdlib.exit and Cmd.eval instead.
val exit_status : ?term_err:int -> int result -> unit

exit_status ~term_err r is Stdlib.exit @@ exit_status_of_status_result ~term_err r

  • deprecated Use Stdlib.exit and Cmd.eval' instead.
+Term (cmdliner.Cmdliner.Term)

Module Cmdliner.Term

Terms.

A term made of terms referring to command line arguments implicitly defines a command line syntax fragment. Terms are associated to command values Cmd.t which are evaluated to eventually produce an exit code.

Nowadays terms are best defined using the Cmdliner.Term.Syntax. See examples in the blueprints.

Terms

type +'a t

The type for terms evaluating to values of type 'a.

val const : 'a -> 'a t

const v is a term that evaluates to v.

val app : ('a -> 'b) t -> 'a t -> 'b t

app f v is a term that evaluates to the result applying the evaluation of v to the one of f.

val map : ('a -> 'b) -> 'a t -> 'b t

map f t is app (const f) t.

val product : 'a t -> 'b t -> ('a * 'b) t

product t0 t1 is app (app (map (fun x y -> (x, y)) t0) t1)

val ($) : ('a -> 'b) t -> 'a t -> 'b t

f $ v is app f v.

module Syntax : sig ... end

let operators.

Interacting with Cmd.t evaluation

These special terms allow to interact with the low-level evaluation process performed on commands.

val term_result : ?usage:bool -> ('a, [ `Msg of string ]) result t -> 'a t

term_result is such that:

  • term_result ~usage (Ok v) evaluates to Ok (`Ok v).
  • term_result ~usage (Error (`Msg e)) evaluates to Error `Term with the error message e and usage shown according to usage (defaults to false)

See also term_result'.

val term_result' : ?usage:bool -> ('a, string) result t -> 'a t

term_result' is like term_result but with a string error case.

val cli_parse_result : ('a, [ `Msg of string ]) result t -> 'a t

cli_parse_result is such that:

  • cli_parse_result (Ok v) evaluates Ok (`Ok v)).} {- [cli_parse_result (Error (`Msg e))] evaluates Error `Parse.

See also cli_parse_result'.

val cli_parse_result' : ('a, string) result t -> 'a t

cli_parse_result' is like cli_parse_result but with a string error case.

val main_name : string t

main_name is a term that evaluates to the main command name; that is the name of the tool.

val choice_names : string list t

choice_names is a term that evaluates to the names of the commands that are children of the main command.

val with_used_args : 'a t -> ('a * string list) t

with_used_args t is a term that evaluates to t tupled with the arguments from the command line that where used to evaluate t.

type 'a ret = [
  1. | `Help of Manpage.format * string option
  2. | `Error of bool * string
  3. | `Ok of 'a
]

The type for command return values. See ret.

val ret : 'a ret t -> 'a t

ret v is a term whose evaluation depends on the case to which v evaluates. With :

  • `Ok v, it evaluates to v.
  • `Error (usage, e), the evaluation fails and Cmdliner prints the error e and the term's usage if usage is true.
  • `Help (format, name), the evaluation fails and Cmdliner prints a manpage in format format. If name is None this is the the main command's manpage. If name is Some c this is the man page of the subcommand c of the main command.
val env : (string -> string option) t

env is the env argument given to command evaluation functions. If you need to refine the environment lookup done by Cmdliner's machinery you should use this rather than direct calls to Sys.getenv_opt.

diff --git a/cmdliner/Cmdliner/index.html b/cmdliner/Cmdliner/index.html index 67744e11..e4e4414d 100644 --- a/cmdliner/Cmdliner/index.html +++ b/cmdliner/Cmdliner/index.html @@ -1,2 +1,2 @@ -Cmdliner (cmdliner.Cmdliner)

Module Cmdliner

Declarative definition of command line interfaces.

Consult the tutorial, details about the supported command line syntax and examples of use.

Open the module to use it, it defines only three modules in your scope.

module Manpage : sig ... end

Man page specification.

module Term : sig ... end

Terms.

module Cmd : sig ... end

Commands.

module Arg : sig ... end

Terms for command line arguments.

+Cmdliner (cmdliner.Cmdliner)

Module Cmdliner

Declarative definition of command line interfaces.

Consult the tutorial, the cookbook, program blueprints and source structure, details about the supported command line syntax and examples of use.

Open the module to use it, it defines only these modules in your scope.

module Manpage : sig ... end

Man pages.

module Term : sig ... end

Terms.

module Cmd : sig ... end

Commands.

module Arg : sig ... end

Terms for command line arguments.

diff --git a/cmdliner/Cmdliner_arg/index.html b/cmdliner/Cmdliner_arg/index.html new file mode 100644 index 00000000..132e898f --- /dev/null +++ b/cmdliner/Cmdliner_arg/index.html @@ -0,0 +1,2 @@ + +Cmdliner_arg (cmdliner.Cmdliner_arg)

Module Cmdliner_arg

This module is hidden.

diff --git a/cmdliner/Cmdliner_base/index.html b/cmdliner/Cmdliner_base/index.html new file mode 100644 index 00000000..1f92b063 --- /dev/null +++ b/cmdliner/Cmdliner_base/index.html @@ -0,0 +1,2 @@ + +Cmdliner_base (cmdliner.Cmdliner_base)

Module Cmdliner_base

This module is hidden.

diff --git a/cmdliner/Cmdliner_cline/index.html b/cmdliner/Cmdliner_cline/index.html new file mode 100644 index 00000000..a6308331 --- /dev/null +++ b/cmdliner/Cmdliner_cline/index.html @@ -0,0 +1,2 @@ + +Cmdliner_cline (cmdliner.Cmdliner_cline)

Module Cmdliner_cline

This module is hidden.

diff --git a/cmdliner/Cmdliner_cmd/index.html b/cmdliner/Cmdliner_cmd/index.html new file mode 100644 index 00000000..05641440 --- /dev/null +++ b/cmdliner/Cmdliner_cmd/index.html @@ -0,0 +1,2 @@ + +Cmdliner_cmd (cmdliner.Cmdliner_cmd)

Module Cmdliner_cmd

This module is hidden.

diff --git a/cmdliner/Cmdliner_completion/index.html b/cmdliner/Cmdliner_completion/index.html new file mode 100644 index 00000000..36e5d91e --- /dev/null +++ b/cmdliner/Cmdliner_completion/index.html @@ -0,0 +1,2 @@ + +Cmdliner_completion (cmdliner.Cmdliner_completion)

Module Cmdliner_completion

This module is hidden.

diff --git a/cmdliner/Cmdliner_def/index.html b/cmdliner/Cmdliner_def/index.html new file mode 100644 index 00000000..78b8188c --- /dev/null +++ b/cmdliner/Cmdliner_def/index.html @@ -0,0 +1,2 @@ + +Cmdliner_def (cmdliner.Cmdliner_def)

Module Cmdliner_def

This module is hidden.

diff --git a/cmdliner/Cmdliner_docgen/index.html b/cmdliner/Cmdliner_docgen/index.html new file mode 100644 index 00000000..aebad754 --- /dev/null +++ b/cmdliner/Cmdliner_docgen/index.html @@ -0,0 +1,2 @@ + +Cmdliner_docgen (cmdliner.Cmdliner_docgen)

Module Cmdliner_docgen

This module is hidden.

diff --git a/cmdliner/Cmdliner_eval/index.html b/cmdliner/Cmdliner_eval/index.html new file mode 100644 index 00000000..85c6f9d8 --- /dev/null +++ b/cmdliner/Cmdliner_eval/index.html @@ -0,0 +1,2 @@ + +Cmdliner_eval (cmdliner.Cmdliner_eval)

Module Cmdliner_eval

This module is hidden.

diff --git a/cmdliner/Cmdliner_manpage/index.html b/cmdliner/Cmdliner_manpage/index.html new file mode 100644 index 00000000..ffdaff40 --- /dev/null +++ b/cmdliner/Cmdliner_manpage/index.html @@ -0,0 +1,2 @@ + +Cmdliner_manpage (cmdliner.Cmdliner_manpage)

Module Cmdliner_manpage

This module is hidden.

diff --git a/cmdliner/Cmdliner_msg/index.html b/cmdliner/Cmdliner_msg/index.html new file mode 100644 index 00000000..eb4a2472 --- /dev/null +++ b/cmdliner/Cmdliner_msg/index.html @@ -0,0 +1,2 @@ + +Cmdliner_msg (cmdliner.Cmdliner_msg)

Module Cmdliner_msg

This module is hidden.

diff --git a/cmdliner/Cmdliner_term/index.html b/cmdliner/Cmdliner_term/index.html new file mode 100644 index 00000000..6dfbaf28 --- /dev/null +++ b/cmdliner/Cmdliner_term/index.html @@ -0,0 +1,2 @@ + +Cmdliner_term (cmdliner.Cmdliner_term)

Module Cmdliner_term

This module is hidden.

diff --git a/cmdliner/Cmdliner_trie/index.html b/cmdliner/Cmdliner_trie/index.html new file mode 100644 index 00000000..55ba01ab --- /dev/null +++ b/cmdliner/Cmdliner_trie/index.html @@ -0,0 +1,2 @@ + +Cmdliner_trie (cmdliner.Cmdliner_trie)

Module Cmdliner_trie

This module is hidden.

diff --git a/cmdliner/_doc-dir/CHANGES.md b/cmdliner/_doc-dir/CHANGES.md old mode 100755 new mode 100644 index 36968f93..78b98382 --- a/cmdliner/_doc-dir/CHANGES.md +++ b/cmdliner/_doc-dir/CHANGES.md @@ -1,3 +1,133 @@ +v2.0.0 2025-09-26 Zagreb +------------------------ + +### End-user visible changes + +- **IMPORTANT** Cmdliner no longer allows command names, option names, + and `Arg.enum` values to be specified by a prefix if the prefix is + unambiguous. See #200 for the rationale. To quickly salvage scripts + that may be relying on the old behaviour, it can be restored by + setting the environment variable `CMDLINER_LEGACY_PREFIXES=true`. + However the scripts should be fixed: this escape hatch will be + removed in the future. + +- Pager. If set, respect the user's `LESS` environment variable + (otherwise the default `LESS=FRX` is left unchanged). Note however + that you likely need at least `R` specified if you define it + yourself, otherwise the manpage may look garbled (#191). Thanks to + Yukai Chou for suggesting. + +- Fix lack of output whenever `PAGER` or `MANPAGER` is set but empty; + fallback to pager discovery (#194). For example this prevented to + see manpages in `emacs`'s compilation mode which unhelpfully + hardcodes `PAGER=""`. + +- Fix synopsis rendering of required optional arguments (#203). + +- Output error messages on `stderr` with styled text (#144). Quoted + and typewriter text is in bold. Variables are written as + underlines. Key words of error messages are in red. + +- Output error messages after the usage line and remove the `Try with + $(tool) --help for more information` message. Instead we explicitly + indicate the `--help` option in the usage line. Having the error message + at the end makes it easier to spot. + +- Make `--help` request work in any context, except after `--` or on + the arguments after an unknown command error in which case that + error is reported (less confusing). Since the option has an optional + argument value, one had to be carefull that it would not pickup the + next argument and try to parse it according to `FMT`. This is no + longer the case. If the argument fails to parse `--help=auto` is + assumed. (#201). + +- Deprecation messages are now prepended to the doc strings in the manpage. + +### API changes + +- Reserve the `--__complete` option for library use. + +- Documentation language, `$(cmd)`, `$(cmd.name)` and `$(tool)` can be + used and should be prefered over of `$(iname)`, `$(tname)` and + `$(mname)`. `$(cmd.parent)` is added to refer to a command's parent + or itself at the root. + +- Make `Cmdliner.Arg.conv` abstract. Thanks to Andrey Popp for + the patch (#206). + +- Thanks to the previous point, use the `docv` parameter of argument + converters can now be used to define the default value used by `docv` in + `Arg.info`. See `Arg.Conv.docv`. + +- Add `Manpage.section_name` type alias (#202). + +- Add `Cmd.make` which should be preferred to `Cmd.v` (The `M.v` notation is + nice for simulating literals, not for heavy constructor). + +- Add `Cmd.Env.info_var`. To get back the environment variable name + from a variable info. + +- Add optional `doc_envs` argument to `Arg.info` for adding the given + environment variables info to the command in which the argument is used. + Sometimes more than one variable make sense and the `env` argument is + not directly used. + +- Add `Arg.Completion` a module to define argument completion + strategies (#1, #187). + +- Add `Arg.Conv` module to define converters. This should be used in + new code. + +- Add `Arg.{file,dir,}path` string converters equiped with appropriate + file system completions. + +- Add `docv` optional parameter to `Arg.enum`. + +- Add `Term.env` which provides access to the environment access + function provided to evaluation functions. + +- Clarify the semantics of the `deprecated` argument of + `Cmdliner.Cmd.info`, `Cmdliner.Arg.info` and + `Cmdliner.Cmd.Env.info`. First, the language markup is now supported + therein. Second the message is no longer only used to warn about + usage it is now also prepended to the doc string of the entity. + +- Use `Arg.conv`'s `docv` property in the documentation of arguments + whenever `Arg.info`'s `docv` is unspecified (#207). + +- Do not check file existence for `-` in `Arg.file` or + `Arg.non_dir_file` values. This is supposed to mean `stdin` or + `stdout` (#208). + +- Fix manpage rendering performing direct calls to `Sys.getenv` in + `Cmd.eval*` functions instead of calling the `env` argument as + advertised in the docs. Incidentally add an `env` optional argument + to `Manpage.print` (#209). + +- Deprecate. `Arg.{printer,conv_docv,conv_parser, + conv_printer,parser_of_kind_of_string,conv,conv'}`. These will + likely never be removed but they should no longer be used for + new code. Use `Arg.Conv`. + +- Remove deprecated `Arg.{converter,parser,pconv}` (#206). +- Remove deprecated `Arg.{env,env_var}` (#206). +- Remove deprecated `Term.{pure,man_format}` (#206). +- Remove deprecated `Term` evaluation interface (#206). + +### Other + +- Install a `cmdliner` tool to help with manpage and completion script + installation. See the command line interface manual of the library + for more information (#187, #227, #228). + +- Install all source files for `odoc` and goto definition editor + functionality. Thanks to Emile Trotignon and Paul-Elliot Anglès + d'Auriac for noticing and suggesting (#225). + +- Added a proper test suite to the library to check for regressions. + Replaces most of the test executables that had to be run and inspected + manually (#205). + v1.3.0 2024-05-23 La Forclaz (VS) --------------------------------- @@ -100,8 +230,8 @@ This version of cmdliner deprecates the `Term.eval*` evaluation functions and `Term.info` information values in favor of the new `Cmdliner.Cmd` module. -The `Cmd` module generalizes the existing sub command support to allow -arbitrarily nested sub commands each with its own man page and command +The `Cmd` module generalizes the existing subcommand support to allow +arbitrarily nested subcommands each with its own man page and command line syntax represented by a `Term.t` value. The mapping between the old interface and the new one should be rather @@ -116,7 +246,7 @@ However in this transition the following things are changed or added: * The `?exits` argument which defaults to `Cmd.Exit.defaults` rather than the empty list. * The `?man_xrefs` which defaults to the list ``[`Main]`` rather - than the empty list (this means that by default sub commands + than the empty list (this means that by default subcommands at any level automatically cross-reference the main command). * The `?sdocs` argument which defaults to `Manpage.s_common_options` rather than `Manpage.s_options`. @@ -136,9 +266,9 @@ However in this transition the following things are changed or added: or `Term.term_result`. Finally be aware that if you replace, in an existing tool, an encoding -of sub commands as positional arguments you will effectively break the +of subcommands as positional arguments you will effectively break the command line compatibility of your tool since options can no longer be -specified before the sub commands, i.e. your tool synopsis moves from: +specified before the subcommands, i.e. your tool synopsis moves from: ``` tool cmd [OPTION]… SUBCMD [ARG]… @@ -367,7 +497,7 @@ v0.9.6 2014-11-18 La Forclaz (VS) the sense that only more command lines are parsed. Thanks to Hugo Heuzard for the patch. - End user error message improvements using heuristics and edit - distance search in the optional argument and sub command name + distance search in the optional argument and subcommand name spaces. Thanks to Hugo Heuzard for the patch. - Adds `Arg.doc_{quote,alts,alts_enum}`, documentation string helpers. diff --git a/cmdliner/_doc-dir/LICENSE.md b/cmdliner/_doc-dir/LICENSE.md old mode 100755 new mode 100644 diff --git a/cmdliner/_doc-dir/README.md b/cmdliner/_doc-dir/README.md old mode 100755 new mode 100644 index c7d0a804..112119b0 --- a/cmdliner/_doc-dir/README.md +++ b/cmdliner/_doc-dir/README.md @@ -1,22 +1,22 @@ Cmdliner — Declarative definition of command line interfaces for OCaml -------------------------------------------------------------------------------- -v1.3.0 +====================================================================== Cmdliner allows the declarative definition of command line interfaces for OCaml. It provides a simple and compositional mechanism to convert command line arguments to OCaml values and pass them to your functions. The -module automatically handles syntax errors, help messages and UNIX man -page generation. It supports programs with single or multiple commands -and respects most of the [POSIX][1] and [GNU][2] conventions. +module automatically handles command line completion, syntax errors, +help messages and UNIX man page generation. It supports programs with +single or multiple commands and respects most of the [POSIX] and [GNU] +conventions. Cmdliner has no dependencies and is distributed under the ISC license. -[1]: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html -[2]: http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html +Homepage: -Home page: http://erratique.ch/software/cmdliner +[POSIX]: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html +[GNU]: http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html ## Installation @@ -27,23 +27,17 @@ Cmdliner can be installed with `opam`: If you don't use `opam` consult the [`opam`](opam) file for build instructions. - ## Documentation -The documentation and API reference is automatically generated by from -the source interfaces. It can be consulted [online][doc] or via -`odig doc cmdliner`. +The documentation can be consulted [online] or via `odig doc cmdliner`. -[doc]: http://erratique.ch/software/cmdliner/doc/Cmdliner +Questions are welcome but better asked on the [OCaml forum] than on the +issue tracker. +[online]: http://erratique.ch/software/cmdliner/doc/ +[OCaml forum]: https://discuss.ocaml.org/ ## Sample programs -If you installed Cmdliner with `opam` sample programs are located in -the directory `opam config var cmdliner:doc`. These programs define -the command line of some classic programs. - -In the distribution sample programs are located in the `test` -directory of the distribution. They can be built and run with: - - topkg build --tests true && topkg test +A few examples and blueprints can be found in the +[documentation][online] and in the [test](test/) directory. diff --git a/cmdliner/_doc-dir/odoc-pages/cli.mld b/cmdliner/_doc-dir/odoc-pages/cli.mld old mode 100755 new mode 100644 index 35799333..a66abc1e --- a/cmdliner/_doc-dir/odoc-pages/cli.mld +++ b/cmdliner/_doc-dir/odoc-pages/cli.mld @@ -1,14 +1,19 @@ {0:cmdline Command line interface} -For tools evaluating a command without sub commands the most general +This manual describes how your tool ends up interacting +with shells when you use Cmdliner. + +{1:invocation Tool invocation} + +For tools evaluating a command without subcommands the most general form of invocation is: -{[ +{v tool [OPTION]… [ARG]… -]} +v} -The tool automatically reponds to the [--help] option by printing the -help. If a version string is provided in the +The tool automatically reponds to the [--help] option by printing +{{!help}the help}. If a version string is provided in the {{!Cmdliner.Cmd.val-info}command information}, it also automatically responds to the [--version] option by printing this string on standard output. @@ -17,22 +22,23 @@ Command line arguments are either {{!optargs}{e optional}} or {{!posargs}{e positional}}. Both can be freely interleaved but since [Cmdliner] accepts many optional forms this may result in ambiguities. The special {{!posargs} token [--]} can be used to -resolve them; anything that follows it is treated as a positional +resolve them: anything that follows it is treated as a positional argument. -Tools evaluating commands with sub commands have this form of invocation +Tools evaluating commands with subcommands have this form of invocation -{[ +{v tool [COMMAND]… [OPTION]… [ARG]… -]} +v} Commands automatically respond to the [--help] option by printing -their help. The sequence of [COMMAND] strings must be the first +{{!help}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. Command names may be specified by -a prefixe as long as they are not ambiguous. +seen the search for a subcommand stops. -{1:optargs Optional arguments} +{1:args Arguments} + +{2:optargs Optional arguments} An optional argument is specified on the command line by a {e name} possibly followed by a {e value}. @@ -48,7 +54,7 @@ The name of an option can be short or long. 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. Long names can be specified by any non ambiguous prefix. +be quiet. The value of an option can be specified in three different ways. @@ -74,7 +80,7 @@ group can end with a short option. For example assuming [-v] and {- [-vxf opt] will be parsed as [-v -x -fopt].} {- [-fvx] will be parsed as [-f=vx].}} -{1:posargs Positional arguments} +{2:posargs Positional arguments} Positional arguments are tokens on the command line that are not option names and are not the value of an optional argument. They are @@ -85,14 +91,28 @@ 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 -- we -are --all positional --argu=ments -]} +{v +tool --option -- but --now we -are --all positional --argu=ments +v} + +{2:constraints Constraints on option names} + +Using the cmdliner library puts the following constraints on your +command line interface: + +{ul +{- The option names [--cmdliner] and [--__complete] are reserved by the + library.} +{- The option name [--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.} +{- Defining the same option or command name via two different + arguments or terms is illegal and raises [Invalid_argument].}} {1:envlookup Environment variables} Non-required command line arguments can be backed up by an environment -variable. If the argument is absent from the command line and that +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. @@ -105,17 +125,360 @@ as follows: {- ["true"], ["yes"], ["y"] or ["1"] is [true].} {- Any other string is an error.}} -Note that environment variables are not supported for {!Cmdliner.Arg.vflag} and -{!Cmdliner.Arg.vflag_all}. +Note that environment variables are not supported for +{!Cmdliner.Arg.vflag} and {!Cmdliner.Arg.vflag_all}. -{1:reserved Reserved option names} +{1:help Help and man pages} -Using the cmdliner library puts the following constraints o +Help and man pages are are generated when you call your tool or a subcommand +with [--help]. By default, if the [TERM] environment variable +is not [dumb] or unset, the tool tries to {{!paging}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. + +{@sh[ +tool --help +tool cmd --help +tool --help=groff > tool.1 +]} + +{2:paging Paging} + +The pager is selected by looking up, in order: + +{ol +{- The [MANPAGER] variable.} +{- The [PAGER] variable.} +{- The tool [less].} +{- The tool [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. + +{2:install_tool_manpages Install} + +The manpages of a tool and its subcommands can be installed to a root +[man] directory [$MANDIR] by invoking: + +{@shell[ +cmdliner install tool-manpages thetool $MANDIR +]} + +This looks up [thetool] in the [PATH]. Use an explicit file path like +[./thetool] to directly specify an executable. + +If you are also {{!install_tool_completion}installing completions} +rather use the [install tool-support] command, see this +{{!page-cookbook.tip_tool_support}cookbook tip} which also has +instructions on how to install if you are using [opam]. + +{1:cli_completion Command line completion} + +Cmdliner programs automatically get support for shell command line +completion. + +The completion process happens via a {{!completion_protocol}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_tool_completion}install} +completion definitions that invoke these completion scripts. Tool +end-users need to {{!user_configuration}make sure} these definitions are +looked up by their shell. + +{2:user_configuration End-user configuration} + +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. + +{3:user_zsh For [zsh]} + +The [FPATH] environment variable must be setup to include the +directory where the generic cmdliner completion function is +{{!install_completion} installed} {b before} properly initializing the +completion system. + +For example, {{:https://github.com/ocaml/opam/issues/6427}for now}, if +you are using [opam]. You should add something like this to your +[.zshrc]: + +{@sh[ +FPATH="$(opam var share)/zsh/site-functions:${FPATH}" +autoload -Uz compinit +compinit -u +]} + +Also make sure this {b happens before} [opam]'s [zsh] init script +inclusion, see {{:https://github.com/ocaml/opam/issues/6428}this +issue}. Note that these instruction do not react dynamically +to [opam] switches changes so you may see odd completion behaviours +when you do so, see this {{:https://github.com/ocaml/opam/issues/6427}this +opam 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). + +{@sh[ +> 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 +{{!install_generic_completion}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_tool_completion}install} a completion +definition. You can always do it yourself by invoking: + +{@sh[ +autoload _cmdliner_generic +compdef _cmdliner_generic thetool +]} + +{3:user_bash For [bash]} + +These instructions assume that you have +{{:https://repology.org/project/bash-completion/versions}[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 +{{!install_completion}installed}. + +For example, {{:https://github.com/ocaml/opam/issues/6427}for now}, if +you are using [opam]. You should add something like this to your +[.bashrc]: +{@sh[ +XDG_DATA_DIRS="$(opam var share):${XDG_DATA_DIRS}" +]} + +Note that these instruction do not react dynamically to [opam] +switches changes so you may see odd completion behaviours when you do +so, see this {{:https://github.com/ocaml/opam/issues/6427}this opam +issue}. + +After this, to test everything is right, check that the [_cmdliner_generic] +function can be looked up: + +{@sh[ +> _completion_loader _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 +{{!install_generic_completion}installed} and that the +[_cmdliner_generic] file can be looked up by [_completion_loader]. + +With this setup, if you are using a cmdliner based tool named +[thetool] that did not {{!install_tool_completion}install} a completion +definition. You can always do it yourself by invoking: + +{@sh[ +_completion_loader _cmdliner_generic +complete -F _cmdliner_generic thetool +]} + +{b Note.} {{:https://github.com/scop/bash-completion/commit/9efc596735c4509001178f0cf28e02f66d1f7703}It seems} [_completion_loader] was deprecated in +bash-completion [2.12] in favour of [_comp_load] but many distributions +are on [< 2.12] and in [2.12] [_completion_loader] simply calls +[_comp_load]. + +{2:install_completion Install} + +Completion scripts need to be installed in subdirectories of a +{{:https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch04s11.html}[share]} +directory which we denote by the [$SHAREDIR] variable below. In a +package installation script this variable is typically defined by: + +{@sh[ +SHAREDIR="$DESTDIR/$PREFIX/share" +]} + +The final destination directory in [share] depends on the shell: {ul -{- The option name [--cmdliner] is reserved by the library.} -{- The option name [--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.} -{- Defining the same option or command name via two different - arguments or terms is illegal and raises [Invalid_argument].}} +{- For [zsh] it is [$SHAREDIR/zsh/site-functions]} +{- For [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. + +{3:install_generic_completion Generic completion scripts} + +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. + +{@sh[ +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. + +{3:install_tool_completion Tool completion scripts} + +If your tool named [thetool] uses Cmdliner you should install completion +definitions for them. They rely on the {{!install_generic_completion}generic +scripts} to be installed. These tool specific scripts can be inspected +and installed via these invocations: + +{@sh[ +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 also {{!install_tool_manpages}installing manpages} rather +use the [install tool-support] command, see this +{{!page-cookbook.tip_tool_support}cookbook tip} which also has +instructions on how to install if you are using [opam]. + +{2:completion_protocol Completion protocol} + +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 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 [cmdliner generic-completion] command. + +The protocol betwen the shell completion {e script} and a +cmdliner based {e tool} is as follows: + +{ol +{- When completion is requested the script invokes the tool with a + modified command line: + {ul + {- The first argument to the tool ([Sys.argv.(1)]) must be the + option [--__complete].} + {- The (possibly empty) argument [ARG] on which the completion is + requested must be replaced by {e exactly} [--__complete=ARG]. Note + that this can happen after the [--] token, this is the reason + why we have an explicit [--__complete] argument in [Sys.argv.(1)]: + it indicates the command line parser must operate in a special mode.}}} +{- The tool responds by writing on standard output a list of + completion directives which match the [completions] rule of the grammar + given below.} +{- 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.}} + +The following ABNF grammar is described using the notations of +{{:https://www.rfc-editor.org/rfc/rfc5234}RFC 5234} and +{{:https://www.rfc-editor.org/rfc/rfc7405}RFC 7405}. A few constraints +are not expressed by the grammar: + +{ul +{- Except in the [completion] rule, the byte stream may contain ANSI escape + sequences introduced by the byte [0x1B].} +{- After stripping the ANSI escape sequences, the resulting byte stream must + be valid UTF-8 text.}} + +{@abnf[ +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 +]} + +The semantics of directives is as follows: + +{ul +{- A [message] 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 [message-end] as it is used to signal the + end of the message. Messages should be reported in the order they + are received.} +{- A [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, this is a string that + defines what the requested [ARG] value can be replaced with. It is + followed by an [item_doc], multi-line ANSI styled text which cannot + have a line that is exactly made of the text [item-end] as it is + used to signal the end of the item.} +{- A [file] directive indicates that the script should add existing + files staring with [ARG] to completion values.} +{- A [dir] directive indicates that the script should add existing + directories starting with [ARG] to completion values.} +{- A [restart] directive indicates that the script should restart + shell completion as if the command line was starting after the leftmost + [--] disambiguation token. The directive never gets emited if + there is no [--] on the command line.}} + +You can easily inspect the completions of any cmdliner based tool by +invoking it like the protocol suggests. For example for the [cmdliner] +tool itself: + +{@shell[ +cmdliner --__complete --__complete= +]} + +{1:error_message_styling Error message ANSI styling} + +Since Cmdliner 2.0 error messages printed on [stderr] use styled text +with ANSI escapes unless one of the following conditions is met: + +{ul +{- The [NO_COLOR] environment variable is set and different + from the empty string. Yes, even if you have [NO_COLOR=false], that's + what the particularly dumb {:https://no-color.org} standard says.} +{- The [TERM] environment variable is [dumb].} +{- The [TERM] environment variable is unset and {!Sys.backend_type} is + not [Other "js_of_ocaml"]. Yes, browser consoles support + ANSI escapes. Yes, you can run Cmdliner in your browser.}} + +{1:legacy_prefix_specification Legacy prefix specification} + +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. {b However the scripts should be fixed: this +escape hatch will be removed in the future.} + +The [CMDLINER_LEGACY_PREFIX=true] escape hatch should not be used for +interactive tool interaction. In particular the behaviour of Cmdliner +completion support under this setting is undefined. diff --git a/cmdliner/_doc-dir/odoc-pages/cookbook.mld b/cmdliner/_doc-dir/odoc-pages/cookbook.mld new file mode 100644 index 00000000..e1486173 --- /dev/null +++ b/cmdliner/_doc-dir/odoc-pages/cookbook.mld @@ -0,0 +1,720 @@ +{0 [Cmdliner] cookbook} + +A few recipes and starting {{!blueprints}blueprints} to describe your +command lines with {!Cmdliner}. + +{b Note.} Some of the code snippets here assume they are done after: +{[ +open Cmdliner +open Cmdliner.Term.Syntax +]} + +{1:tips Tips and pitfalls} + +Command line interfaces are a rather crude and inexpressive user +interaction medium. It is tempting to try to be nice to users in +various ways but this often backfires in confusing context sensitive +behaviours. Here are a few tips and Cmdliner features you {b should +rather not use}. + +{2:tip_avoid_default_command Avoid default commands in groups} + +Command {{!Cmdliner.Cmd.group}groups} can have a default command, that +is be of the form [tool [CMD]]. Except perhaps at the top level of +your tool, it's better to avoid them. They increase command line +parsing ambiguities. + +In particular if the default command has positional arguments, users +are forced to use the {{!cli.posargs}disambiguation token [--]} to +specify them so that they can be distinguished from command +names. For example: + +{@sh[ +tool -- file … +]} + +One thing that is acceptable is to have a default command that simply +{{!cmds_show_docs}shows documentation} for the group of subcommands as +this not interfere with tool operation. + +{2:tip_avoid_default_option_values Avoid default option values} + +Optional arguments {{!Cmdliner.Arg.opt}with values} can have a default +value, that is be of the form [--opt[=VALUE]]. In general it is better +to avoid them as they lead to context sensitive command lines +specifications and surprises when users refine invocations. For examples +suppose you have the synopsis + +{@sh[ +tool --opt[=VALUE] [FILE] +]} + +Trying to refine the following invocation to add a [FILE] parameter is +error prone and painful: + +{@sh[ +tool --opt +]} + +There is more than one way but the easiest way is to specify: +{@sh[ +tool --opt -- FILE +]} +which is not obvious unless you have [tool]'s cli hard wired in your +brain. This would have been a careless refinement if [--opt] did not +have a default option value. + +{2:tip_avoid_required_opt Avoid required optional arguments} + +Cmdliner allows to define required optional arguments. Avoid doing +this, it's a contradiction in the terms. In command line interfaces +optional arguments are defined to be… optional, not doing so is +surprising for your users. Use required positional arguments if +arguments are required by your command invocation. + +Required optional arguments can be useful though if your tool is not +meant to be invoked manually but rather through scripts and has many +required arguments. In this case they become a form of labelled +arguments which can make invocations easier to understand. + +{2:tip_avoid_manpages Avoid making manpages your main documentation} + +Unless your tool is very simple, avoid making manpages the main +documentation medium of your tool. The medium is rather limited and +even though you can convert them to HTML, its cross references +capabilities are rather limited which makes discussing your tool +online more difficult. + +Keep information in manpages to the minimum needed to operate your +tool without having to leave the terminal too much and defer reference +manuals, conceptual information and tutorials to a more evolved medium +like HTML. + +{2:tip_migrating Migrating from other conventions} + +If you are porting your command line parsing to [Cmdliner] and that +you have conventions that clash with [Cmdliner]'s ones but you need to +preserve backward compatibility, one way of proceeding is to +pre-process {!Sys.argv} into a new array of the right shape before +giving it to command {{!Cmdliner.Cmd.section-eval}evaluation +functions} via the [?argv] optional argument. + +These are two common cases: + +{ul +{- Long option names with a single dash like [-warn-error]. In this + case simply prefix an additional [-] to these arguments when they + occur in {!Sys.argv} before the [--] argument; after it, all arguments are + positional and to be treated literally.} +{- Long option names with a single letter like [--X]. In this + case simply chop the first [-] to make it a short option when they + occur in {!Sys.argv} before the [--] argument; after it all arguments are + positional and to be treated literally.}} + +{2:tip_src_structure Source code structure} + +In general Cmdliner wants you to see your tools as regular OCaml functions +that you make available to the shell. This means adopting the following +source structure: + +{[ +(* Implementation of your command. Except for exit codes does not deal with + command line interface related matters and is independent from + Cmdliner. *) + +let exit_ok = 0 +let tool … = …; exit_ok + +(* Command line interface. Adds metadata to your [tool] function arguments + so that they can be parsed from the command line and documented. *) + +open Cmdliner +open Cmdliner.Term.Syntax + +let cmd = … (* Has a term that invokes [tool] *) +let main () = Cmd.eval' cmd +let () = if !Sys.interactive then () else exit (main ()) +]} + +In particular it is good for your readers' understanding that your +program has a single point where it {!Stdlib.exit}s. This structure is +also useful for playing with your program in the OCaml toplevel +(REPL), you can invoke its [main] function without having the risk of it +[exit]ing the toplevel. + +If your tool named [tool] is growing into multiple commands which +have a lot of definitions it is advised to: +{ul +{- Gather command line definition commonalities such as argument + converters or common options in a module called [Tool_cli].} +{- Define each command named [name] in a separate module [Cmd_name] which + exports its command as a [val cmd : int Cmd.t] value.} +{- Gather the commands with {!Cmdliner.Cmd.group} in a source file + called [tool_main.ml].}} + +For an hypothetic tool named [tool] with commands [import], [serve] +and [user], this leads to the following set of files: + +{[ +cmd_import.ml cmd_serve.ml cmd_user.ml tool_cli.ml tool_main.ml +cmd_import.mli cmd_serve.mli cmd_user.mli tool_cli.mli +]} + +The [.mli] files simply export commands: +{[ +val cmd : int Cmdliner.Cmd.t +]} + +And the [tool_main.ml] gathers them with a {!Cmdliner.Cmd.group}: +{[ +let cmd = + let default = Term.(ret (const (`Help (`Auto, None)))) (* show help *) in + Cmd.group (Cmd.info "tool") ~default @@ + [Cmd_import.cmd; Cmd_serve.cmd; Cmd_user.cmd] + +let main () = Cmd.value' cmd +let () = if !Sys.interactive then () else exit (main ()) +]} + +{2:tip_tool_support Installing completions and manpages} + +The [cmdliner] tool can be used to install completion scripts and +manpages for you tool and its subcommands by using the dedicated +{{!page-cli.install_tool_completion}[install tool-completion]} and +{{!page-cli.install_tool_manpages}[install tool-manpages]} subcommands. + +To install both directly (and possibly other support files in the future) +it is more concise to use the [install +tool-support] command. Invoke with [--help] for more information. + +{3:tip_tool_support_with_opam With [opam]} + +If you are installing your package with [opam] for a tool named [tool] +located in the build at the path [$BUILD/tool], you can add the following +instruction after your build instructions in the [build:] field of +your [opam] file (also works if your build system is not using a +[.install] file). + +{@sh[ +build: [ + [ … ] # Your regular build instructions + ["cmdliner" "install" "tool-support" + "--update-opam-install=%{_:name}%.install" + "$BUILD/tool" "_build/cmdliner-install"]] +]} + +You need to specify the path to the built executable, as it cannot be +looked up in the [PATH] yet. Also more than one tool can be specified +in a single invocation and there is a syntax for specifying the actual +tool name if it is renamed on install; see [--help] for more +details. + +If [cmdliner] is only an optional dependency of your package use the +opam filter [{cmdliner:installed}] after the closing bracket of the command +invocation. + +{3:tip_tool_support_with_opam_dune With [opam] and [dune]} + +First make sure your understand the +{{!tip_tool_support_with_opam}above basic instructions} for [opam]. +You then +{{:https://dune.readthedocs.io/en/stable/reference/packages.html#generating-opam-files}need to figure out} how to add the [cmdliner install] instruction to the [build:] +field of the opam file after your [dune] build instructions. For a tool named +[tool] the result should eventually look this: + +{@sh[ +build: [ + [ … ] # Your regular dune build instructions + ["cmdliner" "install" "tool-support" + "--update-opam-install=%{_:name}%.install" + "_build/default/install/bin/tool" {os != "win32"} + "_build/default/install/bin/tool.exe" {os = "win32"} + "_build/cmdliner-install"]] +]} + +{1:conventions Conventions} + +By simply using Cmdliner you are already abiding to a great deal +of command line interface conventions. Here are a few other ones that +are not necessarily enforced by the library but that are good to +adopt for your users. + +{2:conv_use_dash Use ["-"] to specify [stdio] in file path arguments} + +Whenever a command line argument specifies a file path to read or +write you should let the user specify [-] to denote standard in or +standard out, if possible. If you worry about a file sporting this +name, note that the user can always specify it using [./-] for +the argument. + +Very often tools default to [stdin] or [stdout] when a file +input or output is unspecified, here is typical argument definitions +to support these conventions: + +{[ +let infile = + let doc = "$(docv) is the file to read from. Use $(b,-) for $(b,stdin)" in + Arg.(value & opt string "-" & info ["i", "input-file"] ~doc ~docv:"FILE") + +let outfile = + let doc = "$(docv) is the file to write to. Use $(b,-) for $(b,stdout)" in + Arg.(value & opt string "-" & info ["o", "output-file"] ~doc ~docv:"FILE") +]} + +Here is {!Stdlib} based code to read to a string a file or standard +input if [-] is specified: + +{[ +let read_file file = + let read file ic = try Ok (In_channel.input_all ic) with + | Sys_error e -> Error (Printf.sprintf "%s: %s" file e) + in + let binary_stdin () = In_channel.set_binary_mode In_channel.stdin true in + try match file with + | "-" -> binary_stdin (); read file In_channel.stdin + | file -> In_channel.with_open_bin file (read file) + with Sys_error e -> Error e +]} + +Here is {!Stdlib} based code to write a string to a file or standard output +if [-] is specified: + +{[ +let write_file file s = + let write file s oc = try Ok (Out_channel.output_string oc s) with + | Sys_error e -> Error (Printf.sprintf "%s: %s" file e) + in + let binary_stdout () = Out_channel.(set_binary_mode stdout true) in + try match file with + | "-" -> binary_stdout (); write file s Out_channel.stdout + | file -> Out_channel.with_open_bin file (write file s) + with Sys_error e -> Error e +]} + +{2:conv_env_defaults Environment variables as default modifiers} + +Cmdliner has support to back values defined by arguments with +environment variables. The value specified via an environment variable +should never take over an argument specified explicitely on the +command line. The environment variable should be seen as providing +the default value when the argument is absent. + +This is exactly what Cmdliner's support for environment variables does, +see {!env_args} + +{1:args Arguments} + +{2:args_positional How do I define a positional argument?} + +Positional arguments are extracted from the command line using +{{!Cmdliner.Arg.posargs}these combinators} which use zero-based +indexing. The following example extracts the first argument and if +the argument is absent from the command line it evaluates +to ["Revolt!"]. +{[ +let msg = + let doc = "$(docv) is the message to utter." and docv = "MSG" in + Arg.(value & pos 0 string "Revolt!" & info [] ~doc ~docv) +]} + +{2:args_optional How do I define an optional argument?} + +Optional arguments are extracted from the command line using +{{!Cmdliner.Arg.optargs}these combinators}. The actual option +name is defined in the {!Cmdliner.Arg.val-info} structure without +dashes. One character strings define short options, others long +options (see the {{!page-cli.optargs}parsed syntax}). + +The following defines the [-l] and [--loud] options. This is a simple +command line argument without a value also known as a command line {e +flag}. The term [loud] evaluates to [false] when the argument is +absent on the command line and [true] otherwise. + +{[ +let loud = + let doc = "Say the message loudly." in + Arg.(value & flag & info ["l"; "loud"] ~doc) +]} + +The following defines the [-m] and [--message] options. The term [msg] evalutes +to ["Revolt!"] when the option is absent on the command line. +{[ +let msg = + let doc = "$(docv) is the message to utter." and docv = "MSG" in + Arg.(value & opt string "Revolt!" & info ["m"; "message"] ~doc ~docv) +]} + +{2:args_required How do I define a required argument?} + +Some of the constraints on the presence of arguments occur when the +specification of arguments is {{!Cmdliner.Arg.argterms}converted} to +terms. The following says that the first positional argument is required: + +{[ +let msg = + let msg = "$(docv) is the message to utter." and docv = "MSG" in + Arg.(required & pos 0 (some string) None & info [] ~absent ~doc ~docv) +]} + +The value [msg] ends up being a term of type [string]. If the argument +is not provided, Cmdliner will automatically bail out during evaluation +with an error message. + +Note that while it is possible to define required positional argument +it is {{!tip_avoid_required_opt}discouraged}. + +{2:args_detect_absent How can I know if an argument was absent?} + +Most {{!Cmdliner.Arg.posargs}positional} and +{{!Cmdliner.Arg.optargs}optional} arguments have a default value. You +can use a [None] for the default argument and the {!Cmdliner.Arg.some} or +{!Cmdliner.Arg.some'} combinators on your argument converter which simply +wrap its result in a [Some]. + +{[ +let msg = + let msg = "$(docv) is the message to utter." in + let absent = "Random quote." in + Arg.(value & pos 0 (some string) None & info [] ~absent ~doc ~docv:"MSG") +]} + +There is more than one way to document the value when it is +absent. See {!args_absent_doc} + +{2:args_absent_doc How do I document absent argument behaviours?} + +There are three ways to document the behaviour when an argument is +unspecified on the command line. + +{ul +{- If you specify a default value in the argument combinator, this value + gets printed in bold using the {{!Cmdliner.Arg.conv_printer}printer} + of the converter.} +{- If you are using the {!Cmdliner.Arg.some'} and {!Cmdliner.Arg.some} + there is an optional [none] argument that allows you to specify + the default value. If you can exhibit this value at definition + point use {!Cmdliner.Arg.some'}, the underlying converter's + {{!Cmdliner.Arg.conv_printer}printer} will be used. If not + you can specify it as a string rendered in bold via {!Cmdliner.Arg.some}.} +{- If you want to describe a more complex, but short, behaviour use + the [~absent] parameter of {!Cmdliner.Arg.val-info}. Using this + parameter overrides the two previous ways. See + {{!args_detect_absent}this} example. }} + +{2:args_completion How can I customize positional and option value completion?} + +Positional argument values and option values are completed according +to the {{!Cmdliner.Arg.argconv}argument converter} you use for defining +the optional or positional argument. + +A couple of predefined argument converter like {!Cmdliner.Arg.path}, +{!Cmdliner.Arg.filepath} and {!Cmdliner.Arg.dirpath} or +{!Cmdliner.Arg.enum} automatically handle this for you. + +If you would like to perform custom or more elaborate context +sensitive completions you can define your own argument converter with +a completion defined with {!Cmdliner.Arg.Completion.make}. + +Here is an example where the first positional argument is completed +with the filenames found in a directory specified via the [--dir] +option (which defaults to the current working directory if unspecified). +{[ +let dir = Arg.(value & opt dirpath "." & info ["d"; "dir"]) +let dir_filenames_conv = + let complete dir ~token = match dir with + | None -> Error "Could not determine directory to lookup" + | Some dir -> + match Array.to_list (Sys.readdir dir) with + | exception Sys_error e -> Error (String.concat ": " [dir; e]) + | fnames -> + let fnames = List.filter (String.starts_with ~prefix:token) fnames in + Ok (List.map Arg.Completion.string fnames) + in + let completion = Arg.Completion.make ~context:dir complete in + Arg.Conv.of_conv ~completion Arg.string + +let pos0 = Arg.(required & pos 0 (some dir_filenames_conv) None & info []) +]} + +Note that when you use [pos0] in a command line definition you also +need to make sure [dir] is part of the term otherwise the context will +always be [None]: + +{[ +let+ pos0 and+ dir and+ … in … +]} + +{1:envs Environment variables} + +{2:env_args How can environment variables define defaults?} + +As mentioned in {!conv_env_defaults}, any non-required argument can be +defined by an environment variable when absent. This works by +specifying the [env] argument in the argument's {!Cmdliner.Arg.val-info} +information. For example: + +{[ +let msg = + let doc = "$(docv) is the message to utter." and docv = "MSG" in + let env = Cmd.Env.info "MESSAGE" in + Arg.(value & pos 0 string "Revolt!" & info [] ~env ~doc ~docv) +]} + +When the first positional argument is absent it takes the default +value ["Revolt!"], unless the [MESSAGE] variable is defined in +the environment in which case it takes its value. + +Cmdliner handles the environment variable lookup for you. By using the +[msg] term in your command definition all this gets automatically +documented in the tool help. + +{2:env_cmd How do I document environment variables influencing a command?} + +Environment variable that are used to change {{!env_args}argument +defaults} automatically get documented in a command's man page when +you use the argument's term in the command's term. + +However if your command implementation looks up other variables and you +wish to document them in the command's man page, use the [envs] +argument of {!Cmdliner.Cmd.val-info} or the [docs_env] argument +of {!Cmdliner.Arg.val-info}. + +This documents in the {!Cmdliner.Manpage.s_environment} manual section +of [tool] that [EDITOR] is looked up to find the tool to invoke to +edit the files: + +{[ +let editor_env = "EDITOR" +let tool … = … Sys.getenv_opt editor_env +let cmd = + let env = Cmd.Env.info editor_env ~doc:"The editor used to edit files." in + Cmd.make (Cmd.info "tool" ~envs:[env]) @@ + … +]} + +{1:cmds Commands} + +{2:cmds_exit_code_docs How do I document command exit codes?} + +Exit codes are documentd by {!Cmdliner.Cmd.Exit.type-info} values and +must be given to the command's {!Cmdliner.Cmd.type-info} value via the +[exits] optional arguments. For example: + +{[ +let conf_not_found = 1 +let tool … = +let tool_cmd = + let exits = + Cmd.Exit.info conf_not_found "if no configuration could be found." :: + Cmd.Exit.defaults + in + Cmd.make (Cmd.info "mycmd" ~exits) @@ + … +]} + +{2:cmds_show_docs How do I show help in a command group's default?} + +While it is usually {{!tip_avoid_default_command}not advised} to have a default +command in a group, just showing docs is acceptable. A term can request +Cmdliner's generated help by using {!Cmdliner.Term.val-ret}: +{[ +let group_cmd = + let default = Term.(ret (const (`Help (`Auto, None)))) (* show help *) in + Cmd.group (Cmd.info "group") ~default @@ + [first_cmd; second_cmd] +]} + +{2:cmds_which_eval Which [Cmd] evaluation function should I use?} + +There are (too) many {{!Cmdliner.Cmd.section-eval}command evaluation} +functions. They have grown organically in a rather ad-hoc manner. Some +of these are there for backwards compatibility reasons and advanced +usage for complex tools. + +Here are the main ones to use and why you may want to use them which +essentially depends on how you want to handle errors and exit codes +in your tool function. + +{ul +{- {!Cmdliner.Cmd.val-eval}. This forces your tool function to return [()]. + The evaluation function always returns an exit code of [0] unless a + command line parsing error occurs.} +{- {!Cmdliner.Cmd.eval'}. {b Recommended}. This forces your tool function to + return an exit code [exit] which is returned by the evaluation function + unless a command line parsing error occurs. This is the recommended + function to use as it forces you to think about how to report errors and + design useful exit codes for users.} +{- {!Cmdliner.Cmd.eval_result} is akin to {!Cmdliner.Cmd.val-eval} except + it forces your function to return either [Ok ()] or [Error msg]. + The evaluation function returns with exit code [0] unless [Error msg] is + computed in which case [msg] is printed on the error stream prefixed by the + executable name and the evaluation function returns with + exit code {!Cmdliner.Cmd.Exit.some_error}.} +{- {!Cmdliner.Cmd.eval_result'} is akin to {!Cmdliner.Cmd.eval_result}, except + the [Ok] case carries an exit code which is returned by the evaluation + function.}} + +{2:cmds_howto_complete How can my tool support command line completion?} + +The command line interface manual has all +{{!page-cli.cli_completion}the details} and +{{!page-cli.install_tool_completion} specific instructions} for +complementing your tool install. See also {!tip_tool_support}. + +{2:cmds_listing How can I list all the commands of my tool?} + +In a shell the invocation [cmdliner tool-commands $TOOL] lists every +command of the tool $TOOL. + +{2:cmds_errmsg_styling How can I suppress error message styling?} + +Since Cmdliner 2.0, error message printed on [stderr] use styled text +with ANSI escapes. Styled text is disabled if one of the conditions +mentioned {{!page-cli.error_message_styling}here} is met. + +If you want to be more aggressive in suppressing them you can use the +[err] formatter argument of {{!Cmdliner.Cmd.section-eval}command +evaluation} functions with a suitable formatter on which a function +like +{{:https://erratique.ch/software/more/doc/More/Fmt/index.html#val-strip_styles} +this one} has been applied that automatically strips the styling. + +{1:manpage Manpages} + +{2:manpage_hide How do I prevent an item from being automatically listed?} + +In general it's not a good idea to hide stuff from your users but in +case an item needs to be hidden you can use the special +{!Cmdliner.Manpage.s_none} section name. This ensures the item does +not get listed in any section. + +{[ +let secret = Arg.(value & flag & info ["super-secret"] ~docs:Manpage.s_none) +]} + +{2:manpage_synopsis How can I write a better command synopsis section?} + +Define the {!Cmdliner.Manpage.s_synopsis} section in the manpage of +your command. It takes over the one generated by Cmdliner. For example: + +{[ +let man = [ + `S Manpage.s_synopsis; + `P "$(cmd) $(b,--) $(i,TOOL) [$(i,ARG)]…"; `Noblank; + `P "$(cmd) $(i,COMMAND) …"; + `S Manpage.s_description; + `P "Without a command $(cmd) invokes $(i,TOOL)"; ] +]} + +{2:manpage_install How can I install all the manpages of my tool?} + +The command line interface manual +{{!page-cli.install_tool_manpages}the details} on how to install the manpages +of your tool and its subcommands. See also {!tip_tool_support}. + +{1:blueprints Blueprints} + +These blueprints when copied to a [src.ml] file can be compiled and run with: + +{@sh[ +ocamlfind ocamlopt -package cmdliner -linkgpkg src.ml +./a.out --help +]} + +More concrete examples can be found on the {{!page-examples}examples page} +and the {{!page-tutorial}tutorial} may help too. + +These examples follow a conventional {!tip_src_structure}. + +{2:blueprint_min Minimal} + +A minimal example. + +{@ocaml name=blueprint_min.ml[ +let tool () = Cmdliner.Cmd.Exit.ok + +open Cmdliner +open Cmdliner.Term.Syntax + +let cmd = + Cmd.make (Cmd.info "TODO" ~version:"v2.0.0") @@ + let+ unit = Term.const () in + tool unit + +let main () = Cmd.eval' cmd +let () = if !Sys.interactive then () else exit (main ()) +]} + +{2:blueprint_tool A simple tool} + +This is a tool that has a flag, an optional positional argument for +specifying an input file. It also responds to the [--version] option. + +{@ocaml name=blueprint_tool.ml[ +let exit_todo = 1 +let tool ~flag ~infile = exit_todo + +open Cmdliner +open Cmdliner.Term.Syntax + +let flag = Arg.(value & flag & info ["flag"] ~doc:"The flag") +let infile = + let doc = "$(docv) is the input file. Use $(b,-) for $(b,stdin)." in + Arg.(value & pos 0 string "-" & info [] ~doc ~docv:"FILE") + +let cmd = + let doc = "The tool synopsis is TODO" in + let man = [ + `S Manpage.s_description; + `P "$(cmd) does TODO" ] + in + let exits = + Cmd.Exit.info exit_todo ~doc:"When there is stuff todo" :: + Cmd.Exit.defaults + in + Cmd.make (Cmd.info "TODO" ~version:"v2.0.0" ~doc ~man ~exits) @@ + let+ flag and+ infile in + tool ~flag ~infile + +let main () = Cmd.eval' cmd +let () = if !Sys.interactive then () else exit (main ()) +]} + +{2:blueprint_cmds A tool with subcommands} + +This is a tool with two subcommands [hey] and [ho]. If your tools +grows many subcommands you may want to follow these +{{!tip_src_structure}source code conventions}. + +{@ocaml name=blueprint_cmds.ml[ +let hey () = Cmdliner.Cmd.Exit.ok +let ho () = Cmdliner.Cmd.Exit.ok + +open Cmdliner +open Cmdliner.Term.Syntax + +let flag = Arg.(value & flag & info ["flag"] ~doc:"The flag") +let infile = + let doc = "$(docv) is the input file. Use $(b,-) for $(b,stdin)." in + Arg.(value & pos 0 file "-" & info [] ~doc ~docv:"FILE") + +let hey_cmd = + let doc = "The hey command synopsis is TODO" in + Cmd.make (Cmd.info "hey" ~doc) @@ + let+ unit = Term.const () in + ho () + +let ho_cmd = + let doc = "The ho command synopsis is TODO" in + Cmd.make (Cmd.info "ho" ~doc) @@ + let+ unit = Term.const () in + ho unit + +let cmd = + let doc = "The tool synopsis is TODO" in + Cmd.group (Cmd.info "TODO" ~version:"v2.0.0" ~doc) @@ + [hey_cmd; ho_cmd] + +let main () = Cmd.eval' cmd +let () = if !Sys.interactive then () else exit (main ()) +]} diff --git a/cmdliner/_doc-dir/odoc-pages/examples.mld b/cmdliner/_doc-dir/odoc-pages/examples.mld old mode 100755 new mode 100644 index a437b9ce..412d6025 --- a/cmdliner/_doc-dir/odoc-pages/examples.mld +++ b/cmdliner/_doc-dir/odoc-pages/examples.mld @@ -1,9 +1,10 @@ {0 Examples} The examples are self-contained, cut and paste them in a file to play -with them. +with them. See also the suggested {{!page-cookbook.tip_src_structure}source +code structure} and program {{!page-cookbook.blueprints}blueprints}. -{1:exrm A [rm] command} +{1:example_rm A [rm] command} We define the command line interface of an [rm] command with the synopsis: @@ -25,20 +26,21 @@ line and we just take the {!Cmdliner.Arg.last} one to define our term value. If there is no occurrence the last value of the default list [[Always]] is taken. This means the default prompt behaviour is [Always]. -{[ +{@ocaml name=example_rm.ml[ (* Implementation of the command, we just print the args. *) type prompt = Always | Once | Never let prompt_str = function | Always -> "always" | Once -> "once" | Never -> "never" -let rm prompt recurse files = +let rm ~prompt ~recurse files = Printf.printf "prompt = %s\nrecurse = %B\nfiles = %s\n" (prompt_str prompt) recurse (String.concat ", " files) (* Command line interface *) open Cmdliner +open Cmdliner.Term.Syntax let files = Arg.(non_empty & pos_all file [] & info [] ~docv:"FILE") let prompt = @@ -63,32 +65,34 @@ let recursive = let doc = "Remove directories and their contents recursively." in Arg.(value & flag & info ["r"; "R"; "recursive"] ~doc) -let cmd = +let rm_cmd = let doc = "Remove files or directories" in let man = [ `S Manpage.s_description; - `P "$(tname) removes each specified $(i,FILE). By default it does not + `P "$(cmd) removes each specified $(i,FILE). By default it does not remove directories, to also remove them and their contents, use the option $(b,--recursive) ($(b,-r) or $(b,-R))."; `P "To remove a file whose name starts with a $(b,-), for example $(b,-foo), use one of these commands:"; - `Pre "$(mname) $(b,-- -foo)"; `Noblank; - `Pre "$(mname) $(b,./-foo)"; - `P "$(tname) removes symbolic links, not the files referenced by the + `Pre "$(cmd) $(b,-- -foo)"; `Noblank; + `Pre "$(cmd) $(b,./-foo)"; + `P "$(cmd.name) removes symbolic links, not the files referenced by the links."; `S Manpage.s_bugs; `P "Report bugs to ."; `S Manpage.s_see_also; `P "$(b,rmdir)(1), $(b,unlink)(2)" ] in - let info = Cmd.info "rm" ~version:"v1.3.0" ~doc ~man in - Cmd.v info Term.(const rm $ prompt $ recursive $ files) + Cmd.make (Cmd.info "rm" ~version:"v2.0.0" ~doc ~man) @@ + let+ prompt and+ recursive and+ files in + rm ~prompt ~recurse:recursive files -let main () = exit (Cmd.eval cmd) -let () = main () +let main () = Cmd.eval rm_cmd +let () = if !Sys.interactive then () else exit (main ()) ]} -{1:excp A [cp] command} +{1:example_cp A [cp] command} We define the command line interface of a [cp] command with the synopsis: + {v cp [OPTION]… SOURCE… DEST v} @@ -97,16 +101,16 @@ The [DEST] argument must be a directory if there is more than one [SOURCE]. This constraint is too complex to be expressed by the combinators of {!Cmdliner.Arg}. -Hence we just give [DEST] the {!Cmdliner.Arg.string} type and verify the -constraint at the beginning of the implementation of [cp]. If the +Hence we just give [DEST] the {!Cmdliner.Arg.string} type and verify +the constraint at the beginning of the implementation of [cp]. If the constraint is unsatisfied we return an [`Error] result. By using -{!Cmdliner.Term.val-ret} on the lifted result [cp_t] of [cp], -[Cmdliner] handles the error reporting. +{!Cmdliner.Term.val-ret} on the command's term for [cp], [Cmdliner] +handles the error reporting. -{[ +{@ocaml name=example_cp.ml[ (* Implementation, we check the dest argument and print the args *) -let cp verbose recurse force srcs dest = +let cp ~verbose ~recurse ~force srcs dest = let many = List.length srcs > 1 in if many && (not (Sys.file_exists dest) || not (Sys.is_directory dest)) then `Error (false, dest ^ ": not a directory") else @@ -117,6 +121,7 @@ let cp verbose recurse force srcs dest = (* Command line interface *) open Cmdliner +open Cmdliner.Term.Syntax let verbose = let doc = "Print file names as they are copied." in @@ -140,24 +145,25 @@ let dest = let docv = "DEST" in Arg.(required & pos ~rev:true 0 (some string) None & info [] ~docv ~doc) -let cmd = +let cp_cmd = let doc = "Copy files" in let man_xrefs = - [ `Tool "mv"; `Tool "scp"; `Page ("umask", 2); `Page ("symlink", 7) ] + [`Tool "mv"; `Tool "scp"; `Page ("umask", 2); `Page ("symlink", 7)] in - let man = - [ `S Manpage.s_bugs; - `P "Email them to ."; ] + let man = [ + `S Manpage.s_bugs; + `P "Email them to ."; ] in - let info = Cmd.info "cp" ~version:"v1.3.0" ~doc ~man ~man_xrefs in - Cmd.v info Term.(ret (const cp $ verbose $ recurse $ force $ srcs $ dest)) + Cmd.make (Cmd.info "cp" ~version:"v2.0.0" ~doc ~man ~man_xrefs) @@ + Term.ret @@ + let+ verbose and+ recurse and+ force and+ srcs and+ dest in + cp ~verbose ~recurse ~force srcs dest - -let main () = exit (Cmd.eval cmd) -let () = main () +let main () = Cmd.eval cp_cmd +let () = if !Sys.interactive then () else exit (main ()) ]} -{1:extail A [tail] command} +{1:example_tail A [tail] command} We define the command line interface of a [tail] command with the synopsis: @@ -180,7 +186,7 @@ the option [--follow] evaluates to [None] if [--follow] is absent from the command line, to [Some Descriptor] if present but without a value and to [Some v] if present with a value [v] specified. -{[ +{@ocaml name=example_tail.ml[ (* Implementation of the command, we just print the args. *) type loc = bool * int @@ -193,7 +199,7 @@ let loc_str (rev, k) = if rev then str "%d" k else str "+%d" k let follow_str = function Name -> "name" | Descriptor -> "descriptor" let verb_str = function Verbose -> "verbose" | Quiet -> "quiet" -let tail lines follow verb pid files = +let tail ~lines ~follow ~verb ~pid files = Printf.printf "lines = %s\nfollow = %s\nverb = %s\npid = %s\nfiles = %s\n" (loc_str lines) (opt_str follow_str follow) (verb_str verb) @@ -202,17 +208,18 @@ let tail lines follow verb pid files = (* Command line interface *) open Cmdliner +open Cmdliner.Term.Syntax let loc_arg = - let parse s = + let parser s = try if s <> "" && s.[0] <> '+' then Ok (true, int_of_string s) else Ok (false, int_of_string (String.sub s 1 (String.length s - 1))) - with Failure _ -> Error (`Msg "unable to parse integer") + with Failure _ -> Error "unable to parse integer" in - let print ppf p = Format.fprintf ppf "%s" (loc_str p) in - Arg.conv ~docv:"N" (parse, print) + let pp ppf p = Format.fprintf ppf "%s" (loc_str p) in + Arg.Conv.make ~docv:"N" ~parser ~pp () let lines = let doc = "Output the last $(docv) lines or use $(i,+)$(docv) to start \ @@ -246,27 +253,27 @@ let pid = let files = Arg.(value & (pos_all non_dir_file []) & info [] ~docv:"FILE") -let cmd = +let tail_cmd = let doc = "Display the last part of a file" in let man = [ `S Manpage.s_description; - `P "$(tname) prints the last lines of each $(i,FILE) to standard output. If - no file is specified reads standard input. The number of printed + `P "$(cmd) prints the last lines of each $(i,FILE) to standard output. + If no file is specified reads standard input. The number of printed lines can be specified with the $(b,-n) option."; `S Manpage.s_bugs; `P "Report them to ."; `S Manpage.s_see_also; `P "$(b,cat)(1), $(b,head)(1)" ] in - let info = Cmd.info "tail" ~version:"v1.3.0" ~doc ~man in - Cmd.v info Term.(const tail $ lines $ follow $ verb $ pid $ files) + Cmd.make (Cmd.info "tail" ~version:"v2.0.0" ~doc ~man) @@ + let+ lines and+ follow and+ verb and+ pid and+ files in + tail ~lines ~follow ~verb ~pid files - -let main () = exit (Cmd.eval cmd) -let () = main () +let main () = Cmd.eval tail_cmd +let () = if !Sys.interactive then () else exit (main ()) ]} -{1:exdarcs A [darcs] command} +{1:example_darcs A [darcs] command} We define the command line interface of a [darcs] command with the synopsis: @@ -280,10 +287,8 @@ each command. To avoid having to pass them individually to each command we gather them in a record of type [copts]. By lifting the record constructor [copts] into the term [copts_t] we now have a term that we can pass to the commands to stand for an argument of type -[copts]. These options are documented in a section called [COMMON -OPTIONS], since we also want to put [--help] and [--version] in this -section, the term information of commands makes a judicious use of the -[sdocs] parameter of {!Cmdliner.Term.val-info}. +[copts]. These options are documented in the section +{!Cmdliner.Manpage.s_common_options}. The [help] command shows help about commands or other topics. The help shown for commands is generated by [Cmdliner] by making an appropriate @@ -291,9 +296,9 @@ use of {!Cmdliner.Term.val-ret} on the lifted [help] function. If the program is invoked without a command we just want to show the help of the program as printed by [Cmdliner] with [--help]. This is -done by the [default_cmd] term. +done by the [default] term. -{[ +{@ocaml name=example_darcs.ml[ (* Implementations, just print the args. *) type verb = Normal | Quiet | Verbose @@ -321,16 +326,18 @@ let help copts man_format cmds topic = match topic with | None -> `Help (`Pager, None) (* help about the program. *) | Some topic -> let topics = "topics" :: "patterns" :: "environment" :: cmds in - let conv, _ = Cmdliner.Arg.enum (List.rev_map (fun s -> (s, s)) topics) in - match conv topic with - | `Error e -> `Error (false, e) - | `Ok t when t = "topics" -> List.iter print_endline topics; `Ok () - | `Ok t when List.mem t cmds -> `Help (man_format, Some t) - | `Ok t -> + let conv = Cmdliner.Arg.enum (List.rev_map (fun s -> (s, s)) topics) in + let parse = Cmdliner.Arg.Conv.parser conv in + match parse topic with + | Error e -> `Error (false, e) + | Ok t when t = "topics" -> List.iter print_endline topics; `Ok () + | Ok t when List.mem t cmds -> `Help (man_format, Some t) + | Ok t -> let page = (topic, 7, "", "", ""), [`S topic; `P "Say something";] in `Ok (Cmdliner.Manpage.print man_format Format.std_formatter page) open Cmdliner +open Cmdliner.Term.Syntax (* Help sections common to all commands *) @@ -338,9 +345,9 @@ let help_secs = [ `S Manpage.s_common_options; `P "These options are common to all commands."; `S "MORE HELP"; - `P "Use $(mname) $(i,COMMAND) --help for help on a single command.";`Noblank; - `P "Use $(mname) $(b,help patterns) for help on patch matching."; `Noblank; - `P "Use $(mname) $(b,help environment) for help on environment variables."; + `P "Use $(tool) $(i,COMMAND) --help for help on a single command.";`Noblank; + `P "Use $(tool) $(b,help patterns) for help on patch matching."; `Noblank; + `P "Use $(tool) $(b,help environment) for help on environment variables."; `S Manpage.s_bugs; `P "Check bug reports at http://bugs.example.org.";] (* Options common to all commands *) @@ -360,7 +367,7 @@ let copts_t = Arg.(last & vflag_all [Normal] [quiet; verbose]) in let prehook = - let doc = "Specify command to run before this $(mname) command." in + let doc = "Specify command to run before this $(tool) command." in Arg.(value & opt (some string) None & info ["prehook"] ~docs ~doc) in Term.(const copts $ debug $ verb $ prehook) @@ -382,8 +389,9 @@ let initialize_cmd = existing files and subdirectories become …"; `Blocks help_secs; ] in - let info = Cmd.info "initialize" ~doc ~sdocs ~man in - Cmd.v info Term.(const initialize $ copts_t $ repodir) + Cmd.make (Cmd.info "initialize" ~doc ~sdocs ~man) @@ + let+ copts_t and+ repodir in + initialize copts_t repodir let record_cmd = let pname = @@ -409,12 +417,12 @@ let record_cmd = let man = [`S Manpage.s_description; `P "Creates a patch from changes in the working tree. If you specify - a set of files …"; + a set of files…"; `Blocks help_secs; ] in - let info = Cmd.info "record" ~doc ~sdocs ~man in - Cmd.v info - Term.(const record $ copts_t $ pname $ author $ all $ ask_deps $ files) + Cmd.make (Cmd.info "record" ~doc ~sdocs ~man) @@ + let+ copts_t and+ pname and+ author and+ all and+ ask_deps and+ files in + record copts_t pname author all ask_deps files let help_cmd = let topic = @@ -427,17 +435,19 @@ let help_cmd = `P "Prints help about darcs commands and other subjects…"; `Blocks help_secs; ] in - let info = Cmd.info "help" ~doc ~man in - Cmd.v info - Term.(ret (const help $ copts_t $ Arg.man_format $ Term.choice_names $ - topic)) + Cmd.make (Cmd.info "help" ~doc ~man) @@ + Term.ret @@ + let+ copts_t and+ man_format = Arg.man_format + and+ choice_names = Term.choice_names and+ topic in + help copts_t man_format choice_names topic let main_cmd = let doc = "a revision control system" in let man = help_secs in - let info = Cmd.info "darcs" ~version:"v1.3.0" ~doc ~sdocs ~man in + let info = Cmd.info "darcs" ~version:"v2.0.0" ~doc ~sdocs ~man in let default = Term.(ret (const (fun _ -> `Help (`Pager, None)) $ copts_t)) in Cmd.group info ~default [initialize_cmd; record_cmd; help_cmd] -let () = exit (Cmd.eval main_cmd) +let main () = Cmd.eval main_cmd +let () = if !Sys.interactive then () else exit (main ()) ]} diff --git a/cmdliner/_doc-dir/odoc-pages/index.mld b/cmdliner/_doc-dir/odoc-pages/index.mld old mode 100755 new mode 100644 index db93924d..7e42c5c0 --- a/cmdliner/_doc-dir/odoc-pages/index.mld +++ b/cmdliner/_doc-dir/odoc-pages/index.mld @@ -1,12 +1,13 @@ -{0 Cmdliner {%html: v1.3.0%}} +{0 Cmdliner {%html: v2.0.0%}} -[Cmdliner] provides a simple and compositional mechanism +Cmdliner provides a simple and compositional mechanism to convert command line arguments to OCaml values and pass them to your functions. -The library automatically handles syntax errors, help messages and -UNIX man page generation. It supports programs with single or multiple -commands (like [git]) and respect most of the +The library automatically handles command line completion, syntax +errors, help messages and UNIX man page generation. It supports +programs with single or multiple commands (like [git]) and respect +most of the {{:http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html} POSIX} and {{:http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html} @@ -17,18 +18,29 @@ GNU} conventions. The following manuals are available. {ul -{- The {{!page-tutorial}tutorial} gets you through the steps to write - your first command line interface with Cmdliner.} -{- The {{!page-cli}Command line interface manual} describes how command - lines and environment variables are parsed by Cmdliner.} -{- {{!page-tool_man}Tool man pages} describes how Cmdliner generates - man pages for your tools and how you can format them.} -{- The {{!page-examples}examples page} has a few annoted examples that - show to express the command line interface of a few classic tools with - Cmdliner}} +{- The {{!page-tutorial}tutorial} makes you write your first command line + interface with Cmdliner.} +{- The {{!page-cookbook}cookbook} has a few off-the-shelf recipes, + tips about {{!page-cookbook.tip_src_structure}source code structure}, + and {{!page-cookbook.blueprints}blueprints} to define your command lines + with Cmdliner.} +{- The {{!page-cli}command line interface manual} describes how command + lines and environment variables are parsed by Cmdliner and how command line + completion is performed. This can be communicated to the users of your + tools.} +{- The {{!page-tool_man}tool man page} manual describes how + Cmdliner generates man pages for your tools and their commands and how + you can format them.} +{- The {{!page-examples}examples page} has examples of a some + classic UNIX tools with their command line interface implemented by + Cmdliner.}} -{1:api API} +{1:library Library [cmdliner]} +{!modules: Cmdliner} {!modules: -Cmdliner +Cmdliner.Arg +Cmdliner.Cmd +Cmdliner.Manpage +Cmdliner.Term } diff --git a/cmdliner/_doc-dir/odoc-pages/tool_man.mld b/cmdliner/_doc-dir/odoc-pages/tool_man.mld old mode 100755 new mode 100644 index 7029d346..e6836c00 --- a/cmdliner/_doc-dir/odoc-pages/tool_man.mld +++ b/cmdliner/_doc-dir/odoc-pages/tool_man.mld @@ -1,11 +1,14 @@ {0:tool_man Tool man pages} -{1:manual Manual} +See also the {{!page-cli.help}section} about man pages in the command +line interface manual. + +{1:manual Man page generation} Man page sections for a command are printed in the order specified by -manual as given to {!Cmdliner.Cmd.val-info}. Unless specified -explicitly in the command's manual the following sections are -automatically created and populated for you: +the [man] value given to {!Cmdliner.Cmd.val-info}. Unless +specified explicitly in the [man] value the following sections +are automatically created and populated for you: {ul {- {{!Cmdliner.Manpage.s_name}[NAME]} section.} @@ -21,11 +24,10 @@ they respectively mention in their [docs] argument: both the [docv] and [doc] string is specified by {!Cmdliner.Arg.val-info}.} {- For optional arguments, see {!Cmdliner.Arg.val-info}.} {- For exit statuses, see {!Cmdliner.Cmd.Exit.val-info}.} -{- For environment variables, see - {!Cmdliner.Arg.val-env_var} and {!Cmdliner.Cmd.Env.val-info}.}} +{- For environment variables, see {!Cmdliner.Cmd.Env.val-info}.}} If a [docs] section name is mentioned and does not exist in the command's -manual, an empty section is created for it, after which the [doc] strings +[man] value, an empty section is created for it, after which the [doc] strings are inserted, possibly prefixed by boilerplate text (e.g. for {!Cmdliner.Manpage.s_environment} and {!Cmdliner.Manpage.s_exit_status}). @@ -35,7 +37,7 @@ If the created section is: is inserted at the right place in the order specified {{!Cmdliner.Manpage.standard_sections}here}, but after a possible non-standard - section explicitly specified by the command's manual since the latter + section explicitly specified by the command's [man] value since the latter get the order number of the last previously specified standard section or the order of {!Cmdliner.Manpage.s_synopsis} if there is no such section.} {- non-standard, it is inserted before the {!Cmdliner.Manpage.s_commands} @@ -51,20 +53,21 @@ it. {1:doclang Documentation markup language} -Manpage {{!Cmdliner.Manpage.block}blocks} and doc strings support the -following markup language. +Manpage {{!Cmdliner.Manpage.block}blocks} and the doc strings of the +various [info] values support the following markup language. {ul {- Markup directives [$(i,text)] and [$(b,text)], where [text] is raw text respectively rendered in italics and bold.} {- Outside markup directives, context dependent variables of the form - [$(var)] are substituted by marked up data. For example in a term's - man page [$(tname)] is substituted by the term name in bold.} -{- Characters $, (, ) and \ can respectively be escaped by \$, \(, \) - and \\ (in OCaml strings this will be ["\\$"], ["\\("], ["\\)"], - ["\\\\"]). Escaping $ and \ is mandatory everywhere. Escaping ) is - mandatory only in markup directives. Escaping ( is only here for + [$(var)] are substituted by marked up data. For example in a command + man page [$(cmd)] is substituted by the command's invocation in + bold.} +{- Characters '$', '(', ')' and '\' can respectively be escaped by \$, \(, \) + and \\ . In OCaml strings this will be ["\\$"], ["\\("], ["\\)"], + ["\\\\"]. Escaping '$' and '\' is mandatory everywhere. Escaping ')' is + mandatory only in markup directives. Escaping '(' is only here for your symmetric pleasure. Any other sequence of characters starting - with a \ is an illegal character sequence.} + with a '\' is an illegal character sequence.} {- Referring to unknown markup directives or variables will generate errors on standard error during documentation generation.}} diff --git a/cmdliner/_doc-dir/odoc-pages/tutorial.mld b/cmdliner/_doc-dir/odoc-pages/tutorial.mld old mode 100755 new mode 100644 index a950e664..fc3075af --- a/cmdliner/_doc-dir/odoc-pages/tutorial.mld +++ b/cmdliner/_doc-dir/odoc-pages/tutorial.mld @@ -1,82 +1,117 @@ {0:tutorial Tutorial} -{1:started Getting started} +See also the {{!page-cookbook}cookbook}, +{{!page-cookbook.blueprints}blueprints} and +{{!page-examples}examples}. + +{1:terms Commands and terms} With [Cmdliner] your tool's [main] function evaluates a command. A command is a value of type {!Cmdliner.Cmd.t} which gathers a command -name and a term of type {!Cmdliner.Term.t}. A term is an expression to -be evaluated. The type parameter of the term (and the command) +name and a term of type {!Cmdliner.Term.t}. A term represents both a +command line syntax fragment and an expression to be evaluated that +implements your tool. The type parameter of the term (and the command) indicates the type of the result of the evaluation. One way to create terms is by lifting regular OCaml values with {!Cmdliner.Term.const}. Terms can be applied to terms evaluating to -functional values with {!Cmdliner.Term.($)}. +functional values with {!Cmdliner.Term.app}. For example, in a [revolt.ml] file, for the function: -{[ +{@ocaml name=example_revolt1.ml[ let revolt () = print_endline "Revolt!" ]} the term : -{[ +{@ocaml name=example_revolt1.ml[ open Cmdliner -let revolt_t = Term.(const revolt $ const ()) +let revolt_term = Term.app (Term.const revolt) (Term.const ()) ]} is a term that evaluates to the result (and effect) of the [revolt] -function. This term can be attached to a command: +function. This term can be associated to a command: -{[ -let cmd = Cmd.v (Cmd.info "revolt") revolt_t +{@ocaml name=example_revolt1.ml[ +let cmd_revolt = Cmd.make (Cmd.info "revolt") revolt_term ]} and evaluated with {!Cmdliner.Cmd.val-eval}: -{[ -let () = exit (Cmd.eval cmd) +{@ocaml name=example_revolt1.ml[ +let main () = Cmd.eval cmd_revolt +let () = if !Sys.interactive then () else exit (main ()) ]} This defines a command line tool named ["revolt"] (this name will be used in error reporting and documentation generation), without command line arguments, that just prints ["Revolt!"] on [stdout]. -{[ +{@sh[ > ocamlfind ocamlopt -linkpkg -package cmdliner -o revolt revolt.ml > ./revolt Revolt! ]} +{1:term_syntax Term syntax} + +There is a special syntax that uses OCaml's +{{:https://ocaml.org/manual/5.3/bindingops.html}binding operators} for +writing terms which is less error prone when the number of arguments +you want to give to your function grows. In particular it allows you to +easily lift functions which have labels. + +So in fact the program we have just shown above is usually rather +written this way: + +{@ocaml name=example_revolt2.ml[ +let revolt () = print_endline "Revolt!" + +open Cmdliner +open Cmdliner.Term.Syntax + +let cmd_revolt = + Cmd.make (Cmd.info "revolt") @@ + let+ () = Term.const () in + revolt () + +let main () = Cmd.eval cmd_revolt +let () = if !Sys.interactive then () else exit (main ()) +]} + +{1:args_as_terms Command line arguments as terms} + The combinators in the {!Cmdliner.Arg} module allow to extract command line arguments as terms. These terms can then be applied to lifted -OCaml functions to be evaluated. - -Terms corresponding to command line argument data that are part of a -term evaluation implicitly define a command line syntax. We show this -on an concrete example. +OCaml functions to be evaluated. A term that uses terms that correspond +to command line argument implicitely defines a command line syntax +fragment. We show this on an concrete example. In a [chorus.ml] file, consider the [chorus] function that prints repeatedly a given message : -{[ -let chorus count msg = for i = 1 to count do print_endline msg done +{@ocaml name=example_chorus.ml[ +let chorus ~count msg = for i = 1 to count do print_endline msg done ]} we want to make it available from the command line with the synopsis: -{[ +{@sh[ chorus [-c COUNT | --count=COUNT] [MSG] ]} where [COUNT] defaults to [10] and [MSG] defaults to ["Revolt!"]. We first define a term corresponding to the [--count] option: -{[ +{@ocaml name=example_chorus.ml[ +open Cmdliner +open Cmdliner.Term.Syntax + let count = let doc = "Repeat the message $(docv) times." in - Arg.(value & opt int 10 & info ["c"; "count"] ~docv:"COUNT" ~doc) + Arg.(value & opt int 10 & info ["c"; "count"] ~doc ~docv:"COUNT") ]} This says that [count] is a term that evaluates to the value of an @@ -86,14 +121,14 @@ and [docv] are used to generate the option's man page information. The term for the positional argument [MSG] is: -{[ +{@ocaml name=example_chorus.ml[ let msg = let env = let doc = "Overrides the default message to print." in Cmd.Env.info "CHORUS_MSG" ~doc in let doc = "The message to print." in - Arg.(value & pos 0 string "Revolt!" & info [] ~env ~docv:"MSG" ~doc) + Arg.(value & pos 0 string "Revolt!" & info [] ~env ~doc ~docv:"MSG") ]} which says that [msg] is a term whose value is the positional argument @@ -102,39 +137,37 @@ value of the environment variable [CHORUS_MSG] if the argument is unspecified on the command line. Here again [doc] and [docv] are used for the man page information. -The term for executing [chorus] with these command line arguments is : +We can now define a term and command for invoking the [chorus] function +using the {{!term_syntax}term syntax} and the obscure but handy +{{:https://ocaml.org/manual/5.2/bindingops.html#ss%3Aletops-punning} +let-punning} OCaml notation. This also shows that the +value {!Cmdliner.Cmd.val-info} can be given more +information about the term we execute which is notably used to +to generate the tool's man page. -{[ -let chorus_t = Term.(const chorus $ count $ msg) -]} - -We are now ready to define the [main] function of our tool: - -{[ -let cmd = - let doc = "print a customizable message repeatedly" in +{@ocaml name=example_chorus.ml[ +let chorus_cmd = + let doc = "Print a customizable message repeatedly" in let man = [ `S Manpage.s_bugs; `P "Email bug reports to ." ] in - let info = Cmd.info "chorus" ~version:"%‌%VERSION%%" ~doc ~man in - Cmd.v info chorus_t + Cmd.make (Cmd.info "chorus" ~version:"v2.0.0" ~doc ~man) @@ + let+ count and+ msg in + chorus ~count msg -let main () = exit (Cmd.eval cmd) -let () = main () +let main () = Cmd.eval chorus_cmd +let () = if !Sys.interactive then () else exit (main ()) ]} -The [info] value created with {!Cmdliner.Cmd.val-info} gives more -information about the term we execute and is used to generate the -tool's man page. Since we provided a [~version] string, the tool -will automatically respond to the [--version] option by printing this -string. +Since we provided a [~version] string, the tool will automatically +respond to the [--version] option by printing this string. -A tool using {!Cmdliner.Cmd.val-eval} always responds to the [--help] -option by showing the tool's man page generated using the information -you provided with {!Cmdliner.Cmd.val-info} and -{!Cmdliner.Arg.val-info}. Here is the output generated by our -example: +Besides a tool using {!Cmdliner.Cmd.val-eval} always responds to the +[--help] option by showing the tool's man page +{{!page-tool_man.manual}generated} using the information you provided +with {!Cmdliner.Cmd.val-info} and {!Cmdliner.Arg.val-info}. Here is +the manual generated by our example: {v > ocamlfind ocamlopt -linkpkg -package cmdliner -o chorus chorus.ml @@ -189,15 +222,7 @@ is also available in plain text or in the by invoking the program with the option [--help=plain] or [--help=groff]. -For examples of more complex command line definitions look and run -the {{!page-examples}examples}. - -{1:subcommands Sub commands} - -[Cmdliner] also provides support for programs like [git] that have sub -commands each with their own command line syntax and manual: - -{[tool [COMMAND]… [OPTION]… ARG…]} - -These sub commands are defined by grouping them under a parent command -via the {!Cmdliner.Cmd.group} function. +And with this you should master the basics of Cmdliner, for examples +of more complex command line definitions consult the +{{!page-examples}examples}. For more tips, off-the-shelf recipes and +conventions have look at the {{!page-cookbook}cookbook}. \ No newline at end of file diff --git a/cmdliner/cli.html b/cmdliner/cli.html index fba94475..65bf5abd 100644 --- a/cmdliner/cli.html +++ b/cmdliner/cli.html @@ -1,2 +1,28 @@ -cli (cmdliner.cli)

Command line interface

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. Command names may be specified by a prefixe as long as they are not ambiguous.

Optional arguments

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.

  • A short name is a dash followed by a single alphanumeric character: -h, -q, -I.
  • A long name is two dashes followed by alphanumeric characters and dashes: --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. Long names can be specified by any non ambiguous prefix.

The value of an option can be specified in three different ways.

  • As the next token on the command line: -o a.out, --output a.out.
  • Glued to a short name: -oa.out.
  • Glued to a long name after an equal character: --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

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 -- we -are --all positional --argu=ments

Environment variables

Non-required command line arguments can be backed up by an environment variable. If the argument is absent from the command line and that 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.
  • Any other string is an error.

Note that environment variables are not supported for Cmdliner.Arg.vflag and Cmdliner.Arg.vflag_all.

Reserved option names

Using the cmdliner library puts the following constraints o

  • The option name --cmdliner is reserved by the library.
  • The option name --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.
  • Defining the same option or command name via two different arguments or terms is illegal and raises Invalid_argument.
+cli (cmdliner.cli)

Command line interface

This manual describes how your tool ends up interacting with shells when you use Cmdliner.

Tool invocation

For tools evaluating a command without subcommands 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 subcommands 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 subcommand stops.

Arguments

Optional arguments

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.

  • A short name is a dash followed by a single alphanumeric character: -h, -q, -I.
  • A long name is two dashes followed by alphanumeric characters and dashes: --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.

  • As the next token on the command line: -o a.out, --output a.out.
  • Glued to a short name: -oa.out.
  • Glued to a long name after an equal character: --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

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

Constraints on option names

Using the cmdliner library puts the following constraints on your command line interface:

  • The option names --cmdliner and --__complete are reserved by the library.
  • The option name --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.
  • Defining the same option or command name via two different arguments or terms is illegal and raises Invalid_argument.

Environment variables

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.
  • Any other string is an error.

Note that environment variables are not supported for Cmdliner.Arg.vflag and Cmdliner.Arg.vflag_all.

Help and man pages

Help and man pages are are generated when you call your tool or a subcommand 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

Paging

The pager is selected by looking up, in order:

  1. The MANPAGER variable.
  2. The PAGER variable.
  3. The tool less.
  4. The tool 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.

Install

The manpages of a tool and its subcommands can be installed to a root man directory $MANDIR by invoking:

cmdliner install tool-manpages thetool $MANDIR

This looks up thetool in the PATH. Use an explicit file path like ./thetool to directly specify an executable.

If you are also installing completions rather use the install tool-support command, see this cookbook tip which also has instructions on how to install if you are using opam.

Command line completion

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.

End-user configuration

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.

For 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. Note that these instruction do not react dynamically to opam switches changes so you may see odd completion behaviours when you do so, see this this opam 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

For 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}"

Note that these instruction do not react dynamically to opam switches changes so you may see odd completion behaviours when you do so, see this this opam issue.

After this, to test everything is right, check that the _cmdliner_generic function can be looked up:

> _completion_loader _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 _completion_loader.

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:

_completion_loader _cmdliner_generic
+complete -F _cmdliner_generic thetool

Note. It seems _completion_loader was deprecated in bash-completion 2.12 in favour of _comp_load but many distributions are on < 2.12 and in 2.12 _completion_loader simply calls _comp_load.

Install

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:

  • For zsh it is $SHAREDIR/zsh/site-functions
  • For 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.

Generic completion scripts

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.

Tool completion scripts

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 also installing manpages rather use the install tool-support command, see this cookbook tip which also has instructions on how to install if you are using opam.

Completion protocol

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 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 cmdliner generic-completion command.

The protocol betwen the shell completion script and a cmdliner based tool is as follows:

  1. When completion is requested the script invokes the tool with a modified command line:

    • The first argument to the tool (Sys.argv.(1)) must be the option --__complete.
    • The (possibly empty) argument ARG on which the completion is requested must be replaced by exactly --__complete=ARG. Note that this can happen after the -- token, this is the reason why we have an explicit --__complete argument in Sys.argv.(1): it indicates the command line parser must operate in a special mode.
  2. The tool responds by writing on standard output a list of completion directives which match the completions rule of the grammar given below.
  3. 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.

The following ABNF grammar is described using the notations of RFC 5234 and RFC 7405. A few constraints are not expressed by the grammar:

  • Except in the completion rule, the byte stream may contain ANSI escape sequences introduced by the byte 0x1B.
  • After stripping the ANSI escape sequences, the resulting byte stream must be valid UTF-8 text.
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

The semantics of directives is as follows:

  • A message 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 message-end as it is used to signal the end of the message. Messages should be reported in the order they are received.
  • A 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, this is a string that defines what the requested ARG value can be replaced with. It is followed by an item_doc, multi-line ANSI styled text which cannot have a line that is exactly made of the text item-end as it is used to signal the end of the item.
  • A file directive indicates that the script should add existing files staring with ARG to completion values.
  • A dir directive indicates that the script should add existing directories starting with ARG to completion values.
  • A restart directive indicates that the script should restart shell completion as if the command line was starting after the leftmost -- disambiguation token. The directive never gets emited if there is no -- on the command line.

You can easily inspect the completions of any cmdliner based tool by invoking it like the protocol suggests. For example for the cmdliner tool itself:

cmdliner --__complete --__complete=

Error message ANSI styling

Since Cmdliner 2.0 error messages printed on stderr use styled text with ANSI escapes unless one of the following conditions is met:

  • The NO_COLOR environment variable is set and different from the empty string. Yes, even if you have NO_COLOR=false, that's what the particularly dumb https://no-color.org standard says.
  • The TERM environment variable is dumb.
  • The TERM environment variable is unset and Sys.backend_type is not Other "js_of_ocaml". Yes, browser consoles support ANSI escapes. Yes, you can run Cmdliner in your browser.

Legacy prefix specification

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.

The CMDLINER_LEGACY_PREFIX=true escape hatch should not be used for interactive tool interaction. In particular the behaviour of Cmdliner completion support under this setting is undefined.

diff --git a/cmdliner/cookbook.html b/cmdliner/cookbook.html new file mode 100644 index 00000000..3e9d5cde --- /dev/null +++ b/cmdliner/cookbook.html @@ -0,0 +1,173 @@ + +cookbook (cmdliner.cookbook)

Cmdliner cookbook

A few recipes and starting blueprints to describe your command lines with Cmdliner.

Note. Some of the code snippets here assume they are done after:

open Cmdliner
+open Cmdliner.Term.Syntax

Tips and pitfalls

Command line interfaces are a rather crude and inexpressive user interaction medium. It is tempting to try to be nice to users in various ways but this often backfires in confusing context sensitive behaviours. Here are a few tips and Cmdliner features you should rather not use.

Avoid default commands in groups

Command groups can have a default command, that is be of the form tool [CMD]. Except perhaps at the top level of your tool, it's better to avoid them. They increase command line parsing ambiguities.

In particular if the default command has positional arguments, users are forced to use the disambiguation token -- to specify them so that they can be distinguished from command names. For example:

tool -- file …

One thing that is acceptable is to have a default command that simply shows documentation for the group of subcommands as this not interfere with tool operation.

Avoid default option values

Optional arguments with values can have a default value, that is be of the form --opt[=VALUE]. In general it is better to avoid them as they lead to context sensitive command lines specifications and surprises when users refine invocations. For examples suppose you have the synopsis

tool --opt[=VALUE] [FILE]

Trying to refine the following invocation to add a FILE parameter is error prone and painful:

tool --opt

There is more than one way but the easiest way is to specify:

tool --opt -- FILE

which is not obvious unless you have tool's cli hard wired in your brain. This would have been a careless refinement if --opt did not have a default option value.

Avoid required optional arguments

Cmdliner allows to define required optional arguments. Avoid doing this, it's a contradiction in the terms. In command line interfaces optional arguments are defined to be… optional, not doing so is surprising for your users. Use required positional arguments if arguments are required by your command invocation.

Required optional arguments can be useful though if your tool is not meant to be invoked manually but rather through scripts and has many required arguments. In this case they become a form of labelled arguments which can make invocations easier to understand.

Avoid making manpages your main documentation

Unless your tool is very simple, avoid making manpages the main documentation medium of your tool. The medium is rather limited and even though you can convert them to HTML, its cross references capabilities are rather limited which makes discussing your tool online more difficult.

Keep information in manpages to the minimum needed to operate your tool without having to leave the terminal too much and defer reference manuals, conceptual information and tutorials to a more evolved medium like HTML.

Migrating from other conventions

If you are porting your command line parsing to Cmdliner and that you have conventions that clash with Cmdliner's ones but you need to preserve backward compatibility, one way of proceeding is to pre-process Sys.argv into a new array of the right shape before giving it to command evaluation functions via the ?argv optional argument.

These are two common cases:

  • Long option names with a single dash like -warn-error. In this case simply prefix an additional - to these arguments when they occur in Sys.argv before the -- argument; after it, all arguments are positional and to be treated literally.
  • Long option names with a single letter like --X. In this case simply chop the first - to make it a short option when they occur in Sys.argv before the -- argument; after it all arguments are positional and to be treated literally.

Source code structure

In general Cmdliner wants you to see your tools as regular OCaml functions that you make available to the shell. This means adopting the following source structure:

(* Implementation of your command. Except for exit codes does not deal with
+   command line interface related matters and is independent from
+   Cmdliner. *)
+
+let exit_ok = 0
+let tool … = …; exit_ok
+
+(* Command line interface. Adds metadata to your [tool] function arguments
+   so that they can be parsed from the command line and documented. *)
+
+open Cmdliner
+open Cmdliner.Term.Syntax
+
+let cmd = … (* Has a term that invokes [tool] *)
+let main () = Cmd.eval' cmd
+let () = if !Sys.interactive then () else exit (main ())

In particular it is good for your readers' understanding that your program has a single point where it Stdlib.exits. This structure is also useful for playing with your program in the OCaml toplevel (REPL), you can invoke its main function without having the risk of it exiting the toplevel.

If your tool named tool is growing into multiple commands which have a lot of definitions it is advised to:

  • Gather command line definition commonalities such as argument converters or common options in a module called Tool_cli.
  • Define each command named name in a separate module Cmd_name which exports its command as a val cmd : int Cmd.t value.
  • Gather the commands with Cmdliner.Cmd.group in a source file called tool_main.ml.

For an hypothetic tool named tool with commands import, serve and user, this leads to the following set of files:

cmd_import.ml    cmd_serve.ml     cmd_user.ml   tool_cli.ml   tool_main.ml
+cmd_import.mli   cmd_serve.mli    cmd_user.mli  tool_cli.mli

The .mli files simply export commands:

val cmd : int Cmdliner.Cmd.t

And the tool_main.ml gathers them with a Cmdliner.Cmd.group:

let cmd =
+  let default = Term.(ret (const (`Help (`Auto, None)))) (* show help *) in
+  Cmd.group (Cmd.info "tool") ~default @@
+  [Cmd_import.cmd; Cmd_serve.cmd; Cmd_user.cmd]
+
+let main () = Cmd.value' cmd
+let () = if !Sys.interactive then () else exit (main ())

Installing completions and manpages

The cmdliner tool can be used to install completion scripts and manpages for you tool and its subcommands by using the dedicated install tool-completion and install tool-manpages subcommands.

To install both directly (and possibly other support files in the future) it is more concise to use the install tool-support command. Invoke with --help for more information.

With opam

If you are installing your package with opam for a tool named tool located in the build at the path $BUILD/tool, you can add the following instruction after your build instructions in the build: field of your opam file (also works if your build system is not using a .install file).

build: [
+  [ … ] # Your regular build instructions
+  ["cmdliner" "install" "tool-support"
+              "--update-opam-install=%{_:name}%.install"
+              "$BUILD/tool" "_build/cmdliner-install"]]

You need to specify the path to the built executable, as it cannot be looked up in the PATH yet. Also more than one tool can be specified in a single invocation and there is a syntax for specifying the actual tool name if it is renamed on install; see --help for more details.

If cmdliner is only an optional dependency of your package use the opam filter {cmdliner:installed} after the closing bracket of the command invocation.

With opam and dune

First make sure your understand the above basic instructions for opam. You then need to figure out how to add the cmdliner install instruction to the build: field of the opam file after your dune build instructions. For a tool named tool the result should eventually look this:

build: [
+   [ … ] # Your regular dune build instructions
+   ["cmdliner" "install" "tool-support"
+               "--update-opam-install=%{_:name}%.install"
+               "_build/default/install/bin/tool" {os != "win32"}
+               "_build/default/install/bin/tool.exe" {os = "win32"}
+               "_build/cmdliner-install"]]

Conventions

By simply using Cmdliner you are already abiding to a great deal of command line interface conventions. Here are a few other ones that are not necessarily enforced by the library but that are good to adopt for your users.

Use "-" to specify stdio in file path arguments

Whenever a command line argument specifies a file path to read or write you should let the user specify - to denote standard in or standard out, if possible. If you worry about a file sporting this name, note that the user can always specify it using ./- for the argument.

Very often tools default to stdin or stdout when a file input or output is unspecified, here is typical argument definitions to support these conventions:

let infile =
+  let doc = "$(docv) is the file to read from. Use $(b,-) for $(b,stdin)" in
+  Arg.(value & opt string "-" & info ["i", "input-file"] ~doc ~docv:"FILE")
+
+let outfile =
+  let doc = "$(docv) is the file to write to. Use $(b,-) for $(b,stdout)" in
+  Arg.(value & opt string "-" & info ["o", "output-file"] ~doc ~docv:"FILE")

Here is Stdlib based code to read to a string a file or standard input if - is specified:

let read_file file =
+  let read file ic = try Ok (In_channel.input_all ic) with
+  | Sys_error e -> Error (Printf.sprintf "%s: %s" file e)
+  in
+  let binary_stdin () = In_channel.set_binary_mode In_channel.stdin true in
+  try match file with
+  | "-" -> binary_stdin (); read file In_channel.stdin
+  | file -> In_channel.with_open_bin file (read file)
+  with Sys_error e -> Error e

Here is Stdlib based code to write a string to a file or standard output if - is specified:

let write_file file s =
+  let write file s oc = try Ok (Out_channel.output_string oc s) with
+  | Sys_error e -> Error (Printf.sprintf "%s: %s" file e)
+  in
+  let binary_stdout () = Out_channel.(set_binary_mode stdout true) in
+  try match file with
+  | "-" -> binary_stdout (); write file s Out_channel.stdout
+  | file -> Out_channel.with_open_bin file (write file s)
+  with Sys_error e -> Error e

Environment variables as default modifiers

Cmdliner has support to back values defined by arguments with environment variables. The value specified via an environment variable should never take over an argument specified explicitely on the command line. The environment variable should be seen as providing the default value when the argument is absent.

This is exactly what Cmdliner's support for environment variables does, see How can environment variables define defaults?

Arguments

How do I define a positional argument?

Positional arguments are extracted from the command line using these combinators which use zero-based indexing. The following example extracts the first argument and if the argument is absent from the command line it evaluates to "Revolt!".

let msg =
+  let doc = "$(docv) is the message to utter." and docv = "MSG" in
+  Arg.(value & pos 0 string "Revolt!" & info [] ~doc ~docv)

How do I define an optional argument?

Optional arguments are extracted from the command line using these combinators. The actual option name is defined in the Cmdliner.Arg.info structure without dashes. One character strings define short options, others long options (see the parsed syntax).

The following defines the -l and --loud options. This is a simple command line argument without a value also known as a command line flag. The term loud evaluates to false when the argument is absent on the command line and true otherwise.

let loud =
+  let doc = "Say the message loudly." in
+  Arg.(value & flag & info ["l"; "loud"] ~doc)

The following defines the -m and --message options. The term msg evalutes to "Revolt!" when the option is absent on the command line.

let msg =
+  let doc = "$(docv) is the message to utter." and docv = "MSG" in
+  Arg.(value & opt string "Revolt!" & info ["m"; "message"] ~doc ~docv)

How do I define a required argument?

Some of the constraints on the presence of arguments occur when the specification of arguments is converted to terms. The following says that the first positional argument is required:

let msg =
+  let msg = "$(docv) is the message to utter." and docv = "MSG" in
+  Arg.(required & pos 0 (some string) None & info [] ~absent ~doc ~docv)

The value msg ends up being a term of type string. If the argument is not provided, Cmdliner will automatically bail out during evaluation with an error message.

Note that while it is possible to define required positional argument it is discouraged.

How can I know if an argument was absent?

Most positional and optional arguments have a default value. You can use a None for the default argument and the Cmdliner.Arg.some or Cmdliner.Arg.some' combinators on your argument converter which simply wrap its result in a Some.

let msg =
+  let msg = "$(docv) is the message to utter." in
+  let absent = "Random quote." in
+  Arg.(value & pos 0 (some string) None & info [] ~absent ~doc ~docv:"MSG")

There is more than one way to document the value when it is absent. See How do I document absent argument behaviours?

How do I document absent argument behaviours?

There are three ways to document the behaviour when an argument is unspecified on the command line.

  • If you specify a default value in the argument combinator, this value gets printed in bold using the printer of the converter.
  • If you are using the Cmdliner.Arg.some' and Cmdliner.Arg.some there is an optional none argument that allows you to specify the default value. If you can exhibit this value at definition point use Cmdliner.Arg.some', the underlying converter's printer will be used. If not you can specify it as a string rendered in bold via Cmdliner.Arg.some.
  • If you want to describe a more complex, but short, behaviour use the ~absent parameter of Cmdliner.Arg.info. Using this parameter overrides the two previous ways. See this example.

How can I customize positional and option value completion?

Positional argument values and option values are completed according to the argument converter you use for defining the optional or positional argument.

A couple of predefined argument converter like Cmdliner.Arg.path, Cmdliner.Arg.filepath and Cmdliner.Arg.dirpath or Cmdliner.Arg.enum automatically handle this for you.

If you would like to perform custom or more elaborate context sensitive completions you can define your own argument converter with a completion defined with Cmdliner.Arg.Completion.make.

Here is an example where the first positional argument is completed with the filenames found in a directory specified via the --dir option (which defaults to the current working directory if unspecified).

let dir = Arg.(value & opt dirpath "." & info ["d"; "dir"])
+let dir_filenames_conv =
+  let complete dir ~token = match dir with
+  | None -> Error "Could not determine directory to lookup"
+  | Some dir ->
+      match Array.to_list (Sys.readdir dir) with
+      | exception Sys_error e -> Error (String.concat ": " [dir; e])
+      | fnames ->
+          let fnames = List.filter (String.starts_with ~prefix:token) fnames in
+          Ok (List.map Arg.Completion.string fnames)
+  in
+  let completion = Arg.Completion.make ~context:dir complete in
+  Arg.Conv.of_conv ~completion Arg.string
+
+let pos0 = Arg.(required & pos 0 (some dir_filenames_conv) None & info [])

Note that when you use pos0 in a command line definition you also need to make sure dir is part of the term otherwise the context will always be None:

let+ pos0 and+ dir and+ … in …

Environment variables

How can environment variables define defaults?

As mentioned in Environment variables as default modifiers, any non-required argument can be defined by an environment variable when absent. This works by specifying the env argument in the argument's Cmdliner.Arg.info information. For example:

let msg =
+  let doc = "$(docv) is the message to utter." and docv = "MSG" in
+  let env = Cmd.Env.info "MESSAGE" in
+  Arg.(value & pos 0 string "Revolt!" & info [] ~env ~doc ~docv)

When the first positional argument is absent it takes the default value "Revolt!", unless the MESSAGE variable is defined in the environment in which case it takes its value.

Cmdliner handles the environment variable lookup for you. By using the msg term in your command definition all this gets automatically documented in the tool help.

How do I document environment variables influencing a command?

Environment variable that are used to change argument defaults automatically get documented in a command's man page when you use the argument's term in the command's term.

However if your command implementation looks up other variables and you wish to document them in the command's man page, use the envs argument of Cmdliner.Cmd.info or the docs_env argument of Cmdliner.Arg.info.

This documents in the Cmdliner.Manpage.s_environment manual section of tool that EDITOR is looked up to find the tool to invoke to edit the files:

let editor_env = "EDITOR"
+let tool … = … Sys.getenv_opt editor_env
+let cmd =
+   let env = Cmd.Env.info editor_env ~doc:"The editor used to edit files." in
+   Cmd.make (Cmd.info "tool" ~envs:[env]) @@
+   …

Commands

How do I document command exit codes?

Exit codes are documentd by Cmdliner.Cmd.Exit.info values and must be given to the command's Cmdliner.Cmd.info value via the exits optional arguments. For example:

let conf_not_found = 1
+let tool … =
+let tool_cmd =
+  let exits =
+    Cmd.Exit.info conf_not_found "if no configuration could be found." ::
+    Cmd.Exit.defaults
+  in
+  Cmd.make (Cmd.info "mycmd" ~exits) @@
+  …

How do I show help in a command group's default?

While it is usually not advised to have a default command in a group, just showing docs is acceptable. A term can request Cmdliner's generated help by using Cmdliner.Term.ret:

let group_cmd =
+  let default = Term.(ret (const (`Help (`Auto, None)))) (* show help *) in
+  Cmd.group (Cmd.info "group") ~default @@
+  [first_cmd; second_cmd]

Which Cmd evaluation function should I use?

There are (too) many command evaluation functions. They have grown organically in a rather ad-hoc manner. Some of these are there for backwards compatibility reasons and advanced usage for complex tools.

Here are the main ones to use and why you may want to use them which essentially depends on how you want to handle errors and exit codes in your tool function.

  • Cmdliner.Cmd.eval. This forces your tool function to return (). The evaluation function always returns an exit code of 0 unless a command line parsing error occurs.
  • Cmdliner.Cmd.eval'. Recommended. This forces your tool function to return an exit code exit which is returned by the evaluation function unless a command line parsing error occurs. This is the recommended function to use as it forces you to think about how to report errors and design useful exit codes for users.
  • Cmdliner.Cmd.eval_result is akin to Cmdliner.Cmd.eval except it forces your function to return either Ok () or Error msg. The evaluation function returns with exit code 0 unless Error msg is computed in which case msg is printed on the error stream prefixed by the executable name and the evaluation function returns with exit code Cmdliner.Cmd.Exit.some_error.
  • Cmdliner.Cmd.eval_result' is akin to Cmdliner.Cmd.eval_result, except the Ok case carries an exit code which is returned by the evaluation function.

How can my tool support command line completion?

The command line interface manual has all the details and specific instructions for complementing your tool install. See also Installing completions and manpages.

How can I list all the commands of my tool?

In a shell the invocation cmdliner tool-commands $TOOL lists every command of the tool $TOOL.

How can I suppress error message styling?

Since Cmdliner 2.0, error message printed on stderr use styled text with ANSI escapes. Styled text is disabled if one of the conditions mentioned here is met.

If you want to be more aggressive in suppressing them you can use the err formatter argument of command evaluation functions with a suitable formatter on which a function like this one has been applied that automatically strips the styling.

Manpages

How do I prevent an item from being automatically listed?

In general it's not a good idea to hide stuff from your users but in case an item needs to be hidden you can use the special Cmdliner.Manpage.s_none section name. This ensures the item does not get listed in any section.

let secret = Arg.(value & flag & info ["super-secret"] ~docs:Manpage.s_none)

How can I write a better command synopsis section?

Define the Cmdliner.Manpage.s_synopsis section in the manpage of your command. It takes over the one generated by Cmdliner. For example:

let man = [
+ `S Manpage.s_synopsis;
+ `P "$(cmd) $(b,--) $(i,TOOL) [$(i,ARG)]…"; `Noblank;
+ `P "$(cmd) $(i,COMMAND) …";
+ `S Manpage.s_description;
+ `P "Without a command $(cmd) invokes $(i,TOOL)"; ]

How can I install all the manpages of my tool?

The command line interface manual the details on how to install the manpages of your tool and its subcommands. See also Installing completions and manpages.

Blueprints

These blueprints when copied to a src.ml file can be compiled and run with:

ocamlfind ocamlopt -package cmdliner -linkgpkg src.ml
+./a.out --help

More concrete examples can be found on the examples page and the tutorial may help too.

These examples follow a conventional Source code structure.

Minimal

A minimal example.

let tool () = Cmdliner.Cmd.Exit.ok
+
+open Cmdliner
+open Cmdliner.Term.Syntax
+
+let cmd =
+  Cmd.make (Cmd.info "TODO" ~version:"v2.0.0") @@
+  let+ unit = Term.const () in
+  tool unit
+
+let main () = Cmd.eval' cmd
+let () = if !Sys.interactive then () else exit (main ())

A simple tool

This is a tool that has a flag, an optional positional argument for specifying an input file. It also responds to the --version option.

let exit_todo = 1
+let tool ~flag ~infile = exit_todo
+
+open Cmdliner
+open Cmdliner.Term.Syntax
+
+let flag = Arg.(value & flag & info ["flag"] ~doc:"The flag")
+let infile =
+  let doc = "$(docv) is the input file. Use $(b,-) for $(b,stdin)." in
+  Arg.(value & pos 0 string "-" & info [] ~doc ~docv:"FILE")
+
+let cmd =
+  let doc = "The tool synopsis is TODO" in
+  let man = [
+    `S Manpage.s_description;
+    `P "$(cmd) does TODO" ]
+  in
+  let exits =
+    Cmd.Exit.info exit_todo ~doc:"When there is stuff todo" ::
+    Cmd.Exit.defaults
+  in
+  Cmd.make (Cmd.info "TODO" ~version:"v2.0.0" ~doc ~man ~exits) @@
+  let+ flag and+ infile in
+  tool ~flag ~infile
+
+let main () = Cmd.eval' cmd
+let () = if !Sys.interactive then () else exit (main ())

A tool with subcommands

This is a tool with two subcommands hey and ho. If your tools grows many subcommands you may want to follow these source code conventions.

let hey () = Cmdliner.Cmd.Exit.ok
+let ho () = Cmdliner.Cmd.Exit.ok
+
+open Cmdliner
+open Cmdliner.Term.Syntax
+
+let flag = Arg.(value & flag & info ["flag"] ~doc:"The flag")
+let infile =
+  let doc = "$(docv) is the input file. Use $(b,-) for $(b,stdin)." in
+  Arg.(value & pos 0 file "-" & info [] ~doc ~docv:"FILE")
+
+let hey_cmd =
+  let doc = "The hey command synopsis is TODO" in
+  Cmd.make (Cmd.info "hey" ~doc) @@
+  let+ unit = Term.const () in
+  ho ()
+
+let ho_cmd =
+  let doc = "The ho command synopsis is TODO" in
+  Cmd.make (Cmd.info "ho" ~doc) @@
+  let+ unit = Term.const () in
+  ho unit
+
+let cmd =
+  let doc = "The tool synopsis is TODO" in
+  Cmd.group (Cmd.info "TODO" ~version:"v2.0.0" ~doc) @@
+  [hey_cmd; ho_cmd]
+
+let main () = Cmd.eval' cmd
+let () = if !Sys.interactive then () else exit (main ())
diff --git a/cmdliner/examples.html b/cmdliner/examples.html index 5d1fe7a7..c7391d5c 100644 --- a/cmdliner/examples.html +++ b/cmdliner/examples.html @@ -1,17 +1,18 @@ -examples (cmdliner.examples)

Examples

The examples are self-contained, cut and paste them in a file to play with them.

A rm command

We define the command line interface of an rm command with the synopsis:

rm [OPTION]… FILE…

The -f, -i and -I flags define the prompt behaviour of rm. It is represented in our program by the prompt type. If more than one of these flags is present on the command line the last one takes precedence.

To implement this behaviour we map the presence of these flags to values of the prompt type by using Cmdliner.Arg.vflag_all.

This argument will contain all occurrences of the flag on the command line and we just take the Cmdliner.Arg.last one to define our term value. If there is no occurrence the last value of the default list [Always] is taken. This means the default prompt behaviour is Always.

(* Implementation of the command, we just print the args. *)
+examples (cmdliner.examples)

Examples

The examples are self-contained, cut and paste them in a file to play with them. See also the suggested source code structure and program blueprints.

A rm command

We define the command line interface of an rm command with the synopsis:

rm [OPTION]… FILE…

The -f, -i and -I flags define the prompt behaviour of rm. It is represented in our program by the prompt type. If more than one of these flags is present on the command line the last one takes precedence.

To implement this behaviour we map the presence of these flags to values of the prompt type by using Cmdliner.Arg.vflag_all.

This argument will contain all occurrences of the flag on the command line and we just take the Cmdliner.Arg.last one to define our term value. If there is no occurrence the last value of the default list [Always] is taken. This means the default prompt behaviour is Always.

(* Implementation of the command, we just print the args. *)
 
 type prompt = Always | Once | Never
 let prompt_str = function
 | Always -> "always" | Once -> "once" | Never -> "never"
 
-let rm prompt recurse files =
+let rm ~prompt ~recurse files =
   Printf.printf "prompt = %s\nrecurse = %B\nfiles = %s\n"
     (prompt_str prompt) recurse (String.concat ", " files)
 
 (* Command line interface *)
 
 open Cmdliner
+open Cmdliner.Term.Syntax
 
 let files = Arg.(non_empty & pos_all file [] & info [] ~docv:"FILE")
 let prompt =
@@ -36,29 +37,30 @@ let recursive =
   let doc = "Remove directories and their contents recursively." in
   Arg.(value & flag & info ["r"; "R"; "recursive"] ~doc)
 
-let cmd =
+let rm_cmd =
   let doc = "Remove files or directories" in
   let man = [
     `S Manpage.s_description;
-    `P "$(tname) removes each specified $(i,FILE). By default it does not
+    `P "$(cmd) removes each specified $(i,FILE). By default it does not
         remove directories, to also remove them and their contents, use the
         option $(b,--recursive) ($(b,-r) or $(b,-R)).";
     `P "To remove a file whose name starts with a $(b,-), for example
         $(b,-foo), use one of these commands:";
-    `Pre "$(mname) $(b,-- -foo)"; `Noblank;
-    `Pre "$(mname) $(b,./-foo)";
-    `P "$(tname) removes symbolic links, not the files referenced by the
+    `Pre "$(cmd) $(b,-- -foo)"; `Noblank;
+    `Pre "$(cmd) $(b,./-foo)";
+    `P "$(cmd.name) removes symbolic links, not the files referenced by the
         links.";
     `S Manpage.s_bugs; `P "Report bugs to <bugs@example.org>.";
     `S Manpage.s_see_also; `P "$(b,rmdir)(1), $(b,unlink)(2)" ]
   in
-  let info = Cmd.info "rm" ~version:"v1.3.0" ~doc ~man in
-  Cmd.v info Term.(const rm $ prompt $ recursive $ files)
+  Cmd.make (Cmd.info "rm" ~version:"v2.0.0" ~doc ~man) @@
+  let+ prompt and+ recursive and+ files in
+  rm ~prompt ~recurse:recursive files
 
-let main () = exit (Cmd.eval cmd)
-let () = main ()

A cp command

We define the command line interface of a cp command with the synopsis:

cp [OPTION]… SOURCE… DEST

The DEST argument must be a directory if there is more than one SOURCE. This constraint is too complex to be expressed by the combinators of Cmdliner.Arg.

Hence we just give DEST the Cmdliner.Arg.string type and verify the constraint at the beginning of the implementation of cp. If the constraint is unsatisfied we return an `Error result. By using Cmdliner.Term.ret on the lifted result cp_t of cp, Cmdliner handles the error reporting.

(* Implementation, we check the dest argument and print the args *)
+let main () = Cmd.eval rm_cmd
+let () = if !Sys.interactive then () else exit (main ())

A cp command

We define the command line interface of a cp command with the synopsis:

cp [OPTION]… SOURCE… DEST

The DEST argument must be a directory if there is more than one SOURCE. This constraint is too complex to be expressed by the combinators of Cmdliner.Arg.

Hence we just give DEST the Cmdliner.Arg.string type and verify the constraint at the beginning of the implementation of cp. If the constraint is unsatisfied we return an `Error result. By using Cmdliner.Term.ret on the command's term for cp, Cmdliner handles the error reporting.

(* Implementation, we check the dest argument and print the args *)
 
-let cp verbose recurse force srcs dest =
+let cp ~verbose ~recurse ~force srcs dest =
   let many = List.length srcs > 1 in
   if many && (not (Sys.file_exists dest) || not (Sys.is_directory dest))
   then `Error (false, dest ^ ": not a directory") else
@@ -69,6 +71,7 @@ let cp verbose recurse force srcs dest =
 (* Command line interface *)
 
 open Cmdliner
+open Cmdliner.Term.Syntax
 
 let verbose =
   let doc = "Print file names as they are copied." in
@@ -92,21 +95,22 @@ let dest =
   let docv = "DEST" in
   Arg.(required & pos ~rev:true 0 (some string) None & info [] ~docv ~doc)
 
-let cmd =
+let cp_cmd =
   let doc = "Copy files" in
   let man_xrefs =
-    [ `Tool "mv"; `Tool "scp"; `Page ("umask", 2); `Page ("symlink", 7) ]
+    [`Tool "mv"; `Tool "scp"; `Page ("umask", 2); `Page ("symlink", 7)]
   in
-  let man =
-    [ `S Manpage.s_bugs;
-      `P "Email them to <bugs@example.org>."; ]
+  let man = [
+    `S Manpage.s_bugs;
+    `P "Email them to <bugs@example.org>."; ]
   in
-  let info = Cmd.info "cp" ~version:"v1.3.0" ~doc ~man ~man_xrefs in
-  Cmd.v info Term.(ret (const cp $ verbose $ recurse $ force $ srcs $ dest))
+  Cmd.make (Cmd.info "cp" ~version:"v2.0.0" ~doc ~man ~man_xrefs) @@
+  Term.ret @@
+  let+ verbose and+ recurse and+ force and+ srcs and+ dest in
+  cp ~verbose ~recurse ~force srcs dest
 
-
-let main () = exit (Cmd.eval cmd)
-let () = main ()

A tail command

We define the command line interface of a tail command with the synopsis:

tail [OPTION]… [FILE]…

The --lines option whose value specifies the number of last lines to print has a special syntax where a + prefix indicates to start printing from that line number. In the program this is represented by the loc type. We define a custom loc_arg argument converter for this option.

The --follow option has an optional enumerated value. The argument converter follow, created with Cmdliner.Arg.enum parses the option value into the enumeration. By using Cmdliner.Arg.some and the ~vopt argument of Cmdliner.Arg.opt, the term corresponding to the option --follow evaluates to None if --follow is absent from the command line, to Some Descriptor if present but without a value and to Some v if present with a value v specified.

(* Implementation of the command, we just print the args. *)
+let main () = Cmd.eval cp_cmd
+let () = if !Sys.interactive then () else exit (main ())

A tail command

We define the command line interface of a tail command with the synopsis:

tail [OPTION]… [FILE]…

The --lines option whose value specifies the number of last lines to print has a special syntax where a + prefix indicates to start printing from that line number. In the program this is represented by the loc type. We define a custom loc_arg argument converter for this option.

The --follow option has an optional enumerated value. The argument converter follow, created with Cmdliner.Arg.enum parses the option value into the enumeration. By using Cmdliner.Arg.some and the ~vopt argument of Cmdliner.Arg.opt, the term corresponding to the option --follow evaluates to None if --follow is absent from the command line, to Some Descriptor if present but without a value and to Some v if present with a value v specified.

(* Implementation of the command, we just print the args. *)
 
 type loc = bool * int
 type verb = Verbose | Quiet
@@ -118,7 +122,7 @@ let loc_str (rev, k) = if rev then str "%d" k else str "+%d"
 let follow_str = function Name -> "name" | Descriptor -> "descriptor"
 let verb_str = function Verbose -> "verbose" | Quiet -> "quiet"
 
-let tail lines follow verb pid files =
+let tail ~lines ~follow ~verb ~pid files =
   Printf.printf
     "lines = %s\nfollow = %s\nverb = %s\npid = %s\nfiles = %s\n"
     (loc_str lines) (opt_str follow_str follow) (verb_str verb)
@@ -127,17 +131,18 @@ let tail lines follow verb pid files =
 (* Command line interface *)
 
 open Cmdliner
+open Cmdliner.Term.Syntax
 
 let loc_arg =
-  let parse s =
+  let parser s =
     try
       if s <> "" && s.[0] <> '+'
       then Ok (true, int_of_string s)
       else Ok (false, int_of_string (String.sub s 1 (String.length s - 1)))
-    with Failure _ -> Error (`Msg "unable to parse integer")
+    with Failure _ -> Error "unable to parse integer"
   in
-  let print ppf p = Format.fprintf ppf "%s" (loc_str p) in
-  Arg.conv ~docv:"N" (parse, print)
+  let pp ppf p = Format.fprintf ppf "%s" (loc_str p) in
+  Arg.Conv.make ~docv:"N" ~parser ~pp ()
 
 let lines =
   let doc = "Output the last $(docv) lines or use $(i,+)$(docv) to start \
@@ -171,24 +176,24 @@ let pid =
 
 let files = Arg.(value & (pos_all non_dir_file []) & info [] ~docv:"FILE")
 
-let cmd =
+let tail_cmd =
   let doc = "Display the last part of a file" in
   let man = [
     `S Manpage.s_description;
-    `P "$(tname) prints the last lines of each $(i,FILE) to standard output. If
-        no file is specified reads standard input. The number of printed
+    `P "$(cmd) prints the last lines of each $(i,FILE) to standard output.
+        If no file is specified reads standard input. The number of printed
         lines can be  specified with the $(b,-n) option.";
     `S Manpage.s_bugs;
     `P "Report them to <bugs@example.org>.";
     `S Manpage.s_see_also;
     `P "$(b,cat)(1), $(b,head)(1)" ]
   in
-  let info = Cmd.info "tail" ~version:"v1.3.0" ~doc ~man in
-  Cmd.v info Term.(const tail $ lines $ follow $ verb $ pid $ files)
+  Cmd.make (Cmd.info "tail" ~version:"v2.0.0" ~doc ~man) @@
+  let+ lines and+ follow and+ verb and+ pid and+ files in
+  tail ~lines ~follow ~verb ~pid files
 
-
-let main () = exit (Cmd.eval cmd)
-let () = main ()

A darcs command

We define the command line interface of a darcs command with the synopsis:

darcs [COMMAND] …

The --debug, -q, -v and --prehook options are available in each command. To avoid having to pass them individually to each command we gather them in a record of type copts. By lifting the record constructor copts into the term copts_t we now have a term that we can pass to the commands to stand for an argument of type copts. These options are documented in a section called COMMON OPTIONS, since we also want to put --help and --version in this section, the term information of commands makes a judicious use of the sdocs parameter of Cmdliner.Term.info.

The help command shows help about commands or other topics. The help shown for commands is generated by Cmdliner by making an appropriate use of Cmdliner.Term.ret on the lifted help function.

If the program is invoked without a command we just want to show the help of the program as printed by Cmdliner with --help. This is done by the default_cmd term.

(* Implementations, just print the args. *)
+let main () = Cmd.eval tail_cmd
+let () = if !Sys.interactive then () else exit (main ())

A darcs command

We define the command line interface of a darcs command with the synopsis:

darcs [COMMAND] …

The --debug, -q, -v and --prehook options are available in each command. To avoid having to pass them individually to each command we gather them in a record of type copts. By lifting the record constructor copts into the term copts_t we now have a term that we can pass to the commands to stand for an argument of type copts. These options are documented in the section Cmdliner.Manpage.s_common_options.

The help command shows help about commands or other topics. The help shown for commands is generated by Cmdliner by making an appropriate use of Cmdliner.Term.ret on the lifted help function.

If the program is invoked without a command we just want to show the help of the program as printed by Cmdliner with --help. This is done by the default term.

(* Implementations, just print the args. *)
 
 type verb = Normal | Quiet | Verbose
 type copts = { debug : bool; verb : verb; prehook : string option }
@@ -215,16 +220,18 @@ let help copts man_format cmds topic = match topic with
 | None -> `Help (`Pager, None) (* help about the program. *)
 | Some topic ->
     let topics = "topics" :: "patterns" :: "environment" :: cmds in
-    let conv, _ = Cmdliner.Arg.enum (List.rev_map (fun s -> (s, s)) topics) in
-    match conv topic with
-    | `Error e -> `Error (false, e)
-    | `Ok t when t = "topics" -> List.iter print_endline topics; `Ok ()
-    | `Ok t when List.mem t cmds -> `Help (man_format, Some t)
-    | `Ok t ->
+    let conv = Cmdliner.Arg.enum (List.rev_map (fun s -> (s, s)) topics) in
+    let parse = Cmdliner.Arg.Conv.parser conv in
+    match parse topic with
+    | Error e -> `Error (false, e)
+    | Ok t when t = "topics" -> List.iter print_endline topics; `Ok ()
+    | Ok t when List.mem t cmds -> `Help (man_format, Some t)
+    | Ok t ->
         let page = (topic, 7, "", "", ""), [`S topic; `P "Say something";] in
         `Ok (Cmdliner.Manpage.print man_format Format.std_formatter page)
 
 open Cmdliner
+open Cmdliner.Term.Syntax
 
 (* Help sections common to all commands *)
 
@@ -232,9 +239,9 @@ let help_secs = [
  `S Manpage.s_common_options;
  `P "These options are common to all commands.";
  `S "MORE HELP";
- `P "Use $(mname) $(i,COMMAND) --help for help on a single command.";`Noblank;
- `P "Use $(mname) $(b,help patterns) for help on patch matching."; `Noblank;
- `P "Use $(mname) $(b,help environment) for help on environment variables.";
+ `P "Use $(tool) $(i,COMMAND) --help for help on a single command.";`Noblank;
+ `P "Use $(tool) $(b,help patterns) for help on patch matching."; `Noblank;
+ `P "Use $(tool) $(b,help environment) for help on environment variables.";
  `S Manpage.s_bugs; `P "Check bug reports at http://bugs.example.org.";]
 
 (* Options common to all commands *)
@@ -254,7 +261,7 @@ let copts_t =
     Arg.(last & vflag_all [Normal] [quiet; verbose])
   in
   let prehook =
-    let doc = "Specify command to run before this $(mname) command." in
+    let doc = "Specify command to run before this $(tool) command." in
     Arg.(value & opt (some string) None & info ["prehook"] ~docs ~doc)
   in
   Term.(const copts $ debug $ verb $ prehook)
@@ -276,8 +283,9 @@ let initialize_cmd =
        existing files and subdirectories become …";
     `Blocks help_secs; ]
   in
-  let info = Cmd.info "initialize" ~doc ~sdocs ~man in
-  Cmd.v info Term.(const initialize $ copts_t $ repodir)
+  Cmd.make (Cmd.info "initialize" ~doc ~sdocs ~man) @@
+  let+ copts_t and+ repodir in
+  initialize copts_t repodir
 
 let record_cmd =
   let pname =
@@ -303,12 +311,12 @@ let record_cmd =
   let man =
     [`S Manpage.s_description;
      `P "Creates a patch from changes in the working tree. If you specify
-         a set of files …";
+         a set of files…";
      `Blocks help_secs; ]
   in
-  let info = Cmd.info "record" ~doc ~sdocs ~man in
-  Cmd.v info
-    Term.(const record $ copts_t $ pname $ author $ all $ ask_deps $ files)
+  Cmd.make (Cmd.info "record" ~doc ~sdocs ~man) @@
+  let+ copts_t and+ pname and+ author and+ all and+ ask_deps and+ files in
+  record copts_t pname author all ask_deps files
 
 let help_cmd =
   let topic =
@@ -321,16 +329,18 @@ let help_cmd =
      `P "Prints help about darcs commands and other subjects…";
      `Blocks help_secs; ]
   in
-  let info = Cmd.info "help" ~doc ~man in
-  Cmd.v info
-    Term.(ret (const help $ copts_t $ Arg.man_format $ Term.choice_names $
-               topic))
+  Cmd.make (Cmd.info "help" ~doc ~man) @@
+  Term.ret @@
+  let+ copts_t and+ man_format = Arg.man_format
+  and+ choice_names = Term.choice_names and+ topic in
+  help copts_t man_format choice_names topic
 
 let main_cmd =
   let doc = "a revision control system" in
   let man = help_secs in
-  let info = Cmd.info "darcs" ~version:"v1.3.0" ~doc ~sdocs ~man in
+  let info = Cmd.info "darcs" ~version:"v2.0.0" ~doc ~sdocs ~man in
   let default = Term.(ret (const (fun _ -> `Help (`Pager, None)) $ copts_t)) in
   Cmd.group info ~default [initialize_cmd; record_cmd; help_cmd]
 
-let () = exit (Cmd.eval main_cmd)
+let main () = Cmd.eval main_cmd +let () = if !Sys.interactive then () else exit (main ())
diff --git a/cmdliner/index.html b/cmdliner/index.html index 388a010e..2d7e0777 100644 --- a/cmdliner/index.html +++ b/cmdliner/index.html @@ -1,2 +1,2 @@ -index (cmdliner.index)

Package cmdliner

Cmdliner provides a simple and compositional mechanism to convert command line arguments to OCaml values and pass them to your functions.

The library automatically handles syntax errors, help messages and UNIX man page generation. It supports programs with single or multiple commands (like git) and respect most of the POSIX and GNU conventions.

Manuals

The following manuals are available.

  • The tutorial gets you through the steps to write your first command line interface with Cmdliner.
  • The Command line interface manual describes how command lines and environment variables are parsed by Cmdliner.
  • Tool man pages describes how Cmdliner generates man pages for your tools and how you can format them.
  • The examples page has a few annoted examples that show to express the command line interface of a few classic tools with Cmdliner

API

  • Cmdliner Declarative definition of command line interfaces.

Package info

changes-files
license-files
readme-files
+index (cmdliner.index)

Package cmdliner

Cmdliner provides a simple and compositional mechanism to convert command line arguments to OCaml values and pass them to your functions.

The library automatically handles command line completion, syntax errors, help messages and UNIX man page generation. It supports programs with single or multiple commands (like git) and respect most of the POSIX and GNU conventions.

Manuals

The following manuals are available.

  • The tutorial makes you write your first command line interface with Cmdliner.
  • The cookbook has a few off-the-shelf recipes, tips about source code structure, and blueprints to define your command lines with Cmdliner.
  • The command line interface manual describes how command lines and environment variables are parsed by Cmdliner and how command line completion is performed. This can be communicated to the users of your tools.
  • The tool man page manual describes how Cmdliner generates man pages for your tools and their commands and how you can format them.
  • The examples page has examples of a some classic UNIX tools with their command line interface implemented by Cmdliner.

Library cmdliner

  • Cmdliner Declarative definition of command line interfaces.

Package info

changes-files
license-files
readme-files
diff --git a/cmdliner/tool_man.html b/cmdliner/tool_man.html index 80c3f632..31405614 100644 --- a/cmdliner/tool_man.html +++ b/cmdliner/tool_man.html @@ -1,2 +1,2 @@ -tool_man (cmdliner.tool_man)

Tool man pages

Manual

Man page sections for a command are printed in the order specified by manual as given to Cmdliner.Cmd.info. Unless specified explicitly in the command's manual the following sections are automatically created and populated for you:

The various doc documentation strings specified by the command's term arguments get inserted at the end of the documentation section they respectively mention in their docs argument:

  1. For commands, see Cmdliner.Cmd.info.
  2. For positional arguments, see Cmdliner.Arg.info. Those are listed iff both the docv and doc string is specified by Cmdliner.Arg.info.
  3. For optional arguments, see Cmdliner.Arg.info.
  4. For exit statuses, see Cmdliner.Cmd.Exit.info.
  5. For environment variables, see Cmdliner.Arg.env_var and Cmdliner.Cmd.Env.info.

If a docs section name is mentioned and does not exist in the command's manual, an empty section is created for it, after which the doc strings are inserted, possibly prefixed by boilerplate text (e.g. for Cmdliner.Manpage.s_environment and Cmdliner.Manpage.s_exit_status).

If the created section is:

  • standard, it is inserted at the right place in the order specified here, but after a possible non-standard section explicitly specified by the command's manual since the latter get the order number of the last previously specified standard section or the order of Cmdliner.Manpage.s_synopsis if there is no such section.
  • non-standard, it is inserted before the Cmdliner.Manpage.s_commands section or the first subsequent existing standard section if it doesn't exist. Taking advantage of this behaviour is discouraged, you should declare manually your non standard section in the command's manual page.

Finally note that the header of empty sections are dropped from the output. This allows you to share section placements among many commands and render them only if something actually gets inserted in it.

Documentation markup language

Manpage blocks and doc strings support the following markup language.

  • Markup directives $(i,text) and $(b,text), where text is raw text respectively rendered in italics and bold.
  • Outside markup directives, context dependent variables of the form $(var) are substituted by marked up data. For example in a term's man page $(tname) is substituted by the term name in bold.
  • Characters $, (, ) and \ can respectively be escaped by \$, \(, \) and \\ (in OCaml strings this will be "\\$", "\\(", "\\)", "\\\\"). Escaping $ and \ is mandatory everywhere. Escaping ) is mandatory only in markup directives. Escaping ( is only here for your symmetric pleasure. Any other sequence of characters starting with a \ is an illegal character sequence.
  • Referring to unknown markup directives or variables will generate errors on standard error during documentation generation.
+tool_man (cmdliner.tool_man)

Tool man pages

See also the section about man pages in the command line interface manual.

Man page generation

Man page sections for a command are printed in the order specified by the man value given to Cmdliner.Cmd.info. Unless specified explicitly in the man value the following sections are automatically created and populated for you:

The various doc documentation strings specified by the command's term arguments get inserted at the end of the documentation section they respectively mention in their docs argument:

  1. For commands, see Cmdliner.Cmd.info.
  2. For positional arguments, see Cmdliner.Arg.info. Those are listed iff both the docv and doc string is specified by Cmdliner.Arg.info.
  3. For optional arguments, see Cmdliner.Arg.info.
  4. For exit statuses, see Cmdliner.Cmd.Exit.info.
  5. For environment variables, see Cmdliner.Cmd.Env.info.

If a docs section name is mentioned and does not exist in the command's man value, an empty section is created for it, after which the doc strings are inserted, possibly prefixed by boilerplate text (e.g. for Cmdliner.Manpage.s_environment and Cmdliner.Manpage.s_exit_status).

If the created section is:

  • standard, it is inserted at the right place in the order specified here, but after a possible non-standard section explicitly specified by the command's man value since the latter get the order number of the last previously specified standard section or the order of Cmdliner.Manpage.s_synopsis if there is no such section.
  • non-standard, it is inserted before the Cmdliner.Manpage.s_commands section or the first subsequent existing standard section if it doesn't exist. Taking advantage of this behaviour is discouraged, you should declare manually your non standard section in the command's manual page.

Finally note that the header of empty sections are dropped from the output. This allows you to share section placements among many commands and render them only if something actually gets inserted in it.

Documentation markup language

Manpage blocks and the doc strings of the various info values support the following markup language.

  • Markup directives $(i,text) and $(b,text), where text is raw text respectively rendered in italics and bold.
  • Outside markup directives, context dependent variables of the form $(var) are substituted by marked up data. For example in a command man page $(cmd) is substituted by the command's invocation in bold.
  • Characters '$', '(', ')' and '\' can respectively be escaped by \$, \(, \) and \\ . In OCaml strings this will be "\\$", "\\(", "\\)", "\\\\". Escaping '$' and '\' is mandatory everywhere. Escaping ')' is mandatory only in markup directives. Escaping '(' is only here for your symmetric pleasure. Any other sequence of characters starting with a '\' is an illegal character sequence.
  • Referring to unknown markup directives or variables will generate errors on standard error during documentation generation.
diff --git a/cmdliner/tutorial.html b/cmdliner/tutorial.html index 8a994bbe..4ae1fef2 100644 --- a/cmdliner/tutorial.html +++ b/cmdliner/tutorial.html @@ -1,27 +1,43 @@ -tutorial (cmdliner.tutorial)

Tutorial

Getting started

With Cmdliner your tool's main function evaluates a command.

A command is a value of type Cmdliner.Cmd.t which gathers a command name and a term of type Cmdliner.Term.t. A term is an expression to be evaluated. The type parameter of the term (and the command) indicates the type of the result of the evaluation.

One way to create terms is by lifting regular OCaml values with Cmdliner.Term.const. Terms can be applied to terms evaluating to functional values with Cmdliner.Term.($).

For example, in a revolt.ml file, for the function:

let revolt () = print_endline "Revolt!"

the term :

open Cmdliner
+tutorial (cmdliner.tutorial)

Tutorial

See also the cookbook, blueprints and examples.

Commands and terms

With Cmdliner your tool's main function evaluates a command.

A command is a value of type Cmdliner.Cmd.t which gathers a command name and a term of type Cmdliner.Term.t. A term represents both a command line syntax fragment and an expression to be evaluated that implements your tool. The type parameter of the term (and the command) indicates the type of the result of the evaluation.

One way to create terms is by lifting regular OCaml values with Cmdliner.Term.const. Terms can be applied to terms evaluating to functional values with Cmdliner.Term.app.

For example, in a revolt.ml file, for the function:

let revolt () = print_endline "Revolt!"

the term :

open Cmdliner
 
-let revolt_t = Term.(const revolt $ const ())

is a term that evaluates to the result (and effect) of the revolt function. This term can be attached to a command:

let cmd = Cmd.v (Cmd.info "revolt") revolt_t

and evaluated with Cmdliner.Cmd.eval:

let () = exit (Cmd.eval cmd)

This defines a command line tool named "revolt" (this name will be used in error reporting and documentation generation), without command line arguments, that just prints "Revolt!" on stdout.

> ocamlfind ocamlopt -linkpkg -package cmdliner -o revolt revolt.ml
+let revolt_term = Term.app (Term.const revolt) (Term.const ())

is a term that evaluates to the result (and effect) of the revolt function. This term can be associated to a command:

let cmd_revolt = Cmd.make (Cmd.info "revolt") revolt_term

and evaluated with Cmdliner.Cmd.eval:

let main () = Cmd.eval cmd_revolt
+let () = if !Sys.interactive then () else exit (main ())

This defines a command line tool named "revolt" (this name will be used in error reporting and documentation generation), without command line arguments, that just prints "Revolt!" on stdout.

> ocamlfind ocamlopt -linkpkg -package cmdliner -o revolt revolt.ml
 > ./revolt
-Revolt!

The combinators in the Cmdliner.Arg module allow to extract command line arguments as terms. These terms can then be applied to lifted OCaml functions to be evaluated.

Terms corresponding to command line argument data that are part of a term evaluation implicitly define a command line syntax. We show this on an concrete example.

In a chorus.ml file, consider the chorus function that prints repeatedly a given message :

let chorus count msg = for i = 1 to count do print_endline msg done

we want to make it available from the command line with the synopsis:

chorus [-c COUNT | --count=COUNT] [MSG]

where COUNT defaults to 10 and MSG defaults to "Revolt!". We first define a term corresponding to the --count option:

let count =
+Revolt!

Term syntax

There is a special syntax that uses OCaml's binding operators for writing terms which is less error prone when the number of arguments you want to give to your function grows. In particular it allows you to easily lift functions which have labels.

So in fact the program we have just shown above is usually rather written this way:

let revolt () = print_endline "Revolt!"
+
+open Cmdliner
+open Cmdliner.Term.Syntax
+
+let cmd_revolt =
+  Cmd.make (Cmd.info "revolt") @@
+  let+ () = Term.const () in
+  revolt ()
+
+let main () = Cmd.eval cmd_revolt
+let () = if !Sys.interactive then () else exit (main ())

Command line arguments as terms

The combinators in the Cmdliner.Arg module allow to extract command line arguments as terms. These terms can then be applied to lifted OCaml functions to be evaluated. A term that uses terms that correspond to command line argument implicitely defines a command line syntax fragment. We show this on an concrete example.

In a chorus.ml file, consider the chorus function that prints repeatedly a given message :

let chorus ~count msg = for i = 1 to count do print_endline msg done

we want to make it available from the command line with the synopsis:

chorus [-c COUNT | --count=COUNT] [MSG]

where COUNT defaults to 10 and MSG defaults to "Revolt!". We first define a term corresponding to the --count option:

open Cmdliner
+open Cmdliner.Term.Syntax
+
+let count =
   let doc = "Repeat the message $(docv) times." in
-  Arg.(value & opt int 10 & info ["c"; "count"] ~docv:"COUNT" ~doc)

This says that count is a term that evaluates to the value of an optional argument of type int that defaults to 10 if unspecified and whose option name is either -c or --count. The arguments doc and docv are used to generate the option's man page information.

The term for the positional argument MSG is:

let msg =
+  Arg.(value & opt int 10 & info ["c"; "count"] ~doc ~docv:"COUNT")

This says that count is a term that evaluates to the value of an optional argument of type int that defaults to 10 if unspecified and whose option name is either -c or --count. The arguments doc and docv are used to generate the option's man page information.

The term for the positional argument MSG is:

let msg =
   let env =
     let doc = "Overrides the default message to print." in
     Cmd.Env.info "CHORUS_MSG" ~doc
   in
   let doc = "The message to print." in
-  Arg.(value & pos 0 string "Revolt!" & info [] ~env ~docv:"MSG" ~doc)

which says that msg is a term whose value is the positional argument at index 0 of type string and defaults to "Revolt!" or the value of the environment variable CHORUS_MSG if the argument is unspecified on the command line. Here again doc and docv are used for the man page information.

The term for executing chorus with these command line arguments is :

let chorus_t = Term.(const chorus $ count $ msg)

We are now ready to define the main function of our tool:

let cmd =
-  let doc = "print a customizable message repeatedly" in
+  Arg.(value & pos 0 string "Revolt!" & info [] ~env ~doc ~docv:"MSG")

which says that msg is a term whose value is the positional argument at index 0 of type string and defaults to "Revolt!" or the value of the environment variable CHORUS_MSG if the argument is unspecified on the command line. Here again doc and docv are used for the man page information.

We can now define a term and command for invoking the chorus function using the term syntax and the obscure but handy let-punning OCaml notation. This also shows that the value Cmdliner.Cmd.info can be given more information about the term we execute which is notably used to to generate the tool's man page.

let chorus_cmd =
+  let doc = "Print a customizable message repeatedly" in
   let man = [
     `S Manpage.s_bugs;
     `P "Email bug reports to <bugs@example.org>." ]
   in
-  let info = Cmd.info "chorus" ~version:"%‌%VERSION%%" ~doc ~man in
-  Cmd.v info chorus_t
+  Cmd.make (Cmd.info "chorus" ~version:"v2.0.0" ~doc ~man) @@
+  let+ count and+ msg in
+  chorus ~count msg
 
-let main () = exit (Cmd.eval cmd)
-let () = main ()

The info value created with Cmdliner.Cmd.info gives more information about the term we execute and is used to generate the tool's man page. Since we provided a ~version string, the tool will automatically respond to the --version option by printing this string.

A tool using Cmdliner.Cmd.eval always responds to the --help option by showing the tool's man page generated using the information you provided with Cmdliner.Cmd.info and Cmdliner.Arg.info. Here is the output generated by our example:

> ocamlfind ocamlopt -linkpkg -package cmdliner -o chorus chorus.ml
+let main () = Cmd.eval chorus_cmd
+let () = if !Sys.interactive then () else exit (main ())

Since we provided a ~version string, the tool will automatically respond to the --version option by printing this string.

Besides a tool using Cmdliner.Cmd.eval always responds to the --help option by showing the tool's man page generated using the information you provided with Cmdliner.Cmd.info and Cmdliner.Arg.info. Here is the manual generated by our example:

> ocamlfind ocamlopt -linkpkg -package cmdliner -o chorus chorus.ml
 > ./chorus --help
 NAME
        chorus - Print a customizable message repeatedly
@@ -64,4 +80,4 @@ ENVIRONMENT
            Overrides the default message to print.
 
 BUGS
-       Email bug reports to <bugs@example.org>.

If a pager is available, this output is written to a pager. This help is also available in plain text or in the groff man page format by invoking the program with the option --help=plain or --help=groff.

For examples of more complex command line definitions look and run the examples.

Sub commands

Cmdliner also provides support for programs like git that have sub commands each with their own command line syntax and manual:

tool [COMMAND]… [OPTION]… ARG…

These sub commands are defined by grouping them under a parent command via the Cmdliner.Cmd.group function.

+ Email bug reports to <bugs@example.org>.

If a pager is available, this output is written to a pager. This help is also available in plain text or in the groff man page format by invoking the program with the option --help=plain or --help=groff.

And with this you should master the basics of Cmdliner, for examples of more complex command line definitions consult the examples. For more tips, off-the-shelf recipes and conventions have look at the cookbook.

diff --git a/index.html b/index.html index 06c6f5b8..0971242b 100644 --- a/index.html +++ b/index.html @@ -1,2 +1,2 @@ -_opam

OCaml package documentation

Browse by name, by tag, the standard library and the OCaml manual (online, latest version).

Generated for /home/runner/work/linol/linol/_opam/lib

\ No newline at end of file +_opam

OCaml package documentation

Browse by name, by tag, the standard library and the OCaml manual (online, latest version).

Generated for /home/runner/work/linol/linol/_opam/lib

\ No newline at end of file diff --git a/linol-lwt/_doc-dir/CHANGES.md b/linol-lwt/_doc-dir/CHANGES.md index 82fbcdfd..c24db338 100644 --- a/linol-lwt/_doc-dir/CHANGES.md +++ b/linol-lwt/_doc-dir/CHANGES.md @@ -1,4 +1,9 @@ +# 0.11 + +- breaking: the Eio library now needs the output channel to be paired with + an `Eio.Mutex.t` to prevent race conditions (#58) + # 0.10 - use `git subtree` to vendor lsp+jsonrpc, so that they diff --git a/linol/_doc-dir/CHANGES.md b/linol/_doc-dir/CHANGES.md index 82fbcdfd..c24db338 100644 --- a/linol/_doc-dir/CHANGES.md +++ b/linol/_doc-dir/CHANGES.md @@ -1,4 +1,9 @@ +# 0.11 + +- breaking: the Eio library now needs the output channel to be paired with + an `Eio.Mutex.t` to prevent race conditions (#58) + # 0.10 - use `git subtree` to vendor lsp+jsonrpc, so that they diff --git a/logs/Logs_cli/index.html b/logs/Logs_cli/index.html index 7861f752..233317eb 100644 --- a/logs/Logs_cli/index.html +++ b/logs/Logs_cli/index.html @@ -11,7 +11,7 @@ Logs.warn (fun m -> m "Something bad may happen in the future."); if Logs.err_count () > 0 then 1 else 0 -let setup_log style_renderer level = +let setup_log ~style_renderer ~level = Fmt_tty.setup_std_outputs ?style_renderer (); Logs.set_level level; Logs.set_reporter (Logs_fmt.reporter ()) @@ -19,17 +19,20 @@ let setup_log style_renderer level = (* Command line interface *) open Cmdliner +open Cmdliner.Term.Syntax -let setup_log = +let cmd = + Cmd.make (Cmd.info "tool") @@ let env = Cmd.Env.info "TOOL_VERBOSITY" in - Term.(const setup_log $ Fmt_cli.style_renderer () $ Logs_cli.level ~env ()) + let+ style_renderer = Fmt_cli.style_renderer () + and+ level = Logs_cli.level ~env () + and+ msg = + let doc = "The message to output." in + Arg.(value & pos 0 string "Hello horrible world!" & info [] ~doc) + in + setup_log ~style_renderer ~level; + hello msg -let msg = - let doc = "The message to output." in - Arg.(value & pos 0 string "Hello horrible world!" & info [] ~doc) - -let main () = - let cmd = Cmd.make (Cmd.info "tool") Term.(const hello $ setup_log $ msg) in - Cmd.eval' cmd +let main () = Cmd.eval' cmd let () = if !Sys.interactive then () else exit (main ()) diff --git a/logs/_doc-dir/CHANGES.md b/logs/_doc-dir/CHANGES.md index ce6f2525..f8982b69 100644 --- a/logs/_doc-dir/CHANGES.md +++ b/logs/_doc-dir/CHANGES.md @@ -1,3 +1,9 @@ +v0.10.0 2025-11-04 Zagreb +------------------------- + +* Make log mutex immune to raising logging functions. + Thanks to Nathan Taylor for the report and the repro (#57). + v0.9.0 2025-07-08 Zagreb ------------------------ @@ -11,7 +17,7 @@ v0.9.0 2025-07-08 Zagreb * `Logs.format_reporter` and `Logs_fmt.reporter` replace a few format strings and `^^` uses by direct calls to `Format` primitives. * Requires OCaml >= 4.14. -* Use Format.pp_print_text instead of your own. +* Use Format.pp_print_text instead of our own. * Export `logs` from each sub library. v0.8.0 2025-03-10 La Forclaz (VS) diff --git a/logs/_doc-dir/odoc-pages/index.mld b/logs/_doc-dir/odoc-pages/index.mld index 76d2804c..f31cb9a8 100644 --- a/logs/_doc-dir/odoc-pages/index.mld +++ b/logs/_doc-dir/odoc-pages/index.mld @@ -1,4 +1,4 @@ -{0 Logs {%html: v0.9.0%}} +{0 Logs {%html: v0.10.0%}} Logs provides a logging infrastructure. diff --git a/lwt/_doc-dir/CHANGES b/lwt/_doc-dir/CHANGES index 76a6cdb8..efcea74b 100644 --- a/lwt/_doc-dir/CHANGES +++ b/lwt/_doc-dir/CHANGES @@ -1,3 +1,21 @@ +===== 5.9.1 ===== + +====== Packaging ====== + + * lwt_ppx is compatible with newer versions of ppxlib. (Patrick Ferris, Kate Deplaix, Sora Morimoto, #1033) + +====== Other ====== + + * Misc repository maintenance. (Sora Morimoto) + + * Misc typo. (Kaustubh Maske Patil, #1056) + +===== 5.9.1 ===== + +====== Fixes ====== + + * META files now carry version information. (Hugo Heuzard, #1042, #1053) + ===== 5.9.0 ===== ====== Additions ====== @@ -14,6 +32,12 @@ * Misc repository maintenance. (Sora Morimoto, Shon Feder, #1037, #1035) +===== 5.8.1 ===== + +====== Fixes ====== + + * META files now carry version information. (Hugo Heuzard, #1042, #1053) + ===== 5.8.0 ===== ====== Improvements ====== diff --git a/ocaml/index.html b/ocaml/index.html index cf9bf04b..6e808141 100644 --- a/ocaml/index.html +++ b/ocaml/index.html @@ -1,2 +1,2 @@ -index (ocaml.index)

Package ocaml

Stdlib

Threads

  • Event First-class synchronous communication.
  • Thread Lightweight threads for Posix 1003.1c and Win32.

Compiler libs

Package info

changes-files
license-files
readme-files
+index (ocaml.index)

Package ocaml

Library stdlib

Library unix

  • Unix Interface to the Unix system.
  • UnixLabels Interface to the Unix system.
  • Dynlink Dynamic loading of .cmo, .cma and .cmxs files.

Library runtime_events

Library str

  • Str Regular expressions and high-level string processing

Library threads

  • Event First-class synchronous communication.
  • Thread Lightweight threads for Posix 1003.1c and Win32.

Library ocamldoc

Library compiler-libs

Package info

changes-files
license-files
readme-files