summaryrefslogtreecommitdiff
path: root/doc/tutorial.mld
blob: 528f9c4e4d8eec842b8d4c75d3ac0550f3db9254 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
{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 with a term of type {!Cmdliner.Term.t}.  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.