Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add abbreviation recognition for subcommands and options #1047

Merged
merged 37 commits into from
May 23, 2020
Merged

Add abbreviation recognition for subcommands and options #1047

merged 37 commits into from
May 23, 2020

Conversation

NewbieOrange
Copy link
Contributor

@NewbieOrange NewbieOrange commented May 15, 2020

Currently using code snippet from @remkop #732 with minor changes.

For ease of debugging, the AbbreviationMatcher class is in separate file for now.

This is a draft, no javadoc are added yet, and tests may not cover all cases.

Feedbacks are welcomed!

This draft's goal is to resolve #10 and resolve #732.

Edit: All javadoc have been added, and diff coverage is 94.79%.

@codecov-io
Copy link

codecov-io commented May 15, 2020

Codecov Report

Merging #1047 into master will decrease coverage by 0.08%.
The diff coverage is 86.74%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #1047      +/-   ##
============================================
- Coverage     94.35%   94.26%   -0.09%     
- Complexity      443      466      +23     
============================================
  Files             2        3       +1     
  Lines          6482     6573      +91     
  Branches       1735     1757      +22     
============================================
+ Hits           6116     6196      +80     
- Misses           94       99       +5     
- Partials        272      278       +6     
Impacted Files Coverage Δ Complexity Δ
src/main/java/picocli/CommandLine.java 94.13% <81.81%> (-0.06%) 306.00 <3.00> (+2.00) ⬇️
src/main/java/picocli/AbbreviationMatcher.java 90.00% <90.00%> (ø) 21.00 <21.00> (?)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ee28eb1...e7f881b. Read the comment docs.

Copy link
Owner

@remkop remkop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall very nice, thanks for working on this!

There may be some interesting edge cases when abbreviations are combined with case-insensitive mode or POSIX clustered options, I haven't given this much thought yet.

src/main/java/picocli/CommandLine.java Show resolved Hide resolved
src/main/java/picocli/CommandLine.java Show resolved Hide resolved
src/main/java/picocli/CommandLine.java Outdated Show resolved Hide resolved
src/main/java/picocli/CommandLine.java Outdated Show resolved Hide resolved
src/main/java/picocli/NameMatcher.java Outdated Show resolved Hide resolved
src/main/java/picocli/NameMatcher.java Outdated Show resolved Hide resolved
src/test/java/picocli/CommandLineTest.java Outdated Show resolved Hide resolved
@NewbieOrange
Copy link
Contributor Author

NewbieOrange commented May 15, 2020

This currently does not work with case-insensitive mode, because the match function does not take it into consideration. Edit: Make methods in AbbreviationMatcher non-static, and add a field caseInsensitive like the CaseAwareLinkedMap... and put its instance in CommandLine or ParserSpec?

For POSIX options, the current implementation will prioritize full name, and in this case, also the abbreviation. For example, if we have three options: -A, -B and --ABC, if the input is -AB, this PR will match --ABC instead of -A and -B, which is counter-intuitive.

Also, if there are options --a-B, --aB, -a, -B... this will currently be unable to process if user inputs -aB. (Always throws a ParameterException!)

I think the behaviour of this feature should be: full-match > posix-match > abbrev-match? If this is the case, we may make the entire part of pre-processing options to a method, and call with original arg first, then try to match POSIX, if both failed, call the method again with matched arg.

@NewbieOrange
Copy link
Contributor Author

NewbieOrange commented May 15, 2020

Another way is to limit abbreviations to long options only (options starts with --), so it will probably not conflict with POSIX options.

Edit: This seems to be the GNU way.

@NewbieOrange
Copy link
Contributor Author

NewbieOrange commented May 15, 2020

Not sure how to splitIntoChunks with case-insensitivity...

Edit: With case-insensitivity, it may make sense to match prefix only, since it is impossible to trivially split words.

Copy link
Owner

@remkop remkop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!
I added some more comments.

src/main/java/picocli/CommandLine.java Show resolved Hide resolved
src/main/java/picocli/AbbreviationMatcher.java Outdated Show resolved Hide resolved
src/main/java/picocli/CommandLine.java Outdated Show resolved Hide resolved
@NewbieOrange
Copy link
Contributor Author

Any thoughts on behaviour about case-insensitivity and POSIX options mentioned above?

@remkop
Copy link
Owner

remkop commented May 15, 2020

Bedtime for me. I’ll take another look tomorrow.

@remkop
Copy link
Owner

remkop commented May 16, 2020

I haven't had a chance yet to sit down and think clearly about the interaction between case insensitive mode, posix short options, negatable options and abbreviated options. It is possible that some combinations will always give counter-intuitive results.

I would be fine with reducing scope, like leaving negatable options out of scope: for example, we could recognize the abbreviated original option, but the negatable form must always be specified fully and cannot be abbreviated. Just an idea.

The examples you provided are useful to help list up and think through the possible combinations. I just need to find a block of time where I can focus on this. I may not be able to do so this weekend.

Abbreviated commands are easier. One idea is to (initially?) only provide this feature for subcommands.

@NewbieOrange
Copy link
Contributor Author

Actually the negatable form options does work since 747720c.

Feel free to take your time, I am not in a hurry. 😀

@NewbieOrange
Copy link
Contributor Author

NewbieOrange commented May 16, 2020

It makes sense to me that we only split blocks using hyphen (ignore camelCase) in case-insensitive mode.

@NewbieOrange
Copy link
Contributor Author

Also, if there are options -A, -B and -AB, if user inputs -AB, picocli will match -AB instead of -A and -B (full option name match has higher priority than POSIX cluster-options). So we can define a priority for options matching and let the users to avoid ambiguity.

@remkop
Copy link
Owner

remkop commented May 21, 2020

Package private is fine. :-)

About the test, if we pass --AB or --a-b then both a_b and aB options are matched?

@NewbieOrange
Copy link
Contributor Author

NewbieOrange commented May 21, 2020

If we pass --AB then it causes a ParameterException: --AB is not unique: it matches '--a-B', '--aB'

If we pass --a-b then it causes a ParameterException: --a-b is not unique: it matches '--a-B', '--aB'

Edit: Fixed an issue in splitIntoChunks.

@NewbieOrange
Copy link
Contributor Author

If we pass --aB and --a-B then both options are matched.

@NewbieOrange
Copy link
Contributor Author

NewbieOrange commented May 21, 2020

So the current impl will find exact match first, if there is exact match, then any ambiguity is not considered. Otherwise (no exact match), if there is ambiguity, a ParameterException is thrown.

Edit: typo

@NewbieOrange NewbieOrange requested a review from remkop May 21, 2020 15:58
@NewbieOrange
Copy link
Contributor Author

NewbieOrange commented May 22, 2020

The latest code should have addressed most issues.

@remkop
Copy link
Owner

remkop commented May 22, 2020

Great, thank you! I’m not sure if I’ll be able to review today, I’ll try to get it done this weekend.

@remkop remkop merged commit 1b51bf1 into remkop:master May 23, 2020
@remkop remkop added this to the 4.4 milestone May 23, 2020
@remkop remkop added type: API 🔌 type: enhancement ✨ theme: parser An issue or change related to the parser labels May 23, 2020
remkop added a commit that referenced this pull request May 23, 2020
@remkop
Copy link
Owner

remkop commented May 23, 2020

I went ahead and merged the PR.
Thank you very much for the contribution!
I’ll add documentation in the next few days.

@NewbieOrange
Copy link
Contributor Author

Great, glad I could contribute to the picocli community! 😀

remkop added a commit that referenced this pull request May 23, 2020
remkop added a commit that referenced this pull request May 24, 2020
remkop added a commit that referenced this pull request May 24, 2020
@NewbieOrange NewbieOrange deleted the abbrev_recognition branch May 26, 2020 11:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
theme: parser An issue or change related to the parser type: API 🔌 type: enhancement ✨
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support unambiguous abbreviations Support recognizing abbreviated options and commands
4 participants