4

In a CLI app built using picocli, what is the most appropriate way to implement an interactive confirmation?

The scenario is, when a certain command is run, I need to get a confirmation from the user to do a certain task. I used the interactive option mentioned in the picocli documentation but it's not working as expected.

@CommandLine.Option(names = {"-c", "--copy-contract"},
            description = "Do you want to copy the contract in to the project?", interactive = true, arity = "1")
boolean isCopy;

The above option doesn't seem to trigger a user input when the command is run.

Any idea?

Imesh Chandrasiri
  • 5,558
  • 15
  • 60
  • 103
  • How are you invoking the command? Are you specifying the `-c` option on the command line? (That’s necessary to trigger the prompt.) I see the interactive prompt when I invoke the command with `-c`. What do you see? – Remko Popma Jun 05 '19 at 02:33
  • 1
    I actually don't invoke it using the `-c`. I just run the command without the option and expected the prompt. – Imesh Chandrasiri Jun 05 '19 at 05:45
  • By spec, it is the occurrence of the `-c` option on the command line that triggers the interactive prompt. Does it work for you now? – Remko Popma Jun 05 '19 at 05:57
  • Maybe the documentation (https://picocli.info/#_interactive_password_options) can be improved. Suggestions welcome! – Remko Popma Jun 05 '19 at 06:02

1 Answers1

7

The @Option(names = "-c", interactive = true) attribute will cause picocli to prompt the user if (and only if) the -c option is specified.

If the application also needs to prompt the user when the -c option is not specified, it currently needs to be done in the application code.

As of picocli 4.3.2, this can be accomplished as follows:

class MyApp implements Runnable {
    @Option(names = {"-c", "--copy-contract"},
            description = "Do you want to copy the contract in to the project?",
            interactive = true, arity = "1")
    Boolean isCopy;

    public void run() {
        if (isCopy == null) {
            String s = System.console().readLine("Copy the contract? y/n: ");
            isCopy = Boolean.valueOf(s) || "y".equalsIgnoreCase(s);
        }
        System.out.printf("isCopy=%s%n", isCopy);
    }

    public static void main(String... args) {
        new CommandLine(new MyApp()).execute(args);
    }
}

(There is a feature request to include this in picocli in a future release.)

Remko Popma
  • 35,130
  • 11
  • 92
  • 114
  • Hi, is `System.console().readLine()` the method of choice also when using picocli with jline? I thought there is a way to get the reader by commandSpec.commandLine()..., but I don't find it anymore. – Mayra Delgado Nov 24 '21 at 07:56
  • 1
    @MayraDelgado JLine3 has its own `LineReader` class that should be used when combining picocli with JLine3. The [picocli-shell-jline3 Example](https://github.com/remkop/picocli/tree/master/picocli-shell-jline3) shows how to create a `LineReader` in the `main` method. Notice how the `LineReader` is passed to the `CliCommands` application class. – Remko Popma Nov 25 '21 at 09:09