mirror of
https://github.com/c-cube/linol.git
synced 2025-12-08 04:05:46 -05:00
203 lines
5.8 KiB
Text
Executable file
203 lines
5.8 KiB
Text
Executable file
{0:tutorial Tutorial}
|
||
|
||
{1:started 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
|
||
|
||
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.val-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
|
||
> ./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 =
|
||
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 =
|
||
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
|
||
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
|
||
|
||
let main () = exit (Cmd.eval cmd)
|
||
let () = 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.
|
||
|
||
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:
|
||
|
||
{v
|
||
> ocamlfind ocamlopt -linkpkg -package cmdliner -o chorus chorus.ml
|
||
> ./chorus --help
|
||
NAME
|
||
chorus - Print a customizable message repeatedly
|
||
|
||
SYNOPSIS
|
||
chorus [--count=COUNT] [OPTION]… [MSG]
|
||
|
||
ARGUMENTS
|
||
MSG (absent=Revolt! or CHORUS_MSG env)
|
||
The message to print.
|
||
|
||
OPTIONS
|
||
-c COUNT, --count=COUNT (absent=10)
|
||
Repeat the message COUNT times.
|
||
|
||
COMMON OPTIONS
|
||
--help[=FMT] (default=auto)
|
||
Show this help in format FMT. The value FMT must be one of auto,
|
||
pager, groff or plain. With auto, the format is pager or plain
|
||
whenever the TERM env var is dumb or undefined.
|
||
|
||
--version
|
||
Show version information.
|
||
|
||
EXIT STATUS
|
||
chorus exits with the following status:
|
||
|
||
0 on success.
|
||
|
||
123 on indiscriminate errors reported on standard error.
|
||
|
||
124 on command line parsing errors.
|
||
|
||
125 on unexpected internal errors (bugs).
|
||
|
||
ENVIRONMENT
|
||
These environment variables affect the execution of chorus:
|
||
|
||
CHORUS_MSG
|
||
Overrides the default message to print.
|
||
|
||
BUGS
|
||
Email bug reports to <bugs@example.org>.
|
||
v}
|
||
|
||
If a pager is available, this output is written to a pager. This help
|
||
is also available in plain text or in the
|
||
{{:http://www.gnu.org/software/groff/groff.html}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 {{!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.
|