Cmdliner supports argument values like bool
, int
, dir
or file
but these can be extended with custom types. I would be interested in an example for this. For example, I’d like to support min:sec
durations or ISO date-time strings. One needs to provide a parser and a printer for each. Conceptually this is not difficult but I struggle with the maze of types in cmdliner.mli.
The loc_arg
in this sample code of the documentation shows this. HTH.
From the documentation mentioned:
let loc_arg =
let parse 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")
in
let print ppf p = Format.fprintf ppf "%s" (loc_str p) in
Arg.conv ~docv:"N" (parse, print)
My own converter for min:sec
values:
open Rresult
module C = Cmdliner
let msg fmt = Printf.ksprintf (fun str -> `Msg str) fmt
let min_sec =
let parse str =
try R.ok (Scanf.sscanf str "%u:%u" (fun min sec -> (min * 60) + sec))
with _ -> R.error (msg "Can't parse %s as min:sec value" str)
in
let print ppf sec = Format.fprintf ppf "%d:%0d" (sec / 60) (sec mod 60) in
C.Arg.conv ~docv:"S" (parse, print)
let duration =
C.Arg.(
value & opt min_sec 30
& info [ "d"; "duration" ] ~docv:"DURATION"
~doc:"Duration in min:sec of video (and data to extract)")
A good way to find example uses of this or other API is sherlocode:
Sherlocode(%5C%3Fconv%20
EDIT: this markdown parser struggles with the URL so here it is: https://sherlocode.com/?q=Arg.(%5C%3Fconv%20
Would it be of interest to add more (extra) command line types to Cmdliner
that could be provided by the community @dbuenzli? I could imagine:
- date and time values as discussed above
- 2^n value like
1k
,3M
(or1kib
)
You probably want to avoid introducing new dependencies just for this, which eliminates a complex syntax like an URI or similar.
I don’t think these should belong in the cmdliner package (to avoid introducing additional dependencies to everyone). But either of the two following proposals could make sense:
- start opening PRs on your library
foo
(be it for calendar, colour, geometry, or whathaveyou) to add a new packagefoo-cmdliner
in the repo - start a
cmdliner-convs
project which publishes several small packages: one for each library you want convs for
In general I already find cmdliner
to be too much code for what it’s doing, so I rather not add too much there. Especially since this code will end up in each executable even if not used.
The problem for date, time an durations is that there’s no unique answer on how to represent them. For specifying bytes amount it’s a bit less (but still, an int
, an int64
?) and then there’s the problem of SI prefixes vs SI binary prefixes.
So for the time being I find @raphael-proust’s answer more adequate :–)