can i make string option behave same as boolean ?

28 views
Skip to first unread message

mand...@redhat.com

unread,
Sep 15, 2020, 6:31:52 PM9/15/20
to picocli

when I have:

@CommandLine.Option(names = {
"--live" })
boolean live;

then `jbang --live=true` and `jbang --live=false` works, and `jbang --live false` is not interpreting the false argument as a possible value. and `jbang --live=custom` i can even intercept with custom value handler.

now...how can I get the same for 

@CommandLine.Option(names = {
"--live" })
String live;

with this I cannot force that only `--live=myarg` gets taken as input and that `--live myarg`  should not be treated as a value to `live`.

any way for this to work ?

Remko Popma

unread,
Sep 15, 2020, 6:49:48 PM9/15/20
to picocli
Max,

I will look into this.

The intention was that `--option=value` and `--option value` would be treated identically.
There is indeed some special logic for booleans, that takes the separator into account.
This is because boolean options have arity=0, meaning they are not expected to have a parameter.
If the user specified `--option=value`, then the presence of the separator "forces" us to accept "value" as a parameter, and that is what the logic does.

This is a special case. Generally I would think that treating  `--option=value` and `--option value`  differently would be confusing to users, but there may be other use case that I don't understand yet.

Currently the `IParameterConsumer` interface does not give any indication of whether the value was attached with a separator or not, that may have been a bad decision.

I need to think about this further.

Remko

mand...@redhat.com

unread,
Sep 16, 2020, 10:54:53 AM9/16/20
to picocli
i think it would been great to know if paramter is done via = or not as i really dont see another way of allowing to have options that can have a default beavhior but then be able to specify another option....well you can but that would require having one boolean nand then another flag for the option.

i.e. in my case its jbang where I want to do `jbang edit --open myfile.java` (which says please make temporary project for myfile.java for me to edit, oh and please open my default editor on that project) 
but I also want to be able to write `jbang edit --open=idea myfile.java` which says the same but says, use the idea command/editor in this case.

There is no real way for me to know wether `myfile.java` is actually the editor he wants to use or not ....

I've used parameterconsumer in other cases pretty nicely for numeric values where if the value was a number i would acccept it but not if a string/filename that existed - but it just gets dirty.

And when I look at all my special cases I could have handled it much more uniformly if I had a "OnlyExplicitlyAssignedParameterConsumer.class"  or something ;) 

mand...@redhat.com

unread,
Sep 16, 2020, 10:55:36 AM9/16/20
to picocli
btw. see https://github.com/jbangdev/jbang/pull/314 for latest issue i'm trying to solve and made me open this one. might give you some more context.

Remko Popma

unread,
Sep 16, 2020, 7:05:47 PM9/16/20
to picocli
Thank you for clarifying the use case: there is an option with an optional parameter, and this introduces ambiguity.

I like your proposed solution to try to disambiguate the input with a '=' separator;
it is intuitive that `A` is the option parameter in a command like `jbang edit --open=A B`, where `jbang edit --open A B` is more ambiguous.
The drawback is that users need to know this.

A similar solution (that already works with all versions of picocli) is to disambiguate with the `--` end-of-options delimiter.
`jbang edit --open -- A B`  # both A and B are positional parameters
`jbang edit --open A -- B`  # A is a parameter for the open option and B is a positional parameter

This has the same drawback that users need to know this.
Arguably the `--` end-of-options delimiter is less well-known, although it can be shown in the usage help with `@Command(showEndOfOptionsDelimiterInUsageHelp=true)`.
Still, this is something to consider for commands that define both an option with an optional parameter and a positional parameter.

Ultimately, this is a limitation of the picocli parser: if a command has an option with an optional parameter (like --live[=editor]), then the picocli parser will currently greedily assign the value that follows the option to this option. This is regardless of whether the command also defines a positional parameter and the last argument could also have been interpreted as that positional parameter. This is especially painful if the positional parameter is mandatory (see https://github.com/remkop/picocli/issues/981).

I raised https://github.com/remkop/picocli/issues/980 to improve the parser, but this is not trivial:
it essentially requires the parser to detect ambiguity (all options or positional parameters whose arity is a range instead of a fixed number),
and build up multiple parse results: one for each possible interpretation of the input.
If we succeed in that, we need to decide what to do in cases where 
* all interpretations failed (what error message to produce)
* multiple interpretations succeeded (which one to choose)

Your idea to disambiguate with '='  will not solve the full range of ambiguity problems, but it may be easier to implement than a backtracking parser.
Currently I can think of two mechanisms to do this:

1. introduce a new `@Option(assignFallbackWhenSeparatorMissing = true|false)` attribute.
    For options with an optional parameter, this attribute would tell the parser to use the '=' separator to disambiguate the input.
    The value following the option is _only_ considered to be the option parameter if the value is attached to the option with the '=' separator.
2. introduce a new `IParameterConsumer2` interface, that takes an additional `LookBehind { SEPARATE, ATTACHED, ATTACHED_WITH_SEPARATOR}` enum parameter to the `consumeParameters` method. 
    We would also need an additional `@Option(parameterConsumer2 = <class>)` attribute. 
    Applications can then use this to build custom disambiguation logic.
3. Somehow make this information (of whether a separator was specified or not) available to implementors of the existing `IParameterConsumer` interface.
    Perhaps by adding some method on `ArgSpec`, `CommandSpec` or any object reachable from these objects.
    Of by setting a static ThreadLocal. :-)

There may be other approaches, please let me know your thoughts.

Remko.

Max Rydahl Andersen

unread,
Sep 18, 2020, 9:38:38 PM9/18/20
to Remko Popma, picocli



> Thank you for clarifying the use case: there is an option with an
> optional
> parameter, and this introduces ambiguity.
>
> I like your proposed solution to try to disambiguate the input with a
> '='
> separator;
> it is intuitive that `A` is the option parameter in a command like
> `jbang
> edit --open=A B`, where `jbang edit --open A B` is more ambiguous.
> The drawback is that users need to know this.


> A similar solution (that already works with all versions of picocli)
> is to
> disambiguate with the `--` end-of-options
> <https://picocli.info/#_double_dash> delimiter.
> `jbang edit --open -- A B` # both A and B are positional parameters
> `jbang edit --open A -- B` # A is a parameter for the open option and
> B is
> a positional parameter

> This has the same drawback that users need to know this.
> Arguably the `--` end-of-options delimiter is less well-known,
> although it
> can be shown in the usage help with
> `@Command(showEndOfOptionsDelimiterInUsageHelp=true)`.
> Still, this is something to consider for commands that define both an
> option with an optional parameter and a positional parameter.

issue is that it only work for one parameter - what if you have two ?
+1 for a boolean for its simplicity.

> 2. introduce a new `IParameterConsumer2` interface, that takes an
> additional `LookBehind { SEPARATE, ATTACHED, ATTACHED_WITH_SEPARATOR}`
> enum
> parameter to the `consumeParameters` method.
> We would also need an additional `@Option(parameterConsumer2 =
> <class>)` attribute.
> Applications can then use this to build custom disambiguation
> logic.


doesn't feel right.

> 3. Somehow make this information (of whether a separator was specified
> or
> not) available to implementors of the existing `IParameterConsumer`
> interface.
> Perhaps by adding some method on `ArgSpec`, `CommandSpec` or any
> object
> reachable from these objects.

better than #2

> Of by setting a static ThreadLocal. :-)

noooo! ::)
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "picocli" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/picocli/__tziJIw3lE/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> picocli+u...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/picocli/82736e2f-0954-4825-9bbc-82cf70d31301n%40googlegroups.com.

Remko Popma

unread,
Oct 15, 2020, 12:05:50 AM10/15/20
to picocli
I raised https://github.com/remkop/picocli/issues/1217 to track this.

Anyone who has a GitHub account, please use the GitHub issue tracker instead of this mailing list.

Remko Popma

unread,
Oct 16, 2020, 6:56:27 AM10/16/20
to picocli
Reading my own message again, it sounds less friendly than I intended. Apologies.

I found myself losing track of some very nice feature requests because I failed to create GitHub issues for them.
Just thinking it may be easier to start with a GitHub issue in the first place... :-) 
Reply all
Reply to author
Forward
0 new messages