Skip to content

Commit

Permalink
ConsoleEngine: Add support for widget execution, fixes #503
Browse files Browse the repository at this point in the history
  • Loading branch information
mattirn committed Jan 31, 2020
1 parent 1bcf06f commit ab7f094
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 55 deletions.
102 changes: 73 additions & 29 deletions builtins/src/main/java/org/jline/builtins/ConsoleEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,32 @@

import org.jline.builtins.CommandRegistry;
import org.jline.reader.Completer;
import org.jline.reader.LineReader;
import org.jline.reader.ParsedLine;
import org.jline.reader.Widget;

/**
* Manage console variables, commands and script executions.
*
* Manage console variables, commands and script executions.
*
* @author <a href="mailto:matti.rintanikkola@gmail.com">Matti Rinta-Nikkola</a>
*/
public interface ConsoleEngine extends CommandRegistry {

/**
* Removes command first character if it is colon
* @param command
* @return
* @param command name to complete
* @return command name without colon
*/
static String plainCommand(String command) {
return command.startsWith(":") ? command.substring(1) : command;
return command.startsWith(":") ? command.substring(1) : command;
}

/**
* Sets lineReader
* @param reader LineReader
*/
void setLineReader(LineReader reader);

/**
* Sets systemRegistry
* @param systemRegistry
Expand All @@ -42,86 +50,122 @@ static String plainCommand(String command) {
* Substituting args references with their values.
* @param args
* @return Substituted args
* @throws Exception
* @throws Exception in case of error
*/
Object[] expandParameters(String[] args) throws Exception;

/**
* Returns all scripts found from PATH
* @return script names
*/
List<String> scripts();


/**
* Sets file name extension used by console scripts
* @param console script file extension
*/
public void setScriptExtension(String extension);

/**
* Returns true if alias 'name' exists
* @param alias name
* @return
* @return true if alias exists
*/
boolean hasAlias(String name);

/**
* Returns alias 'name' value
* @param alias name
* @return value of alias
*/
String getAlias(String name);

/**
* Returns script and variable completers
* @return completers
* @return script completers
*/
List<Completer> scriptCompleters();

/**
* Executes parsed line that does not contain known command by the system registry.
* If parsed line is neither JLine or ScriptEngine script it will be evaluated
* as ScriptEngine statement.
* @param parsedLine
* @return result
* @throws Exception
* @param parsed command line
* @return command line execution result
* @throws Exception in case of error
*/
Object execute(ParsedLine parsedLine) throws Exception;

/**
* Executes either JLine or ScriptEngine script.
* @param script
* @return result
* @throws Exception
* @param script file
* @return script execution result
* @throws Exception in case of error
*/
default Object execute(File script) throws Exception {
return execute(script, "", new String[0]);
}

/**
* Executes either JLine or ScriptEngine script.
* @param script
* @param cmdLine
* @param args
* @return result
* @throws Exception
* @param script file
* @param cmdLine complete command line
* @param svript arguments
* @return script execution result
* @throws Exception in case of error
*/
Object execute(File script, String cmdLine, String[] args) throws Exception;

/**
* Post processes execution result. If result is to be assigned to the console variable
* then method will return null.
* @param line
* @param result
* @return result
* @param result to process
* @return processed result
*/
Object postProcess(String line, Object result);

/**
* Displays object.
* @param object
* @param object to print
*/
void println(Object object);

/**
* Displays object.
* @param options
* @param object
* @param options println options
* @param object to print
*/
void println(Map<String, Object> options, Object object);

/**
* Get variable value
* @param name of variable
* @return variable value
*/
Object getVariable(String name);

/**
* Execute widget function
* @param function to execute
* @return true on success
*/
boolean executeWidget(Object function);

static class WidgetCreator implements Widget {
private ConsoleEngine consoleEngine;
private Object function;

public WidgetCreator(ConsoleEngine consoleEngine, String function) {
this.consoleEngine = consoleEngine;
this.function = consoleEngine.getVariable(function);
}

@Override
public boolean apply() {
return consoleEngine.executeWidget(function);
}

}

}
70 changes: 50 additions & 20 deletions builtins/src/main/java/org/jline/builtins/ConsoleEngineImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,16 @@ public enum Command {SHOW
private Exception exception;
private SystemRegistry systemRegistry;
private String scriptExtension = "jline";
private final Parser parser;
private final Terminal terminal;
private final Supplier<Path> workDir;
private final ConfigurationPath configPath;
private final Map<String, String> aliases = new HashMap<>();
private Path aliasFile;
private LineReader reader;

@SuppressWarnings("unchecked")
public ConsoleEngineImpl(ScriptEngine engine
, Parser parser
, Terminal terminal
, Supplier<Path> workDir, ConfigurationPath configPath) throws IOException {
this.engine = engine;
this.parser = parser;
this.terminal = terminal;
this.workDir = workDir;
this.configPath = configPath;
Set<Command> cmds = new HashSet<>(EnumSet.allOf(Command.class));
Expand All @@ -103,14 +98,27 @@ public ConsoleEngineImpl(ScriptEngine engine
}
}

@Override
public void setLineReader(LineReader reader) {
this.reader= reader;
}

private Parser parser() {
return reader.getParser();
}

private Terminal terminal() {
return reader.getTerminal();
}

@Override
public void setSystemRegistry(SystemRegistry systemRegistry) {
this.systemRegistry = systemRegistry;
}

public ConsoleEngineImpl scriptExtension(String extension) {
@Override
public void setScriptExtension(String extension) {
this.scriptExtension = extension;
return this;
}

@Override
Expand Down Expand Up @@ -449,7 +457,7 @@ private void internalExecute() throws Exception {
for (String l; (l = br.readLine()) != null;) {
try {
line += l;
parser.parse(line, line.length() + 1, ParseContext.ACCEPT_LINE);
parser().parse(line, line.length() + 1, ParseContext.ACCEPT_LINE);
done = true;
for (int i = 1; i < args.length; i++) {
line = line.replaceAll("\\s\\$" + i + "\\b",
Expand All @@ -467,8 +475,8 @@ private void internalExecute() throws Exception {
if (verbose) {
AttributedStringBuilder asb = new AttributedStringBuilder();
asb.append(line, AttributedStyle.DEFAULT.foreground(AttributedStyle.GREEN));
asb.toAttributedString().println(terminal);
terminal.flush();
asb.toAttributedString().println(terminal());
terminal().flush();
}
systemRegistry.execute(line);
line = "";
Expand Down Expand Up @@ -499,6 +507,7 @@ public Object getResult() {

}

@Override
public Object execute(File script, String cmdLine, String[] args) throws Exception {
ScriptFile file = new ScriptFile(script, cmdLine, args);
file.execute();
Expand All @@ -522,7 +531,7 @@ public Object execute(ParsedLine pl) throws Exception {
StringBuilder sb = new StringBuilder();
for (String s: line.split("\n|\n\r")) {
if (isCommandLine(s)) {
List<String> ws = parser.parse(s, 0, ParseContext.COMPLETE).words();
List<String> ws = parser().parse(s, 0, ParseContext.COMPLETE).words();
int idx = ws.get(0).lastIndexOf(":");
if (idx > 0) {
sb.append(ws.get(0).substring(0, idx));
Expand Down Expand Up @@ -566,6 +575,27 @@ public Object execute(ParsedLine pl) throws Exception {
return out;
}

@Override
public Object getVariable(String name) {
if (!engine.hasVariable(name)) {
throw new IllegalArgumentException("Variable " + name + " does not exists!");
}
return engine.get(name);
}

@Override
public boolean executeWidget(Object function) {
engine.put("_reader", reader);
engine.put("_widgetFunction", function);
try {
engine.execute("_widgetFunction()");
} catch (Exception e) {
println(e);
return false;
}
return true;
}

@Override
public Object postProcess(String line, Object result) {
Object out = result;
Expand Down Expand Up @@ -625,7 +655,7 @@ public void println(Map<String, Object> options, Object object) {
if (object == null) {
return;
}
options.putIfAbsent("width", terminal.getSize().getColumns());
options.putIfAbsent("width", terminal().getSize().getColumns());
String style = (String) options.getOrDefault("style", "");
int width = (int) options.get("width");
if (style.equalsIgnoreCase("JSON")) {
Expand All @@ -634,7 +664,7 @@ public void println(Map<String, Object> options, Object object) {
highlight(width, style, (String) object);
} else if (object instanceof Exception) {
if (object instanceof Options.HelpException) {
Options.HelpException.highlight(((Exception)object).getMessage(), Options.HelpException.defaultStyle()).print(terminal);
Options.HelpException.highlight(((Exception)object).getMessage(), Options.HelpException.defaultStyle()).print(terminal());
} else if (options.getOrDefault("exception", "stack").equals("stack")) {
((Exception) object).printStackTrace();
} else {
Expand All @@ -646,24 +676,24 @@ public void println(Map<String, Object> options, Object object) {
asb.append("Caught exception: ", AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
asb.append(object.getClass().getCanonicalName(), AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
}
asb.toAttributedString().println(terminal);
asb.toAttributedString().println(terminal());
}
} else if (object instanceof String) {
highlight(AttributedStyle.YELLOW + AttributedStyle.BRIGHT, object);
} else if (object instanceof Number) {
highlight(AttributedStyle.BLUE + AttributedStyle.BRIGHT, object);
} else {
for (AttributedString as : engine.highlight(options, object)) {
as.println(terminal);
as.println(terminal());
}
}
terminal.flush();
terminal().flush();
}

private void highlight(int attrStyle, Object obj) {
AttributedStringBuilder asb = new AttributedStringBuilder();
asb.append(obj.toString(), AttributedStyle.DEFAULT.foreground(attrStyle));
asb.toAttributedString().println(terminal);
asb.toAttributedString().println(terminal());
}

private void highlight(int width, String style, String object) {
Expand All @@ -680,9 +710,9 @@ private void highlight(int width, String style, String object) {
AttributedStringBuilder asb = new AttributedStringBuilder();
asb.append(s).setLength(width);
if (highlighter != null) {
highlighter.highlight(asb).println(terminal);
highlighter.highlight(asb).println(terminal());
} else {
asb.toAttributedString().println(terminal);
asb.toAttributedString().println(terminal());
}
}
}
Expand Down
9 changes: 3 additions & 6 deletions demo/src/main/java/org/jline/demo/Repl.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,9 @@
import org.jline.reader.EndOfFileException;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.MaskingCallback;
import org.jline.reader.ParsedLine;
import org.jline.reader.Reference;
import org.jline.reader.UserInterruptException;
import org.jline.reader.LineReader.Option;
import org.jline.reader.Parser.ParseContext;
import org.jline.reader.impl.DefaultParser;
import org.jline.reader.impl.LineReaderImpl;
import org.jline.reader.impl.DefaultParser.Bracket;
Expand Down Expand Up @@ -256,13 +253,12 @@ public static void main(String[] args) {
GroovyEngine scriptEngine = new GroovyEngine();
scriptEngine.put("ROOT", root);
ConfigurationPath configPath = new ConfigurationPath(Paths.get(root), Paths.get(root));
Builtins builtins = new Builtins(Paths.get(""), configPath, null);
ConsoleEngine consoleEngine = new ConsoleEngineImpl(scriptEngine, parser, terminal, ()->Paths.get(""), configPath);
ConsoleEngine consoleEngine = new ConsoleEngineImpl(scriptEngine, ()->Paths.get(""), configPath);
Builtins builtins = new Builtins(Paths.get(""), configPath, (String fun)-> {return new ConsoleEngine.WidgetCreator(consoleEngine, fun);});
MyCommands myCommands = new MyCommands();
SystemRegistry systemRegistry = new SystemRegistryImpl(parser, terminal, configPath);
systemRegistry.setCommandRegistries(consoleEngine, builtins, myCommands);
//
//
// LineReader
//
LineReader reader = LineReaderBuilder.builder()
Expand All @@ -284,6 +280,7 @@ public static void main(String[] args) {
//
// complete command registeries
//
consoleEngine.setLineReader(reader);
builtins.setLineReader(reader);
myCommands.setLineReader(reader);
//
Expand Down

0 comments on commit ab7f094

Please sign in to comment.