remkop / picocli

Picocli is a modern framework for building powerful, user-friendly, GraalVM-enabled command line apps with ease. It supports colors, autocompletion, subcommands, and more. In 1 source file so apps can include as source & avoid adding a dependency. Written in Java, usable from Groovy, Kotlin, Scala, etc.
https://picocli.info
Apache License 2.0
4.92k stars 423 forks source link

JLine 3 Auto Completion Issue With Space Separator #999

Open andrewauclair opened 4 years ago

andrewauclair commented 4 years ago

Hi,

I found an issue with the JLine 3 - picocli system completer when it comes to auto completing options. I was able to reproduce it with the example.

If you type "cmd=" and then press tab, you will see the auto complete options. You can also type something like "cmd=op", press tab and it will complete to "cmd=top". But if you type "cmd " then press tab, nothing happens. Same with "cmd op" and tab.

I'm assuming this should work because picocli supports using space or = for the separator.

Looking at the JLine 3 Completer.java complete method I can see that there are several references to "=", so maybe this is really a JLine 3 issue.

Thanks in advance for any help!

remkop commented 4 years ago

Hi @andrewauclair, thanks for raising this.

You mention you are using the example, but can you also specify which version you are using?

I recently accepted a PR from one of the JLine maintainers, that fixes an issue with completion for subcommands (https://github.com/remkop/picocli/issues/969).

This is in master and will be part of the upcoming picocli 4.3 release. It would be great if you could verify whether the problem you mention still exists with current picocli master.

To try the latest version, do this:

git clone https://github.com/remkop/picocli.git
cd picocli
gradlew publishToMavenLocal

That should publish picocli-shell-jline3-4.2.1-SNAPSHOT to your local .m2 Maven cache. You can then try this in a project that uses the info.picocli:picocli-shell-jline3-4.2.1-SNAPSHOT dependency. Also make sure to use the latest JLine 3.14.1.

andrewauclair commented 4 years ago

Yes, it still seems to happen with the latest. I now see that the check for "=" is in the PicocliCommands.java complete method. I attempted to debug this, but I don't think it's possible in IntelliJ. I replaced the 2 ='s with spaces and it actually kind of works, except you have to escape the space, which is weird.

It seems more consistent now though. I believe before I had issues with it working with the long options. But I can't reproduce that portion with the new code.

I'm also looking to do sub-subcommands. So it was nice to see that that will be supported now.

remkop commented 4 years ago

Understood. I may not be able to look into this for a while; pretty busy with trying to get picocli 4.3 released and other commitments... Hopefully the picocli 4.3 release will significantly improve completion with JLine3 though.

andrewauclair commented 4 years ago

Thanks! No worries. I've found that JLine3 can be a real time sink. Maybe I'll dig into it a little more. For now I think I'll have to get used to using =.

andrewauclair commented 4 years ago

Bit of an update. I've been playing around with this for the last hour or so and came up with the code below. With this else statement at the end of the PicocliCompleter complete method, instead of the existing else in that location, then I think it works properly.

I actually dug around in the JLine 3 OptionCompleter code and I can see that it does the same as the new PicocliCommands. If you use an equals like say: -l=/one/two, then you can never complete it using -l=two. This makes sense because JLine3 is checking if the word contains any of the candidate strings, which in this case isn't possible because the candidate string is -l=/one/two.

Now for the fun part. If you're using a space instead of an equals to separate the -l and two, then they become 2 separate words. This means that JLine3 can properly do the string contains with the list of candidates, in this case /one/two.

I just wanted to document my findings here for you. When 4.3 comes out I will just use a modified copy of PicocliCommands that I created in my project which works just fine. So feel free to push this one off for a while.

I'm just working on a little personal project that I use at work to track my TODOs. Not including testing libraries (Mockito and JUnit), I think picocli has been my favorite library to work with in recent memory. The API is feature rich and the documentation is very well written. It has cleaned up my code a ton and in ways I couldn't have even thought of. I recently used the ITypeConverter with a custom class to force some validation of arguments, which was awesome.

Good luck with 4.3!

else {
                if (commandLine.wordIndex() - 1 >= 0 && words.get(commandLine.wordIndex() - 1).startsWith("-")) {
                    for (CommandLine.Model.OptionSpec option : sub.getCommandSpec().options()) {
                        if (option.completionCandidates() != null) {
                            addCandidates(candidates, option.completionCandidates(), "", "", true);
                        }
                    }
                }
                else {
                    addCandidates(candidates, sub.getSubcommands().keySet());
                    for (CommandLine s : sub.getSubcommands().values()) {
                        addCandidates(candidates, Arrays.asList(s.getCommandSpec().aliases()));
                    }
                }
            }