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.
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.
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.
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).
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.
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.
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.
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?