-
Notifications
You must be signed in to change notification settings - Fork 412
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
(WIP) Add support for quoting parameters #293
Conversation
Codecov Report
@@ Coverage Diff @@
## master #293 +/- ##
==========================================
- Coverage 89.07% 86.07% -3%
- Complexity 281 296 +15
==========================================
Files 4 5 +1
Lines 3852 4035 +183
Branches 933 964 +31
==========================================
+ Hits 3431 3473 +42
- Misses 209 343 +134
- Partials 212 219 +7
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've done a quick review and added some comments.
Thanks for working on this! It's really starting to take shape!
@@ -0,0 +1,371 @@ | |||
package picocli; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's put this class in a new package picocli.interactive
. I'm thinking that this package may grow in the future to contain additional functionality for interactive command line applications.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Except this is useful for normal as well as interactive programs. I'm planning (if you're OK with it) to add the finalized version in as an inner class of CommandLine
, similar to everything else, and to help with the whole "one file" thing. But if I add anything else for interactive stuff, I'll do that in a separate package (and pull request).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In normal usage the operating system shell will take care of the tokenizing and quoting so this is really for interactive use as far as I can see. There are all kinds of interesting things that can be done for picocli-based interactive shells, including things like autocompletion. I really think this should live in a new picocli.interactive
package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, will do. I wasn't sure if the OS handled all that or if picocli did (all my testing has been interactive, so I apparently had forgotten how non interactive apps worked 🙄).
import picocli.CommandLine.Option; | ||
import picocli.CommandLine.Parameters; | ||
|
||
public class CommandTokenizer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be great to have some javadoc that describes what this class does, ideally with an example of how it can be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. I'm waiting until it's done though, in case we decide anything needs to be changed.
// Remove blanks at start and end of a string | ||
private boolean trimBlanks = true; | ||
|
||
public CommandTokenizer(String cmd) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both constructors start parsing the specified input immediately before users have had a chance to configure the tokenizer. It may be better to postpone the call to parse
until the user calls the tokens
or nextToken
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, you're right. Didn't think about that, will fix.
this.tokens = parse(input); | ||
} | ||
|
||
private String[] parse(String cmd) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add unit tests for this method and the other public parse
method? We can make this method package-private to allow unit tests to call it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I've never done unit testing before, but for something like this, I think it should be simple.
I might actually make them public
, so that people can reuse the object. In that case, I would also add a no-arg constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you’ve never created unit tests before it will be a revelation. :-) Unit tests are a great way to shake out bugs and create confidence that future changes didn’t break anything. They are crucial to keeping software “soft”.
Please see the picocli tests for examples.
Huh, somehow the javadocs broke, and that is failing Travis. Not sure how to fix it. |
I think I included all the parameters and returns. |
The problem seems to be the |
Currently, I only have unit tests for the |
...and the javadoc broke again 😤 |
You'll get there! 😄 |
Any idea what broke the javadoc this time? There are a ton of errors in the log, and I've never used javadoc before. |
(Away from PC). Most of those are warnings, not errors. If you search for “error” you’ll quickly find it. |
I found a few:
|
I'm not sure how to fix the issue. During my manual testing, it should succeed. I'm not sure what JUnit is doing that I'm not (or vice-versa) that causes the issue. I'm pretty sure what is happening is it is splitting on the space in the comments test, but when I manually run parse on it, it doesn't split there. I've tried both the String and Scanner versions, to see if there is some difference, but it seems to be the same. |
The test failure says:
Unsure why. You can try printing the result of the parse to stdout so you can see what the actual results are in the Travis CI log. |
Yep, it's splitting on the space. Like I said, I have zero idea why that would happen, whenever I try the test input, it works, but in JUnit it isn't. |
Could it have something to do with the difference in environment? Different behaviour when running on Linux? |
Possibly? I'm not using JUnit, because AIDE does not support it. I'm using a mini interactive shell that returns the tokenizer output. |
Maybe a difference between the JVM and the Dalvik VM (or ART, I think), because AIDE works by dexing stuff? |
The issue was that the code to trim blanks was in the Scanner method, not the String one. It's weird that switching to the String one in my manual testing didn't point that out, I must've still been using the Scanner one somehow. |
Good catch! |
From: Feedback:
Also question: I mean, why you not replaced parse(str) implementation with short code?
|
Will fix those issues, thanks! Currently, the |
do you plan to add symbol escaping in windows notation? I mean, caret symbol and something. For example: ^" - escaped quotes (instead of a slash notation for *nix) |
Shouldn't this be possible in |
IMHO it's dirty way, add another methods to clear lists. |
Not so simple, he-he 😄 See there: https://ss64.com/nt/syntax-esc.html
Note: PS. I think it will be better to drop pipes parsing in first version, because it's complex for windows and *nix. So just drop the last rule with variable escape length. |
I'm not dealing with pipes yet, that would probably be really tough, because I think I'd have to change |
If you look, there are already methods that take a |
About flags, I think it will be better to move all of them to the factory, that returns actual parser via interface. So, we can extend the factory with custom flags, and to add new parser implementations for new shells |
I’m a bit confused. I thought we were talking about the tokenizer parser. Are you talking about the |
When I read POSIX parser I assumed you meant a parser for the POSIX.1-2017 Utility Argument Syntax. This is implemented in I realize now you may have been talking about POSIX.1-2017 Token Recognition instead. |
I should probably actually read that, I have just been doing this based off of my current shell knowledge and never even thought of the POSIX standard. |
Yep, I meant about token recognition for POSIX shells. |
@PorygonZRocks your approach sounds reasonable to me. Adding Presets to imitate the behaviour of specific OS shells would be a nice convenience layer on top of the tokenizer class. |
f3aa509
to
eaa3a23
Compare
Oops, I forgot about this. Anyway, I'm going through the code, and just realized that it may be better to just have the methods take a |
I recently did some work on an interactive shell when helping Micronaut migrate their interactive CLI to picocli. Their CLI was based on JLine 2. JLine has support for command history, command line completion, ANSI and more. Have you had a chance to look at it? I found that JLine and picocli complement each other very well, there is no overlap in features. JLine is well done and I don't want to rewrite JLine in picocli. Instead, I am planning to provide some classes and documentation to help users integrate JLine and picocli, starting with a completer and some examples. It turns out that JLine includes a tokenizer. I'm not sure yet what to do with this PR. Can you take a look at the above and let me know your thoughts? |
That sounds a lot better, for some reason I had thought JLine was made with native libraries. |
I may still look at creating a simpler way to use the two to create an interactive shell easily, but looks like this tokenizer isn't needed. |
I’m thinking to rename the module to Suggestions for such features or documentation are welcome! |
This adds a class (
CommandTokenzer
) that takes text, and splits it based on customizable whitespace characters, and has support for quoting/escaping spaces with customizable quote and escape characters. The methods are intended to be similar to that ofStreamTokenizer
(hence the name). See here for some more details.Note that currently the class is not used, as it is not finalized yet and (as I mentioned in the issue) I have to edit
CommandLine.java
with a normal text editor, not my IDE, so it is easier to keep it separate until completion.