When I first came to nim I was looking for a faster, type-safe alternative to python and it was love at first sight. But then I rapidly came unstuck trying to write anything in it, since I found parseopt lead to spaghetti code and there was no argparse available. Years later (after I left nim behind for a while), there's nim-argparse and docopt.nim but they weren't quite was I was looking for, and I still had a soft spot for parsing as a project. So, without further ado, I bring you therapist, a new command line parser.
A simple hello world example:
import therapist
# The parser is specified as a tuple
let spec = (
# Name is a positional argument, by virtue of being surrounded by < and >
name: newStringArg(@["<name>"], help="Person to greet"),
# --times is an optional argument, by virtue of starting with - and/or --
times: newIntArg(@["-t", "--times"], default=1, help="How many times to greet"),
# --version will cause 0.1.0 to be printed
version: newMessageArg(@["--version"], "0.1.0", help="Prints version"),
# --help will cause a help message to be printed
help: newHelpArg(@["-h", "--help"], help="Show help message"),
)
# `args` and `command` would normally be picked up from the commandline
spec.parseOrQuit(prolog="Greeter", args="-t 2 World", command="hello")
# If a help message or version was requested or a parse error generated it would be printed
# and then the parser would call `quit`. Getting past `parseOrQuit` implies we're ok.
for i in 1..spec.times.value:
echo "Hello " & spec.name.value
doAssert spec.name.seen
doAssert spec.name.value == "World"
doAssert spec.times.seen
doAssert spec.times.value == 2
Since this is my first library for nim, feedback (and that's not how you do it, try this) welcome!
You might also find https://github.com/c-blake/cligen interesting. The central insight is that a Nim proc signature (or Python or C++ or any language with default values...) already contains an adequate "spec".
More meaningful per parameter help is about all that is missing, but can be easily "added in" when identifier names & types alone are insufficient descriptions of their purpose.
There are other bells & whistles in cligen like prefix matching (bridging the gap from short to long options) that might also inspire you.
Thanks! argh and click were never really to my tastes aesthetically / from a readability point of view, but there's no denying they're highly efficient in terms of characters typed. I've added cligen to the alternatives menu (as well as case/style-insensitive pattern matching to the future options).
(Aside: another one of my side projects, a shell programming language, uses this insight in reverse - it uses command --foo=bar quux as the way to call command(quux, foo="bar"))