picocli icon indicating copy to clipboard operation
picocli copied to clipboard

access unmatched options as map

Open xenoterracide opened this issue 4 years ago • 5 comments

maybe this is already possible but I didn't see it, I'd like to be able to access all options passed, or maybe just the ones not configured with picocli. I'm developing a scaffolding system inspired by hygen. hygen allows you to define variables on the command line, it automatically generates?/parses those command line parameters and stuffs them into a javascript object. What I'd like is to be able to do is something like this on my picocli class. I can probably do this with a programatic spec, however, I'm still not certain if I can combine the 2 styles, and if I need to do this with programmatic I would prefer to combine the styles.

@Options( unrecognizedOnly = true )
Map<String, String> options = new HashMap<>();

xenoterracide avatar Dec 07 '20 20:12 xenoterracide

There is a list-like facility for unmatched parameters: see Unmatched Input.

The easiest way to use this is with the @Unmatched annotation:

class MyApp {
    @Unmatched
    List<String> unmatched;
}

remkop avatar Dec 08 '20 00:12 remkop

hmm.... but what would this produce in the array?

--foo bar --baz=fun

I suspect (but haven't tried, sorry)

["--foo", "bar", "--baz=fun"]

which means I'd have to go about parsing this array myself. What I'd like is

{
   "foo": "bar",
   "baz": "fun"
}

this way I could do

@Unmatched( options = true, stripDashes=true )
Map<String, String> options;

          Map<String, Object> context = new HashMap<>();
          context.putAll( Map.of( "args", args, "name", name ) ); // comes from parameters
          context.putAll( e.getValue().getContext() ); // comes from a config file
          context.putAll( options ); // allow overriding anything

the context which is then passed to a template parser

I also wonder given the documentation... since I already have positional parameters, and one is a ..* all parameters, how this would impact that, especially if you put the option after the parameters.

xenoterracide avatar Dec 08 '20 01:12 xenoterracide

Yes, if you have a positional parameter list or array defined that captures all indices, then the @Unmatched list will only contain "unknown options": args that "resemble" options but are not defined as picocli @Option options.

The exact behaviour can be controlled with parser configuration like setStopAtUnmatched, setUnmatchedArgumentsAllowed , and setUnmatchedOptionsArePositionalParams.

I suspect that in the example you provided, the @Unmatched list would end up containing ["--foo", "--baz=fun"], while "bar" would be added to the positional parameters list.

So, overall, picocli currently does not provide the facility to parse the unmatched arguments. Note that it is not trivial to impose structure on this list; for example, some apps would want bar to be interpreted as a parameter for --foo, while others may want --foo to have zero parameters and treat bar as a standalone (positional) parameter. Yet other apps may want to treat --foo as an option with 2 parameters, the first one being bar, and the second param being --baz=fun. All these are valid interpretations, depending on the app.

Things get even trickier if the end user specifies "unmatched" arguments intermingled with "defined" options and their parameters.

Are you interested in providing a pull request for this?

remkop avatar Dec 08 '20 03:12 remkop

maybe, we'll see, this particular feature isn't urgent for me, it's another nice to have, eventually that may change as I don't really have a great workaround for this feature that's not basically equivalent to implementing it. I can definitely see what you're saying about the trickiness though.

xenoterracide avatar Dec 08 '20 03:12 xenoterracide

ugh, I actually may need this in order for my stuff to actually work right :/ so you may get your wish :/

xenoterracide avatar Dec 19 '20 01:12 xenoterracide