-
Notifications
You must be signed in to change notification settings - Fork 419
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
picocli-shell-jline demo does not compile #989
Comments
Checking... |
Dependencies
Ok, good point. It may be more user-friendly to make JLine a transitive dependency so it gets pulled in automatically when you have Note that JLine 3 is much more modular than JLine 2, and I think you still need to add one of Jansi or JNA when running your app on Windows. So to be honest I am not sure what would be the best transitive dependency/dependencies to pull in... Problem with Example
Apologies 🙇 . I recently accepted a pull request by one of the JLine authors that fixed an issue with subcommand completion. The PR fixed the issue but also requires things to be wired up a bit differently than before. So, the example is showing you how to do things with the (unreleased) upcoming version of picocli-shell-jline3. (Kind of the opposite of an example that is out of date. Still not very useful. Hm...) Solution 1: Use the (Latest) Source, Luke! ⚔️If you are up for it, I would suggest using a SNAPSHOT build ⚡ of To do this, check out picocli master locally, and build it with
You can then try this in a project that uses the For reference, I tested the PR with the below command and did not find any issues:
Solution 2: Use the Previous ExampleHere is the old example code that should work with package picocli.shell.jline3.example;
import org.fusesource.jansi.AnsiConsole;
import org.jline.builtins.Builtins;
import org.jline.builtins.Completers.SystemCompleter;
import org.jline.builtins.Options.HelpException;
import org.jline.builtins.Widgets.CmdDesc;
import org.jline.builtins.Widgets.CmdLine;
import org.jline.builtins.Widgets.TailTipWidgets;
import org.jline.builtins.Widgets.TailTipWidgets.TipType;
import org.jline.reader.*;
import org.jline.reader.impl.DefaultParser;
import org.jline.reader.impl.LineReaderImpl;
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;
import org.jline.utils.AttributedStringBuilder;
import org.jline.utils.AttributedStyle;
import picocli.CommandLine;
import picocli.CommandLine.ArgGroup;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParentCommand;
import picocli.shell.jline3.PicocliCommands;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
/**
* Example that demonstrates how to build an interactive shell with JLine3 and picocli.
* @since 4.1.2
*/
public class Example {
/**
* Top-level command that just prints help.
*/
@Command(name = "",
description = {
"Example interactive shell with completion. " +
"Hit @|magenta <TAB>|@ to see available commands.",
"Type `@|bold,yellow keymap ^[s tailtip-toggle|@`, " +
"then hit @|magenta ALT-S|@ to toggle tailtips.",
""},
footer = {"", "Press Ctl-D to exit."},
subcommands = {
MyCommand.class, ClearScreen.class, CommandLine.HelpCommand.class})
static class CliCommands implements Runnable {
LineReaderImpl reader;
PrintWriter out;
CliCommands() {}
public void setReader(LineReader reader){
this.reader = (LineReaderImpl)reader;
out = reader.getTerminal().writer();
}
public void run() {
out.println(new CommandLine(this).getUsageMessage());
}
}
/**
* A command with some options to demonstrate completion.
*/
@Command(name = "cmd", mixinStandardHelpOptions = true, version = "1.0",
description = "Command with some options to demonstrate TAB-completion" +
" (note that enum values also get completed)",
subcommands = CommandLine.HelpCommand.class)
static class MyCommand implements Runnable {
@Option(names = {"-v", "--verbose"},
description = { "Specify multiple -v options to increase verbosity.",
"For example, `-v -v -v` or `-vvv`"})
private boolean[] verbosity = {};
@ArgGroup(exclusive = false)
private MyDuration myDuration = new MyDuration();
static class MyDuration {
@Option(names = {"-d", "--duration"},
description = "The duration quantity.",
required = true)
private int amount;
@Option(names = {"-u", "--timeUnit"},
description = "The duration time unit.",
required = true)
private TimeUnit unit;
}
@ParentCommand CliCommands parent;
public void run() {
if (verbosity.length > 0) {
parent.out.printf("Hi there. You asked for %d %s.%n",
myDuration.amount, myDuration.unit);
} else {
parent.out.println("hi!");
}
}
}
/**
* Command that clears the screen.
*/
@Command(name = "cls", aliases = "clear", mixinStandardHelpOptions = true,
description = "Clears the screen", version = "1.0")
static class ClearScreen implements Callable<Void> {
@ParentCommand CliCommands parent;
public Void call() throws IOException {
parent.reader.clearScreen();
return null;
}
}
/**
* Provide command descriptions for JLine TailTipWidgets
* to be displayed in the status bar.
*/
private static class DescriptionGenerator {
Builtins builtins;
PicocliCommands picocli;
public DescriptionGenerator(Builtins builtins, PicocliCommands picocli) {
this.builtins = builtins;
this.picocli = picocli;
}
CmdDesc commandDescription(CmdLine line) {
CmdDesc out = null;
switch (line.getDescriptionType()) {
case COMMAND:
String cmd = Parser.getCommand(line.getArgs().get(0));
if (builtins.hasCommand(cmd)) {
out = builtins.commandDescription(cmd);
} else if (picocli.hasCommand(cmd)) {
out = picocli.commandDescription(cmd);
}
break;
default:
break;
}
return out;
}
}
public static void main(String[] args) {
AnsiConsole.systemInstall();
try {
// set up JLine built-in commands
Path workDir = Paths.get("");
Builtins builtins = new Builtins(workDir, null, null);
builtins.rename(org.jline.builtins.Builtins.Command.TTOP, "top");
builtins.alias("zle", "widget");
builtins.alias("bindkey", "keymap");
SystemCompleter systemCompleter = builtins.compileCompleters();
// set up picocli commands
CliCommands commands = new CliCommands();
CommandLine cmd = new CommandLine(commands);
PicocliCommands picocliCommands = new PicocliCommands(workDir, cmd);
systemCompleter.add(picocliCommands.compileCompleters());
systemCompleter.compile();
Terminal terminal = TerminalBuilder.builder().build();
LineReader reader = LineReaderBuilder.builder()
.terminal(terminal)
.completer(systemCompleter)
.parser(new DefaultParser())
.variable(LineReader.LIST_MAX, 50) // max tab completion candidates
.build();
builtins.setLineReader(reader);
commands.setReader(reader);
DescriptionGenerator descriptionGenerator = new DescriptionGenerator(builtins, picocliCommands);
new TailTipWidgets(reader, descriptionGenerator::commandDescription, 5, TipType.COMPLETER);
String prompt = "prompt> ";
String rightPrompt = null;
// start the shell and process input until the user quits with Ctl-D
String line;
while (true) {
try {
line = reader.readLine(prompt, rightPrompt, (MaskingCallback) null, null);
if (line.matches("^\\s*#.*")) {
continue;
}
ParsedLine pl = reader.getParser().parse(line, 0);
String[] arguments = pl.words().toArray(new String[0]);
String command = Parser.getCommand(pl.word());
if (builtins.hasCommand(command)) {
builtins.execute(command, Arrays.copyOfRange(arguments, 1, arguments.length)
, System.in, System.out, System.err);
} else {
new CommandLine(commands).execute(arguments);
}
} catch (HelpException e) {
HelpException.highlight(e.getMessage(), HelpException.defaultStyle()).print(terminal);
} catch (UserInterruptException e) {
// Ignore
} catch (EndOfFileException e) {
return;
} catch (Exception e) {
AttributedStringBuilder asb = new AttributedStringBuilder();
asb.append(e.getMessage(), AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
asb.toAttributedString().println(terminal);
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}
} |
I updated the picocli-shell-jline3 readme, thanks for pointing this out! Feedback welcome! |
wow. thanx for this detailed answer! |
I tried to get the demo in the README up and running, without success so far.
https://github.com/remkop/picocli/blob/master/picocli-shell-jline3/README.md
at least, when I add
as dependencies, it compiles. But I thought I wouldn't need jline as extra dependency, would I?
when I don't add it, I get a
So, not that it compiles, I try to start the fat-jar and get a
which referes to the line
When I try to cast the
picocliCommand
right in the source, I get a null pointer exception.Do you have a quick hint? Thanx!
The text was updated successfully, but these errors were encountered: