mirror of
https://github.com/c-cube/linol.git
synced 2025-12-06 03:05:31 -05:00
83 lines
9.8 KiB
HTML
83 lines
9.8 KiB
HTML
<!DOCTYPE html>
|
||
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>tutorial (cmdliner.tutorial)</title><meta charset="utf-8"/><link rel="stylesheet" href="../_odoc-theme/odoc.css"/><meta name="generator" content="odoc 3.1.0"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/><script src="../highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body class="odoc"><nav class="odoc-nav"><a href="index.html">Up</a> – <a href="../index.html">Index</a> » <a href="index.html">cmdliner</a> » tutorial</nav><header class="odoc-preamble"><h1 id="tutorial"><a href="#tutorial" class="anchor"></a>Tutorial</h1><p>See also the <a href="cookbook.html" title="cookbook">cookbook</a>, <a href="cookbook.html#blueprints" title="blueprints">blueprints</a> and <a href="examples.html" title="examples">examples</a>.</p></header><div class="odoc-tocs"><nav class="odoc-toc odoc-local-toc"><ul><li><a href="#terms">Commands and terms</a></li><li><a href="#term_syntax">Term syntax</a></li><li><a href="#args_as_terms">Command line arguments as terms</a></li></ul></nav></div><div class="odoc-content"><h2 id="terms"><a href="#terms" class="anchor"></a>Commands and terms</h2><p>With <code>Cmdliner</code> your tool's <code>main</code> function evaluates a command.</p><p>A command is a value of type <a href="Cmdliner/Cmd/index.html#type-t"><code>Cmdliner.Cmd.t</code></a> which gathers a command name and a term of type <a href="Cmdliner/Term/index.html#type-t"><code>Cmdliner.Term.t</code></a>. 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.</p><p>One way to create terms is by lifting regular OCaml values with <a href="Cmdliner/Term/index.html#val-const"><code>Cmdliner.Term.const</code></a>. Terms can be applied to terms evaluating to functional values with <a href="Cmdliner/Term/index.html#val-app"><code>Cmdliner.Term.app</code></a>.</p><p>For example, in a <code>revolt.ml</code> file, for the function:</p><pre class="language-ocaml"><code>let revolt () = print_endline "Revolt!"</code></pre><p>the term :</p><pre class="language-ocaml"><code>open Cmdliner
|
||
|
||
let revolt_term = Term.app (Term.const revolt) (Term.const ())</code></pre><p>is a term that evaluates to the result (and effect) of the <code>revolt</code> function. This term can be associated to a command:</p><pre class="language-ocaml"><code>let cmd_revolt = Cmd.make (Cmd.info "revolt") revolt_term</code></pre><p>and evaluated with <a href="Cmdliner/Cmd/index.html#val-eval"><code>Cmdliner.Cmd.eval</code></a>:</p><pre class="language-ocaml"><code>let main () = Cmd.eval cmd_revolt
|
||
let () = if !Sys.interactive then () else exit (main ())</code></pre><p>This defines a command line tool named <code>"revolt"</code> (this name will be used in error reporting and documentation generation), without command line arguments, that just prints <code>"Revolt!"</code> on <code>stdout</code>.</p><pre class="language-sh"><code>> ocamlfind ocamlopt -linkpkg -package cmdliner -o revolt revolt.ml
|
||
> ./revolt
|
||
Revolt!</code></pre><h2 id="term_syntax"><a href="#term_syntax" class="anchor"></a>Term syntax</h2><p>There is a special syntax that uses OCaml's <a href="https://ocaml.org/manual/5.3/bindingops.html">binding operators</a> 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.</p><p>So in fact the program we have just shown above is usually rather written this way:</p><pre class="language-ocaml"><code>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 ())</code></pre><h2 id="args_as_terms"><a href="#args_as_terms" class="anchor"></a>Command line arguments as terms</h2><p>The combinators in the <a href="Cmdliner/Arg/index.html"><code>Cmdliner.Arg</code></a> 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.</p><p>In a <code>chorus.ml</code> file, consider the <code>chorus</code> function that prints repeatedly a given message :</p><pre class="language-ocaml"><code>let chorus ~count msg = for i = 1 to count do print_endline msg done</code></pre><p>we want to make it available from the command line with the synopsis:</p><pre class="language-sh"><code>chorus [-c COUNT | --count=COUNT] [MSG]</code></pre><p>where <code>COUNT</code> defaults to <code>10</code> and <code>MSG</code> defaults to <code>"Revolt!"</code>. We first define a term corresponding to the <code>--count</code> option:</p><pre class="language-ocaml"><code>open Cmdliner
|
||
open Cmdliner.Term.Syntax
|
||
|
||
let count =
|
||
let doc = "Repeat the message $(docv) times." in
|
||
Arg.(value & opt int 10 & info ["c"; "count"] ~doc ~docv:"COUNT")</code></pre><p>This says that <code>count</code> is a term that evaluates to the value of an optional argument of type <code>int</code> that defaults to <code>10</code> if unspecified and whose option name is either <code>-c</code> or <code>--count</code>. The arguments <code>doc</code> and <code>docv</code> are used to generate the option's man page information.</p><p>The term for the positional argument <code>MSG</code> is:</p><pre class="language-ocaml"><code>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 ~doc ~docv:"MSG")</code></pre><p>which says that <code>msg</code> is a term whose value is the positional argument at index <code>0</code> of type <code>string</code> and defaults to <code>"Revolt!"</code> or the value of the environment variable <code>CHORUS_MSG</code> if the argument is unspecified on the command line. Here again <code>doc</code> and <code>docv</code> are used for the man page information.</p><p>We can now define a term and command for invoking the <code>chorus</code> function using the <a href="#term_syntax" title="term_syntax">term syntax</a> and the obscure but handy <a href="https://ocaml.org/manual/5.2/bindingops.html#ss%3Aletops-punning">let-punning</a> OCaml notation. This also shows that the value <a href="Cmdliner/Cmd/index.html#val-info"><code>Cmdliner.Cmd.info</code></a> can be given more information about the term we execute which is notably used to to generate the tool's man page.</p><pre class="language-ocaml"><code>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
|
||
Cmd.make (Cmd.info "chorus" ~version:"v2.1.0" ~doc ~man) @@
|
||
let+ count and+ msg in
|
||
chorus ~count msg
|
||
|
||
let main () = Cmd.eval chorus_cmd
|
||
let () = if !Sys.interactive then () else exit (main ())</code></pre><p>Since we provided a <code>~version</code> string, the tool will automatically respond to the <code>--version</code> option by printing this string.</p><p>Besides a tool using <a href="Cmdliner/Cmd/index.html#val-eval"><code>Cmdliner.Cmd.eval</code></a> always responds to the <code>--help</code> option by showing the tool's man page <a href="tool_man.html#manual" title="manual">generated</a> using the information you provided with <a href="Cmdliner/Cmd/index.html#val-info"><code>Cmdliner.Cmd.info</code></a> and <a href="Cmdliner/Arg/index.html#val-info"><code>Cmdliner.Arg.info</code></a>. Here is the manual generated by our example:</p><pre>> 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>.</pre><p>If a pager is available, this output is written to a pager. This help is also available in plain text or in the <a href="http://www.gnu.org/software/groff/groff.html">groff</a> man page format by invoking the program with the option <code>--help=plain</code> or <code>--help=groff</code>.</p><p>And with this you should master the basics of Cmdliner, for examples of more complex command line definitions consult the <a href="examples.html" title="examples">examples</a>. For more tips, off-the-shelf recipes and conventions have look at the <a href="cookbook.html" title="cookbook">cookbook</a>.</p></div></body></html>
|