I am very pleased to announce the first release of ppx_subliner
! The package is now available through OPAM.
I am always a big fan of ppx_deriving_cmdliner
. It helps you construct Cmdliner.Term.t
from record types and makes writing cli parsing intuitive and painless. But it lacks the ability to generate values for sub-command groups and the final Cmdliner
evaluations. Therefore, ppx_subliner
comes to life.
ppx_subliner
can work with ppx_deriving_cmdliner
to generate sub-command groups. You can do so by simply tagging the extension to a variant type.
type foo = { my_arg : string } [@@deriving cmdliner]
type params =
| Foo of foo
| Bar
[@@deriving_inline subliner]
include
sig
[@@@ocaml.warning "-32"]
val params_cmdliner_group_cmds : (params -> 'a) -> 'a Cmdliner.Cmd.t list
end[@@ocaml.doc "@inline"]
[@@@end]
It will generate a function which takes in a handle function and return the sub-command list. Here is a simple handle function.
let handle = function
| Foo { my_arg } -> print_endline ("Foo " ^ my_arg)
| Bar -> print_endline "Bar"
From here, you either construct the final evaluation manually:
let cmd =
let open Cmdliner in
let doc = "Some docs" in
let info = Cmd.info ~doc "foobar" in
Cmd.group info (params_cmdliner_group_cmds handle)
let () = exit (Cmdliner.eval cmd)
or use the [%%subliner.cmds]
rewriter, which reuses the setfield syntax:
(* {eval function}.{type name} <- {function expression> *)
[%%subliner.cmds eval.params <- handle]
[@@name "foobar"] [@@version "3.14"]
(** Some docs *)
$ foobar.exe foo --my-arg 123
Foo 123
Both the deriver and rewriter will respect the OCaml docstring. You can also use [@name]
, [@man]
, [@envs]
etc to configure all aspects of the underlying Cmdliner.Cmd.info
value.
You can also use different evaluation function and set optional arguments:
[%%subliner.cmds (eval_result ~catch:false).params <-
(function
| Foo { my_arg } -> print_endline ("Foo " ^ my_arg) |> Result.ok
| Bar -> print_endline "Bar" |> Result.ok)]
Please see more details in the documentation.
What’s next
I want to support inline record and enum as arg in the future, and maybe replicate some of ppx_deriving_cmdliner
’s functionality, but better support for deriving_inline
, lists (ie. -I liba -I libb
instead of -I liba,libb
), positional arguments and more compile time validation. We shall see.
Hope this is helpful. Happy hacking!