Closed lordvlad closed 5 years ago
The short answer is cligen
's usage probably will not be the most appropriate thing to print.
A big part of the time-saving/convenience of cligen
is to autogenerate its usage based on some syntax. It seems like you are creating your own sub-syntax within args
. That is fine as far as it goes, but to explain that sub-syntax you will have to build your own usage message.
Indeed, if you are only ever operating on args: seq[string]
, cligen
may provide very little/no value added: there's no native type conversion, you probably need your own help, you are doing your own larger syntax, and your proc is CLI-only. Even parseopt*
probably provides no real value add in this case.
All that said, I do provide pretty arbitrary ways to do things with parseOnly
. See test/ParseOnly.nim
for example usage. You can see, for example, how to access the .message
field in the if clHelpOnly in fooParse:
clause. That example does not actually dispatch, but you could just add another dispatchFoo(parseOnly=false)
(or simply no argument at all) to do that.
Thanks for the quick answer. Is there maybe a better way to support positional arguments together with non-optional arguments? What I'd love to have is:
configure(key, value="")
and call it simply with
my_cli config key
got get some configuration and
my_cli config key value
to set some configuration
Unless/until you have more params that aren't just generic string
, you are probably better off just directly parsing os.commandLineParams()
. You basically have that parser written already. Seems like you may want the user to be required to type a "config"
argument.
For example, if you put the below in a file called my_cli.nim
you get what you want (obviously needing to flesh out (get|set)_config
and the help message):
import os, sets
proc get_config(k: string) = echo "get ", k
proc set_config(k, v: string) = echo "set ", k, " = ", v
proc usage(extra="", status=0) =
echo "help: ", extra
quit(status)
const helps = [ "help", "--help", "-h" ].toSet
let args = commandLineParams()
if args.len < 1 or args[0] in helps: usage("", 0)
if args[0] != "config": usage("bad command", 1)
elif args.len == 1: usage("too few arguments", 1)
if args.len == 2: get_config(args[1])
elif args.len == 3: set_config(args[1], args[2])
else: usage("too many arguments", 1)
If you were writing a module that had an import
-able configure
usable by Nim code instead of the CLI, or add params, or so on then you might be able to use cligen.dispatchMulti
with a cmdName
of "config"
(or just name the proc
config
in the first place). Really it would just take seq[string]
, too, though. If empty string is an invalid "set" value then you could probably do something, but I don't see cligen
as helping you very much in this use case.
cligen
(is not about/was never about) trying to create any conceivable command syntax..Only a couple convenient/quasi-standard syntaxes. There was some discussion here https://github.com/c-blake/cligen/issues/62 about a new way to set positional
that might potentially help. That work is not done yet, it might still not be exactly what you would want, and I have no personal need for this feature. If you wanted to work on a pull request, I'm not anti-inclusion of the feature, though.
thanks for the detailed answer
just found the mention of positionals in your TODO.md
. Is this planned for the near future?
That TODO item is not something I plan on working on as I don't have a need for that feature, as mentioned, but I'm open to someone else having a try and doing a PR or something.
not an issue really, I just can't figure it out, I guess. Since cligen currently does not support non-optional positional arguments as far as i can tell, I'm using something along the lines
What I want to do instead of only raising the error is printing the usage for the configure subcommand before exiting with exitCode 1.