Skip to content

Commit

Permalink
SystemRegistry: register and manage subcommands execution and completion
Browse files Browse the repository at this point in the history
  • Loading branch information
mattirn committed Mar 19, 2020
1 parent c463205 commit c2d2087
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,11 @@ default String name() {
*/
default List<String> commandInfo(String command) {
try {
invoke(new CommandSession(), command, new Object[] {"--help"});
Object[] args = {"--help"};
if (command.equals("help")) {
args = new Object[] {};
}
invoke(new CommandSession(), command, args);
} catch (HelpException e) {
return Builtins.compileCommandInfo(e.getMessage());
} catch (Exception e) {
Expand Down
6 changes: 5 additions & 1 deletion builtins/src/main/java/org/jline/builtins/Completers.java
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,10 @@ public OptionCompleter(Collection<OptDesc> options, int startPos) {
this.startPos = startPos;
}

public void setStartPos(int startPos) {
this.startPos = startPos;
}

@Override
public void complete(LineReader reader, final ParsedLine commandLine, List<Candidate> candidates) {
assert commandLine != null;
Expand All @@ -941,7 +945,7 @@ public void complete(LineReader reader, final ParsedLine commandLine, List<Candi
candidates.add(new Candidate(buffer, buffer, null, null, null, null, true));
return;
}
String command = reader.getParser().getCommand(words.get(0));
String command = reader.getParser().getCommand(words.get(words.size() - startPos));
if (buffer.startsWith("-")) {
boolean addbuff = true;
boolean valueCandidates = false;
Expand Down
118 changes: 76 additions & 42 deletions builtins/src/main/java/org/jline/builtins/SystemRegistryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@
* @author <a href="mailto:matti.rintanikkola@gmail.com">Matti Rinta-Nikkola</a>
*/
public class SystemRegistryImpl implements SystemRegistry {
public enum Command {
EXIT, HELP
};

public enum Pipe {
FLIP, NAMED, AND, OR
Expand All @@ -67,11 +64,9 @@ public enum Pipe {
private Integer consoleId;
private Parser parser;
private ConfigurationPath configPath;
private Map<Command, String> commandName = new HashMap<>();
private Map<String, Command> nameCommand = new HashMap<>();
private Map<String, String> aliasCommand = new HashMap<>();
private Map<String,CommandRegistry> subcommands = new HashMap<>();
private Map<Pipe, String> pipeName = new HashMap<>();
private final Map<Command, CommandMethods> commandExecute = new HashMap<>();
private final Map<String, CommandMethods> commandExecute = new HashMap<>();
private Map<String, List<String>> commandInfos = new HashMap<>();
private Exception exception;
private CommandOutputStream outputStream;
Expand All @@ -81,21 +76,12 @@ public SystemRegistryImpl(Parser parser, Terminal terminal, ConfigurationPath co
this.parser = parser;
this.configPath = configPath;
outputStream = new CommandOutputStream(terminal);
Set<Command> cmds = new HashSet<>(EnumSet.allOf(Command.class));
for (Command c : cmds) {
commandName.put(c, c.name().toLowerCase());
}
doNameCommand();
pipeName.put(Pipe.FLIP, "|;");
pipeName.put(Pipe.NAMED, "|");
pipeName.put(Pipe.AND, "&&");
pipeName.put(Pipe.OR, "||");
commandExecute.put(Command.EXIT, new CommandMethods(this::exit, this::exitCompleter));
commandExecute.put(Command.HELP, new CommandMethods(this::help, this::helpCompleter));
}

private void doNameCommand() {
nameCommand = commandName.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
commandExecute.put("exit", new CommandMethods(this::exit, this::exitCompleter));
commandExecute.put("help", new CommandMethods(this::help, this::helpCompleter));
}

public void rename(Pipe pipe, String name) {
Expand Down Expand Up @@ -151,7 +137,7 @@ public Set<String> commandNames() {
}

private Set<String> localCommandNames() {
return nameCommand.keySet();
return commandExecute.keySet();
}

@Override
Expand All @@ -160,29 +146,26 @@ public Map<String, String> commandAliases() {
for (CommandRegistry r : commandRegistries) {
out.putAll(r.commandAliases());
}
out.putAll(aliasCommand);
return out;
}

private Command command(String name) {
Command out = null;
if (!isLocalCommand(name)) {
throw new IllegalArgumentException("Command does not exists!");
}
if (aliasCommand.containsKey(name)) {
name = aliasCommand.get(name);
}
if (nameCommand.containsKey(name)) {
out = nameCommand.get(name);
} else {
throw new IllegalArgumentException("Command does not exists!");
}
return out;
/**
* Register subcommand registry
* @param command main command
* @param subcommandRegistry subcommand registry
*/
public void register(String command, CommandRegistry subcommandRegistry) {
subcommands.put(command, subcommandRegistry);
commandExecute.put(command, new Builtins.CommandMethods(this::subcommand, this::emptyCompleter));
}

private List<String> localCommandInfo(String command) {
try {
localExecute(command, new String[] { "--help" });
if (subcommands.containsKey(command)) {
return subcommands.get(command).commandInfo("help");
} else {
localExecute(command, new String[] { "--help" });
}
} catch (HelpException e) {
exception = null;
return Builtins.compileCommandInfo(e.getMessage());
Expand Down Expand Up @@ -215,7 +198,7 @@ public boolean hasCommand(String command) {
}

private boolean isLocalCommand(String command) {
return nameCommand.containsKey(command) || aliasCommand.containsKey(command);
return commandExecute.containsKey(command);
}

private boolean isCommandOrScript(String command) {
Expand All @@ -229,10 +212,28 @@ private boolean isCommandOrScript(String command) {
public Completers.SystemCompleter compileCompleters() {
Completers.SystemCompleter out = CommandRegistry.aggregateCompleters(commandRegistries);
Completers.SystemCompleter local = new Completers.SystemCompleter();
for (Map.Entry<Command, String> entry : commandName.entrySet()) {
local.add(entry.getValue(), commandExecute.get(entry.getKey()).compileCompleter().apply(entry.getValue()));
for (String command : commandExecute.keySet()) {
if (subcommands.containsKey(command)) {
for(Map.Entry<String,List<Completer>> entry : subcommands.get(command).compileCompleters().getCompleters().entrySet()) {
for (Completer cc : entry.getValue()) {
if (!(cc instanceof ArgumentCompleter)) {
throw new IllegalArgumentException();
}
List<Completer> cmps = ((ArgumentCompleter)cc).getCompleters();
cmps.add(0, NullCompleter.INSTANCE);
cmps.set(1, new StringsCompleter(entry.getKey()));
Completer last = cmps.get(cmps.size() - 1);
if (last instanceof OptionCompleter) {
((OptionCompleter)last).setStartPos(cmps.size() - 1);
cmps.set(cmps.size() - 1, last);
}
local.add(command, new ArgumentCompleter(cmps));
}
}
} else {
local.add(command, commandExecute.get(command).compileCompleter().apply(command));
}
}
local.addAliases(aliasCommand);
out.add(local);
out.compile();
return out;
Expand Down Expand Up @@ -284,7 +285,13 @@ public Widgets.CmdDesc commandDescription(Widgets.CmdLine line) {
case COMMAND:
String cmd = parser.getCommand(line.getArgs().get(0));
if (isCommandOrScript(cmd) && !hasPipes(line.getArgs())) {
out = commandDescription(cmd);
if (subcommands.containsKey(cmd)) {
List<String> args = line.getArgs();
String c = args.size() > 1 ? args.get(1) : "help";
out = subcommands.get(cmd).commandDescription(c);
} else {
out = commandDescription(cmd);
}
}
break;
case METHOD:
Expand Down Expand Up @@ -333,7 +340,7 @@ public Object localExecute(String command, String[] args) throws Exception {
if (!isLocalCommand(command)) {
throw new IllegalArgumentException();
}
Object out = commandExecute.get(command(command)).executeFunction()
Object out = commandExecute.get(command).executeFunction()
.apply(new Builtins.CommandInput(command, args, commandSession()));
if (exception != null) {
throw exception;
Expand Down Expand Up @@ -1250,6 +1257,7 @@ private Object help(Builtins.CommandInput input) {
boolean withInfo = commands.size() < terminal().getHeight() || !opt.args().isEmpty() ? true : false;
int max = Collections.max(commands, Comparator.comparing(String::length)).length() + 1;
TreeMap<String, String> builtinCommands = new TreeMap<>();
TreeMap<String, String> systemCommands = new TreeMap<>();
for (CommandRegistry r : commandRegistries) {
if (isBuiltinRegistry(r)) {
for (String c : r.commandNames()) {
Expand All @@ -1258,9 +1266,19 @@ private Object help(Builtins.CommandInput input) {
}
}
for (String c : localCommandNames()) {
builtinCommands.put(c, doCommandInfo(commandInfo(c)));
systemCommands.put(c, doCommandInfo(commandInfo(c)));
exception = null;
}
if (isInArgs(opt.args(), "System")) {
printHeader("System");
if (withInfo) {
for (Map.Entry<String, String> entry : systemCommands.entrySet()) {
printCommandInfo(entry.getKey(), entry.getValue(), max);
}
} else {
printCommands(systemCommands.keySet(), max);
}
}
if (isInArgs(opt.args(), "Builtins")) {
printHeader("Builtins");
if (withInfo) {
Expand Down Expand Up @@ -1321,6 +1339,18 @@ private Object exit(Builtins.CommandInput input) {
return null;
}

private Object subcommand(Builtins.CommandInput input) {
Object out = null;
try {
out = subcommands.get(input.command()).execute(input.session()
, input.args()[0]
, Arrays.copyOfRange(input.args(), 1, input.args().length));
} catch (Exception e) {
exception = e;
}
return out;
}

private List<OptDesc> commandOptions(String command) {
try {
localExecute(command, new String[] { "--help" });
Expand Down Expand Up @@ -1348,6 +1378,10 @@ private List<String> registryNames() {
return out;
}

private List<Completer> emptyCompleter(String command) {
return new ArrayList<>();
}

private List<Completer> helpCompleter(String command) {
List<Completer> completers = new ArrayList<>();
completers.add(new ArgumentCompleter(NullCompleter.INSTANCE,
Expand Down
Loading

0 comments on commit c2d2087

Please sign in to comment.