Skip to content

Commit

Permalink
GroovyEngine: display method descriptions on status bar
Browse files Browse the repository at this point in the history
  • Loading branch information
mattirn committed Jun 20, 2020
1 parent 272648e commit fb196ca
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.nio.file.Path;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -76,6 +77,7 @@ public enum Pipe {
private SystemCompleter customSystemCompleter = new SystemCompleter();
private AggregateCompleter customAggregateCompleter = new AggregateCompleter(new ArrayList<>());
private boolean commandGroups = true;
private Function<CmdLine,CmdDesc> scriptDescription;

public SystemRegistryImpl(Parser parser, Terminal terminal, Supplier<Path> workDir, ConfigurationPath configPath) {
this.parser = parser;
Expand Down Expand Up @@ -338,6 +340,10 @@ private CmdDesc commandDescription(CommandRegistry subreg) {
return new CmdDesc(main, ArgDesc.doArgNames(Arrays.asList("")), options);
}

public void setScriptDescription(Function<CmdLine,CmdDesc> scriptDescription) {
this.scriptDescription = scriptDescription;
}

@Override
public CmdDesc commandDescription(CmdLine line) {
CmdDesc out = null;
Expand Down Expand Up @@ -370,7 +376,7 @@ public CmdDesc commandDescription(CmdLine line) {
break;
case METHOD:
case SYNTAX:
// TODO
out = scriptDescription.apply(line);
break;
}
return out;
Expand Down
1 change: 1 addition & 0 deletions demo/src/main/java/org/jline/demo/Repl.java
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ public static void main(String[] args) {
systemRegistry.register("groovy", new GroovyCommand(scriptEngine, printer));
systemRegistry.setCommandRegistries(consoleEngine, builtins, myCommands);
systemRegistry.addCompleter(scriptEngine.getScriptCompleter());
systemRegistry.setScriptDescription(scriptEngine::scriptDescription);
//
// LineReader
//
Expand Down
251 changes: 201 additions & 50 deletions groovy/src/main/java/org/jline/script/GroovyEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package org.jline.script;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
Expand All @@ -17,6 +18,9 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jline.builtins.Nano.SyntaxHighlighter;
import org.jline.console.CmdDesc;
import org.jline.console.CmdLine;
import org.jline.console.ScriptEngine;
import org.jline.groovy.Utils;
import org.jline.reader.Candidate;
Expand Down Expand Up @@ -336,6 +340,11 @@ public Cloner getObjectCloner() {
return objectCloner;
}

public CmdDesc scriptDescription(CmdLine line) {
return new Inspector(this).scriptDescription(line);
}


private Completer compileCompleter() {
List<Completer> completers = new ArrayList<>();
completers.add(new ArgumentCompleter(new StringsCompleter("while", "class", "for", "print", "println"), NullCompleter.INSTANCE));
Expand Down Expand Up @@ -482,6 +491,54 @@ public static void doCandidates(List<Candidate> candidates, Collection<String> f
null, false));
}
}

public static int statementBegin(String buffer, String wordbuffer, Brackets brackets) {
int out = wordbuffer.lastIndexOf('=');
if (brackets.openRound()) {
int idx = buffer.lastIndexOf(wordbuffer);
if (idx > -1) {
out = statementBegin(out
, brackets.lastOpenRound() - idx
, brackets.lastComma() - idx
, brackets.lastOpenCurly() - idx
, brackets.lastCloseCurly() - idx
, brackets.lastSemicolon() -idx
, brackets.lastBlanck() - idx);
}
}
return out;
}

public static int statementBegin(int eqPos, Brackets brackets) {
return statementBegin(eqPos
, brackets.lastOpenRound()
, brackets.lastComma()
, brackets.lastOpenCurly(), brackets.lastCloseCurly(), brackets.lastSemicolon(), brackets.lastBlanck());
}

private static int statementBegin(int eqPos, int openRound, int comma, int openCurly, int closeCurly, int semicolon, int blanck) {
int out = eqPos;
if (openRound > out) {
out = openRound;
}
if (comma > out) {
out = comma;
}
if (openCurly > out) {
out = openCurly;
}
if (closeCurly > out) {
out = closeCurly;
}
if (semicolon > out) {
out = semicolon;
}
if (blanck > out) {
out = blanck;
}
return Math.max(out, -1);
}

}

private class PackageCompleter implements Completer {
Expand Down Expand Up @@ -543,13 +600,7 @@ public void complete(LineReader reader, ParsedLine commandLine, List<Candidate>
&& brackets.lastCloseRound() > brackets.lastBlanck()
&& brackets.lastCloseRound() > brackets.lastCloseCurly()) {
int varsep = buffer.lastIndexOf('.');
int eqsep = statementBegin(buffer.indexOf('=')
, brackets.lastOpenRound()
, brackets.lastComma()
, brackets.lastOpenCurly()
, brackets.lastCloseCurly()
, brackets.lastSemicolon()
, brackets.lastBlanck());
int eqsep = Helpers.statementBegin(buffer.lastIndexOf('='), brackets);
if (varsep > 0 && varsep > eqsep) {
Class<?> clazz = evaluateClass(inspector, buffer.substring(eqsep + 1, varsep));
int vs = wordbuffer.lastIndexOf('.');
Expand Down Expand Up @@ -580,7 +631,7 @@ public void complete(LineReader reader, ParsedLine commandLine, List<Candidate>
}
} else {
int varsep = wordbuffer.lastIndexOf('.');
int eqsep = statementBegin(buffer, wordbuffer, brackets);
int eqsep = Helpers.statementBegin(buffer, wordbuffer, brackets);
String param = wordbuffer.substring(eqsep + 1);
if (varsep < 0 || varsep < eqsep) {
String curBuf = wordbuffer.substring(0, eqsep + 1);
Expand Down Expand Up @@ -620,46 +671,6 @@ public void complete(LineReader reader, ParsedLine commandLine, List<Candidate>
}
}

private int statementBegin(String buffer, String wordbuffer, Brackets brackets) {
int out = wordbuffer.indexOf('=');
if (brackets.openRound()) {
int idx = buffer.lastIndexOf(wordbuffer);
if (idx > -1) {
out = statementBegin(out
, brackets.lastOpenRound() - idx
, brackets.lastComma() - idx
, brackets.lastOpenCurly() - idx
, brackets.lastCloseCurly() - idx
, brackets.lastSemicolon() -idx
, brackets.lastBlanck() - idx);
}
}
return out;
}

private int statementBegin(int eqPos, int openRound, int comma, int openCurly, int closeCurly, int semicolon, int blanck) {
int out = eqPos;
if (openRound > out) {
out = openRound;
}
if (comma > out) {
out = comma;
}
if (openCurly > out) {
out = openCurly;
}
if (closeCurly > out) {
out = closeCurly;
}
if (semicolon > out) {
out = semicolon;
}
if (blanck > out) {
out = blanck;
}
return Math.max(out, -1);
}

private Set<String> variables(Inspector inspector) {
if (inspector == null) {
inspector = new Inspector(groovyEngine);
Expand Down Expand Up @@ -748,12 +759,21 @@ public Inspector(GroovyEngine groovyEngine) {
}

public Class<?> evaluateClass(String objectStatement) {
Class<?> out = null;
try {
return execute(objectStatement).getClass();
if (objectStatement.contains("(") || objectStatement.contains(")")
|| objectStatement.contains("{") || objectStatement.contains("}")) {
out = execute(objectStatement).getClass();
} else if (!objectStatement.contains(".") ) {
out = (Class<?>)execute(objectStatement + ".class");
} else {
out = Class.forName(objectStatement);
}

} catch (Exception e) {

}
return null;
return out;
}

private Object execute(String statement) {
Expand Down Expand Up @@ -808,6 +828,137 @@ public Object getVariable(String name) {
return sharedData.hasVariable(name) ? sharedData.getVariable(name) : null;
}

public CmdDesc scriptDescription(CmdLine line) {
CmdDesc out = null;
try {
switch (line.getDescriptionType()) {
case COMMAND:
break;
case METHOD:
out = methodDescription(line);
break;
case SYNTAX:
break;
}
} catch (Exception e) {
if (Log.isDebugEnabled()) {
e.printStackTrace();
}
}
return out;
}

private String trimName(String name) {
String out = name;
int idx = name.indexOf('(');
if (idx > 0) {
out = name.substring(0, idx);
}
return out;
}

private CmdDesc methodDescription(CmdLine line) throws Exception {
CmdDesc out = new CmdDesc();
List<String> args = line.getArgs();
boolean constructor = false;
Class<?> clazz = null;
String methodName = null;
if ((args.size() == 2 && args.get(0).matches("(new|\\w+=new)"))
|| (args.size() > 2 && args.get(args.size() - 2).matches("(new|.*\\(new|.*,new)"))) {
constructor = true;
clazz = evaluateClass(trimName(args.get(args.size() - 1)));
} else {
String buffer = line.getHead();
String wordbuffer = args.get(args.size() - 1);
Brackets brackets = new Brackets(buffer);
int varsep = wordbuffer.lastIndexOf('.');
int eqsep = Helpers.statementBegin(buffer, wordbuffer, brackets);
if (varsep > 0 && varsep > eqsep) {
loadStatementVars(buffer);
methodName = trimName(wordbuffer.substring(varsep + 1));
clazz = evaluateClass(wordbuffer.substring(eqsep + 1, varsep));
}
}
List<AttributedString> mainDesc = new ArrayList<>();
if (clazz != null) {
SyntaxHighlighter java = SyntaxHighlighter.build("classpath:/org/jline/groovy/java.nanorc");
mainDesc.add(java.highlight(clazz.toString()));
if (constructor) {
for (Constructor<?> m : clazz.getConstructors()) {
StringBuilder sb = new StringBuilder();
sb.append(m.getName());
sb.append("(");
boolean first = true;
for(Class<?> p: m.getParameterTypes()) {
if (!first) {
sb.append(", ");
}
sb.append(p.getTypeName());
first = false;
}
sb.append(")");
first = true;
for (Class<?> e: m.getExceptionTypes()) {
if (first) {
sb.append(" throws ");
} else {
sb.append(", ");
}
sb.append(e.getCanonicalName());
first = false;
}
mainDesc.add(java.highlight(sb.toString().replaceAll("java.lang.", "")));
}
} else {
List<String> addedMethods = new ArrayList<>();
do {
for (Method m : clazz.getMethods()) {
if (!m.getName().equals(methodName)) {
continue;
}
StringBuilder sb = new StringBuilder();
if (Modifier.isFinal(m.getModifiers())) {
sb.append("final ");
}
if (Modifier.isStatic(m.getModifiers())) {
sb.append("static ");
}
sb.append(m.getReturnType().getCanonicalName());
sb.append(" ");
sb.append(methodName);
sb.append("(");
boolean first = true;
for (Class<?> p : m.getParameterTypes()) {
if (!first) {
sb.append(", ");
}
sb.append(p.getTypeName());
first = false;
}
sb.append(")");
first = true;
for (Class<?> e : m.getExceptionTypes()) {
if (first) {
sb.append(" throws ");
} else {
sb.append(", ");
}
sb.append(e.getCanonicalName());
first = false;
}
if (!addedMethods.contains(sb.toString())) {
addedMethods.add(sb.toString());
mainDesc.add(java.highlight(sb.toString().replaceAll("java.lang.", "")));
}
}
clazz = clazz.getSuperclass();
} while (clazz != null);
}
out.setMainDesc(mainDesc);
}
return out;
}

}

private static class ObjectCloner implements Cloner {
Expand Down
17 changes: 17 additions & 0 deletions groovy/src/main/resources/org/jline/groovy/java.nanorc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## Here is an example for Java.
##
syntax "Java" "\.java$"
color green "\<(boolean|byte|char|double|float|int|long|new|short|this|transient|void)\>"
color red "\<(break|case|catch|continue|default|do|else|finally|for|if|return|switch|throw|try|while)\>"
color green,,faint "(([a-z]{2,}[.]{1}){2,10}([a-z]{2,}){0,1})"
color green "\<[A-Z]{0,2}([A-Z]{1}[a-z]+){1,}\>"
color cyan "\<(abstract|class|extends|final|implements|import|instanceof|interface|native|package|private|protected|public|static|strictfp|super|synchronized|throws|volatile)\>"
color red ""[^"]*""
color yellow "\<(true|false|null)\>"
color yellow "\<[A-Z]+([_]{1}[A-Z]+){0,}\>"
icolor yellow "\b(([1-9][0-9]+)|0+)\.[0-9]+\b" "\b[1-9][0-9]*\b" "\b0[0-7]*\b" "\b0x[1-9a-f][0-9a-f]*\b"
color blue "//.*"
color blue start="/\*" end="\*/"
color brightblue start="/\*\*" end="\*/"
color brightwhite,yellow "(FIXME|TODO|XXX)"
color ,green "[[:space:]]+$"

0 comments on commit fb196ca

Please sign in to comment.