[ANN] Cmdliner 1.1.0

Hello,

It’s my pleasure to announce the release 1.1.0 of cmdliner. Cmdliner allows the declarative definition of command line interfaces in OCaml.

The main points of this release are:

  • Support for UTF-8 man pages.
  • Support for deprecating commands, arguments and environment variables.
  • Arbitrary sub command nesting, each with its own command line syntax and help page.

To bring in the latter but limit cruft and confusion, the API was reorganized around the notion of command. But except for the vagaries of introducing a new module in your scope, no existing program should be broken due to this.

However all programs will be subject to deprecation warnings to migrate to this new API. This being mostly a reorganization rather than a redesign, transitioning to it should be smooth (example for a simple tool), but a few defaults have been changed along the way.

Therefore make sure to read the release notes which have all the details and credits the people who gave a hand for this long delayed release; many thanks to them.

Finally a special thanks to @kit-ty-kate for her tremendous help and dedicated boring work in having this merged into the opam package repository.

If you have any question about the new API, use this thread.

Home page: https://erratique.ch/software/cmdliner
API docs & manuals: https://erratique.ch/software/cmdliner/doc/ or odig doc cmdliner
Install: opam install cmdliner

Best,

Daniel


A big thank to my donators and to the person who made a recent private donation.

37 Likes

Speaking of which I would be grateful if people could refrain from putting expect tests on cmdliner’s man page and error message output in the test suites that are run by default on the opam repository.

Cmdliner’s man page and error messages are not part of its interface and subject to change from version to version. Having packages fail in the CI because of this is unhelpful and time consuming.

4 Likes

Hi @dbuenzli,

Thank you for the release, these changes, especially the arbitrary sub command nesting, look really promising!

Yet, it has been a while since I have followed your work (so sorry if it is already possible) but do you plan or are interested in supporting an automatic generation of auto-completion facility? Indeed, it seems possible to complete command names, flags and file arguments (and potentially custom provided arguments) from the declarative information. Doing this in this library sounds to be the best place.

Regards,

Yes, completion is the long standing issue number 1 !

The lack of real shell standard and the arcane systems shells provide are part of the problem.

Nevertheless I made a bit of progress. I wanted to have something for it in this release but I ran out of time and didn’t want to further block this long due release.

If people are interested in moving this forward the best way is to contribute a prototype for me to look at (e.g. that’s the way arbitrary subcommands eventually happened thanks to a prototype by @rgrinberg).

3 Likes

Has this new version introduced a new way of having common options for all sub-commands? For instance, git has -C or --no-pager that are used before sub-commands. In ocluster, we have a small hack to move around a global option in Sys.argv.

Not sure exactly what you mean by that but:

  1. You could always have common options for all sub-commands: simply define a term for them and use them in all sub-commands. All sub-commands will share these options.

  2. From an end-user perspective however you always have to write (sub)commands before any optional arguments.

Regarding 2. I wanted to lift that limitation to allow to define optional arguments before sub commands, but was quickly reminded by reality that given the rather flexible way cmdliner parses option arguments – namely that option arguments need not be glued to their option (--output file, -o file) and that option arguments can be optional, (e.g. see --help) this quickly becomes too ambiguous and confusing. In fact I even remember destroying my opam switch because this was breaking some js_of_ocaml invocations made by build systems.

Already having optional subcommands is borderline (but I kept it because I think it’s an established and useful pattern): in this case you always have to use the -- token for positional arguments if you don’t mention the subcommand, otherwise the first positional argument will be interpreted as a subcommand name.

The actual end user syntax parsed by cmdliner is described in this manual.

1 Like

That’s what I wanted, thanks for the explanation.

I’ve experimented with auto-completion for small interactive tools a while ago, and although this is not shell auto-completion, it might be nice to provide an API to generate auto-completions from a cmdliner declaration independently of the UI used for the auto-completion (shell, lambda-term, notty, etc.).
Here is what I ended up with: https://v3.ocaml.org/p/cmdtui/0.4.3/doc/Cmdtui/index.html#type-completion (inspired by cmdliner, utop and the auto-completion in the redis CLI, but quite minimal).
I’m not sure how useful an auto-completion API in cmdliner would be, the main use-case for auto-completion is probably shell completion (which the library above doesn’t help with), and adapting the above complete API to support the full composability of cmdliner would be non-trivial. However if you think it is useful I could think about how to integrate a complete-like API into cmdliner itself. What do you think?

For shell completion have you looked at how this is handled in other ecosystems? E.g. clap/clap_complete/src/shells at master · clap-rs/clap · GitHub (which might help figuring out how the glue code between the shell and cmdliner could look like)

1 Like

New sub commands are great but I wish I could use custom parser for default case so I could for example use cmd 123 as a shortcut for cmd get 123.

That of course would not work in every case, its less error prone and more predictable for end-users to be uniform.

1 Like

For those of us getting deprecation notices/errors when upgrading to cmdliner 1.1, I updated the examples of my cmdliner cheatsheet.

5 Likes

I tried the installation instructions in the firs post, but I get the following:

$ opam install cmdliner
[NOTE] Package cmdliner is already installed (current version is 1.0.4).

Is the new version “officially” released yet ?

Edit: as a complement, here is another output:

$ opam show cmdliner

<><> cmdliner: information on all versions ><><><><><><><><><><><><><><><><><><>
name                   cmdliner
all-installed-versions 1.0.4 [default 4.13.1]
all-versions           0.9.2  0.9.4  0.9.5  0.9.6  0.9.7  0.9.8  1.0.0  1.0.1  1.0.2  1.0.3  1.0.4  1.1.0

<><> Version-specific details <><><><><><><><><><><><><><><><><><><><><><><><><>
version       1.0.4
repository    default
...

(in the line “all versions”, 1.0.4 is in bold). And

$ opam list --installable cmdliner
# Packages matching: installable & name-match(cmdliner)
# Name   # Installed # Synopsis
cmdliner 1.0.4       Declarative definition of command line interfaces for OCaml
$ 

So I tried the following:

$ opam install cmdliner.1.1.0
The following actions will be performed:
  ⊘ remove    ocamlformat-rpc 0.20.1         [conflicts with cmdliner]

opam info shows you the package constraints, confirming your findings:

$ opam info ocamlformat-rpc
...
depends      "dune" {>= "2.8"}
...
             "cmdliner" {< "1.1.0"}
...
1 Like