`opt_all` options that mutually affect each other
bensmrs opened this issue · 12 comments
Hi!
I’m trying to add --include
and --exclude
options to my program, so that each option takes precedence over the previous ones, i.e. --include=/var --exclude=/var/log --include=/var/log/foo
.
Doing it with opt_all
gives two lists of parameters, one for --include
and the other for --exclude
, but I can’t find a clean way to store the result like [Include "/var"; Exclude "/var/log"; Include "/var/log/foo"]
. Is there one?
My current non-clean solution is to use a mutable list with custom parsers for --include
and --exclude
that feed this list…
Thanks
I don't think so. In general support for context dependent options is poor in cmdliner (on purpose).
Would exposing the id
function from Cmdliner_info.Arg
be that bad? At least it could help me reorder the two lists in a proper way.
I don't see how this helps.
I thought it increased at parsing time but I’m now getting that it increases at option definition time… So for now, you’d recommend me to stick to my mutable list hack?
Yes. Or change the way your cli works. Generally I rather define a set with all includes and then simply remove excludes from this set. This doesn't support your example but it has the advantage to be simpler to understand for users when you read the cli (not context dependent).
Unfortunately, the example I’ve shown is a typical use case for my CLI, I think tools like rsync
do it too. But I completely understand that you want to stick to context-free stuff as much as possible.
Maybe doing something like info ["include"; "exclude"]
with a common description and having type 'a parser = ?name:string -> string -> [ `Ok of 'a | `Error of string ]
in Cmdliner_arg
(with name
the option name) could do the trick without breaking already existing programs, but that may not be a path you’d want to pursue.
Could you perhaps try something with with_used_args. I'm not longer exactly how it works. (Likely as painful but maybe a little bit less ugly).
Awesome, that’s exactly what I needed! It gives me terms with (initial_value, option_name)
. Thanks a lot!
Be careful though IIRC this gives you the cli verbatim (it was added so that you could reply to the user with what she wrote verbatim) so you likely need to process that list I suspect that say --include=/var/ --exclude /var/log
will give you ["--include=/var/"; "--exclude"; "/var/log"; ]
.
type 'a parser = ?name:string -> string -> [
Ok of 'a |
Error of string ]
Also that would break everyone, but an alternative conv
constructor could be provided. I will think about that in the future.
Yes, the option is prefixed with dashes.
Also that would break everyone
Well… It sure breaks a few internal signatures, but the fact that name
is optional here should make the change transparent to most people, as the “old” functions would still typecheck. But that’s just a guess.
Anyway, with_used_args
is fine for me
Yes, the option is prefixed with dashes.
More important, the option and the option argument may be in two different strings.
but the fact that
name
is optional here should make the change transparent to most people,
No. It breaks anyone who implemented the 'a parser
signature: you require their function to have an optional ?name
argument which they don't have.