# \[ANN\] First release of ppx\_subliner, a ppx deriver and rewriter for Cmldliner sub-command

**URL:** https://discuss.ocaml.org/t/ann-first-release-of-ppx-subliner-a-ppx-deriver-and-rewriter-for-cmldliner-sub-command/11610
**Category:** Ecosystem
**Tags:** announce, cmdliner, ppxlib
**Created:** [March 8, 2023, 2:29am UTC](https://discuss.ocaml.org/t/ann-first-release-of-ppx-subliner-a-ppx-deriver-and-rewriter-for-cmldliner-sub-command/11610 "2023-03-08T02:29:21Z")
**Posts on this page:** 1
**Page:** 1

<div class="post-metadata">

### Author: ![bn-d](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/bn-d/32/6471_2.png) [@bn-d](https://discuss.ocaml.org/u/bn-d)
#### Post date: [March 8, 2023, 2:29am UTC](https://discuss.ocaml.org/t/ann-first-release-of-ppx-subliner-a-ppx-deriver-and-rewriter-for-cmldliner-sub-command/11610/1 "2023-03-08T02:29:21Z")

</div>

I am very pleased to announce the first release of [`ppx_subliner`](https://github.com/bn-d/ppx_subliner)! The package is now available through [OPAM](https://opam.ocaml.org/packages/ppx_subliner/).

I am always a big fan of [`ppx_deriving_cmdliner`](https://github.com/hammerlab/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.

```ocaml
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.

```ocaml
let handle = function
  | Foo { my_arg } -> print_endline ("Foo " ^ my_arg)
  | Bar -> print_endline "Bar" 

```

From here, you either construct the final evaluation manually:

```ocaml
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:

```ocaml
(* {eval function}.{type name} <- {function expression> *)

```

```ocaml
[%%subliner.cmds eval.params <- handle]
[@@name "foobar"] [@@version "3.14"]
(** Some docs *)

```

```console
$ 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:

```ocaml
[%%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](https://boni.ng/ppx_subliner/ppx_subliner/index.html).

#### 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!

> **[GitHub - bn-d/ppx\_subliner: \[@@ deriving\] plugin to generate Cmdliner...](https://github.com/bn-d/ppx_subliner)**
>
> \[@@ deriving\] plugin to generate Cmdliner sub-command groups, and ppx rewriter to generate Cmdliner evaluations.
