Skip to content

Commit

Permalink
Bump JLine to 3.14.1
Browse files Browse the repository at this point in the history
  • Loading branch information
mattirn authored and remkop committed Apr 10, 2020
1 parent f5129db commit 9609980
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 89 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ivyVersion = 2.4.0
jacocoVersion = 0.8.2
jansiVersion = 1.15
jlineVersion = 2.14.6
jline3Version = 3.13.2
jline3Version = 3.14.1
junitDepVersion = 4.11
junitVersion = 4.12
springBootVersion = 2.2.2.RELEASE
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package picocli.shell.jline3;

import java.nio.file.Path;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import org.jline.builtins.CommandRegistry;
import org.jline.builtins.Completers.OptionCompleter;
import org.jline.builtins.Completers.SystemCompleter;
import org.jline.builtins.Options.HelpException;
Expand All @@ -16,15 +22,12 @@
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Model.OptionSpec;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
* Compiles SystemCompleter for command completion and implements a method commandDescription() that provides command descriptions
Expand All @@ -34,11 +37,11 @@
*
* @since 4.1.2
*/
public class PicocliCommands {
public class PicocliCommands implements CommandRegistry {
private final Supplier<Path> workDir;
private final CommandLine cmd;
private final List<String> commands;
private final Map<String, String> aliasCommand;
private final Set<String> commands;
private final Map<String,String> aliasCommand = new HashMap<>();

public PicocliCommands(Path workDir, CommandLine cmd) {
this(() -> workDir, cmd);
Expand All @@ -47,18 +50,12 @@ public PicocliCommands(Path workDir, CommandLine cmd) {
public PicocliCommands(Supplier<Path> workDir, CommandLine cmd) {
this.workDir = workDir;
this.cmd = cmd;
commands = new ArrayList<>(cmd.getCommandSpec().subcommands().keySet());
aliasCommand = extractAliases(cmd);
}

private static Map<String, String> extractAliases(CommandLine cmd) {
Map<String, String> result = new LinkedHashMap<>();
for (String name : cmd.getCommandSpec().subcommands().keySet()) {
for (String alias : cmd.getSubcommands().get(name).getCommandSpec().aliases()) {
result.put(alias, name);
commands = cmd.getCommandSpec().subcommands().keySet();
for (String c: commands) {
for (String a: cmd.getSubcommands().get(c).getCommandSpec().aliases()) {
aliasCommand.put(a, c);
}
}
return result;
}

/**
Expand Down Expand Up @@ -161,15 +158,40 @@ public CmdDesc commandDescription(String command) {
for (String d: o.description()) {
val.add(new AttributedString(d));
}
if (val.isEmpty()) {
val.add(new AttributedString("")); // in order to avoid IndexOutOfBoundsException
// need to be fixed in JLine
}
if (o.arity().max() > 0 && key.matches(".*[a-zA-Z]{2,}$")) {
if (o.arity().max() > 0) {
key += "=" + o.paramLabel();
}
options.put(key, val);
}
return new CmdDesc(main, ArgDesc.doArgNames(Arrays.asList("")), options);
}

@Override
public List<String> commandInfo(String command) {
List<String> out = new ArrayList<>();
CommandSpec spec = cmd.getSubcommands().get(command).getCommandSpec();
Help cmdhelp = new picocli.CommandLine.Help(spec);
String description = AttributedString.stripAnsi(spec.usageMessage().sectionMap().get("description").render(cmdhelp).toString());
out.addAll(Arrays.asList(description.split("\\r?\\n")));
return out;
}

@Override
public Object execute(CommandRegistry.CommandSession session, String command, String[] args) throws Exception {
List<String> arguments = new ArrayList<>();
arguments.add(command);
arguments.addAll(Arrays.asList(args));
cmd.execute(arguments.toArray(new String[0]));
return null;
}

@Override
public Set<String> commandNames() {
return commands;
}

@Override
public Map<String, String> commandAliases() {
return aliasCommand;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@

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.keymap.KeyMap;
import org.jline.builtins.SystemRegistry;
import org.jline.builtins.SystemRegistryImpl;
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;
Expand All @@ -26,7 +23,6 @@
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;

Expand All @@ -41,10 +37,9 @@ public class Example {
*/
@Command(name = "",
description = {
"Example interactive shell with completion. " +
"Example interactive shell with completion and autosuggestions. " +
"Hit @|magenta <TAB>|@ to see available commands.",
"Type `@|bold,yellow keymap ^[s tailtip-toggle|@`, " +
"then hit @|magenta ALT-S|@ to toggle tailtips.",
"Hit @|magenta ALT-S|@ to toggle tailtips.",
""},
footer = {"", "Press Ctl-D to exit."},
subcommands = {
Expand Down Expand Up @@ -120,95 +115,57 @@ public Void call() throws IOException {
}
}

/**
* 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;
}
private static Path workDir() {
return Paths.get(System.getProperty("user.dir"));
}

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 builtins = new Builtins(Example::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();
PicocliCommands picocliCommands = new PicocliCommands(Example::workDir, cmd);

Parser parser = new DefaultParser();
Terminal terminal = TerminalBuilder.builder().build();

SystemRegistry systemRegistry = new SystemRegistryImpl(parser, terminal, Example::workDir, null);
systemRegistry.setCommandRegistries(builtins, picocliCommands);

LineReader reader = LineReaderBuilder.builder()
.terminal(terminal)
.completer(systemCompleter)
.parser(new DefaultParser())
.completer(systemRegistry.completer())
.parser(parser)
.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);
new TailTipWidgets(reader, systemRegistry::commandDescription, 5, TipType.COMPLETER);
KeyMap<Binding> keyMap = reader.getKeyMaps().get("main");
keyMap.bind(new Reference("tailtip-toggle"), KeyMap.alt("s"));

String prompt = "prompt> ";
String rightPrompt = null;

// start the shell and process input until the user quits with Ctl-D
// start the shell and process input until the user quits with Ctrl-D
String line;
while (true) {
try {
systemRegistry.cleanUp();
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);
systemRegistry.execute(line);
} 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);
systemRegistry.trace(e);
}
}
} catch (Throwable t) {
Expand Down

0 comments on commit 9609980

Please sign in to comment.