Closed SolitudeSF closed 5 years ago
On the parsing/input side, you can cut/paste redefine (post import
and pre-dispatch
) any of the standard ones from cligen/argcvt
to do whatever logic/sanitizing of user input. You can always switch off the value of ArgcvtParams.parNm
on a per parameter basis. On the output side there is argHelp
which also receives ArgcvtParams
and could list acceptable values to the user on a per-param basis. distinct
types can potentially help if you are also the author of the API being wrapped and want to switch in "batches" of similarly typed parameters. cligen
does understand enum
types pretty well, too, if your use case fits in with those.
You can look at test/FancyRepeats.nim
for e.g. usage of parNm
and test/Enums.nim
for enum
usage. There's really quite a bit of CLI-author control, but I don't know how much any of it exactly counts as what you mean by "builtin".
i guess enums work close enough, at least for limiting strings.
Cool. The enum
approach has other bonuses/drawbacks like if you use the value in a Nim case
statement it will help you check that you handle all possible values (unless you put an else
in there). If you want to keep them strings (and not convert to string via $
on the enum
) then you could also do argParse
/argHelp
overloads for HashSet[string]
. The parNm
approach is, of course, very general..maybe too general (hence automating too little) unless you really need it. I wasn't sure if you meant things like "ints < 314" or something from your brief question.
nah, i meant just simple check if the value is in this limited set of acceptable values. the enums work ok for strings. sadly im too unfamiliar with the library to understand workarounds you're proposing.
well thinking about it, there is almost no case where there is limited set of acceptable values for option that is not a string. and for some edgecases you could just define argParse for distinct type
What you say is right, but if even the distinct type doesn't get you where you want to be, you can re-define the overloads for argHelp
and argParse
for that type of parameter the way test/FancyRepeats.nim
does. It sounds like you get it, but I'll elaborate just in case some passer by finds this thread via search.
FancyRepeats
is after a different goal -- getting -vvvv
means very verbose behavior, but the technique is the same. Inside your overloads you can handle the edge case one way and the regular int
case the other. The FancyRepeats
help calls that user-visible type "countr" (just a lame name I invented). For my "ints < 314" example constraint, the help might say "0..314" instead of "countr" to guide the CLI user. And in the argParse
, instead of the inc(dst)
different-style branch, it could still parseInt
as normal in both branches (or just before a branch), but then check that the number is "in range" and error out if not. So, the parNm
business is very general, but you have to do switching work yourself (within the Nim type for the argParse
/argHelp
, anyway). So, fully fleshed out if you replaced the special argParse
/argHelp
of test/FancyRepeats.nim
then it would make users have to give a number in 0..314
for verb
:
proc argParse*(dst: var int, dfl: int; a: var ArgcvtParams): bool =
if parseInt(strip(a.val), dst) == 0:
a.msg = "Bad value: \"$1\" for option \"$2\"; expecting int\n$3" %
[ a.val, a.key, a.help ]
return false
if a.parNm == "verb": # make "verb" a special kind of int
if verb < 0 or verb > 314:
a.msg = "Bad value: \"$1\" for option \"$2\"; expecting 0..314\n$3" %
[ a.val, a.key, a.help ]
return false
return true
proc argHelp*(defVal: int, a: var ArgcvtParams): seq[string] =
if a.parNm == "verb": # This is a parNm-conditional limited int
result = @[ a.argKeys, "0..314", a.argDf($defVal) ]
else:
result = @[ a.argKeys, "int", a.argDf($defVal) ]
Of course Nim has ranged int
types, too, but with the above technique you can implement basically arbitrary logic on a per-parameter basis.
Is there a builtin way to provide set of acceptable values for an option?