Hi everyone,
I have been working on a small library called smartcli:
https://github.com/planetis-m/smartcli
The goal is simple: write a help text block once, and get both a small CLI parser and a typed options object from it at compile time.
More specifically, this is a nimony plugin, so cliapp"""...""" expands into the parser and typed result during compilation.
It is aimed at nimony projects that want something docopt-like without pulling in a larger parser layer or dropping back to manual argument loops.
The design direction came from @Araq's idea here:
https://forum.nim-lang.org/t/13777#83561
The shape is:
import smartcli
let options = cliapp"""Greeter v0.1
This program greets.
Usage: greeter [options] INPUT greet|version
Arguments:
INPUT Input file
Commands:
greet Greets
version Displays version and quits
Options:
--mode=fast|slow Output mode
--output=FILE Output file
-v, --verbose Enable verbose output
-h, --help Show this help and exit"""
echo options.input
echo options.output
echo options.verbose
echo options.command
echo options.mode
From that spec, smartcli generates parser code plus typed fields:
The part I like most is that the help text stays the source of truth, but the result is still typed enough to feel pleasant in normal Nim code.
Current scope is intentionally small:
This is not trying to be a full docopt implementation. Right now it is more of a minimal compile-time DSL for the common shape of small CLIs.
If this direction seems useful, the main thing I would like feedback on is the command shape.
Right now smartcli assumes positional arguments come first and the command comes last:
tool INPUT greet
Would it make more sense to design around command-first CLIs instead:
tool greet INPUT
Or is the current shape reasonable for a small DSL like this?
I would also appreciate feedback on:
Thanks. Any criticism is welcome.
Would it make more sense to design around command-first CLIs instead
Yes, definitely.