Skip to content

Commit

Permalink
Groovy REPL: highlight command and groovy language syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
mattirn committed Nov 28, 2020
1 parent bb5e85a commit ca381ee
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 20 deletions.
10 changes: 8 additions & 2 deletions console/src/main/java/org/jline/console/SystemRegistry.java
Expand Up @@ -26,8 +26,8 @@
public interface SystemRegistry extends CommandRegistry, ConsoleOptionGetter {

/**
* Set command registeries
* @param commandRegistries command registeries used by the application
* Set command registries
* @param commandRegistries command registries used by the application
*/
void setCommandRegistries(CommandRegistry... commandRegistries);

Expand Down Expand Up @@ -117,6 +117,12 @@ public interface SystemRegistry extends CommandRegistry, ConsoleOptionGetter {
* @return true if the specified line has a command registered
*/
boolean isCommandOrScript(ParsedLine line);
/**
* Returns whether a line contains command/script that is known to this registry.
* @param command the command to test
* @return true if the specified line has a command registered
*/
boolean isCommandOrScript(String command);

/**
* Orderly close SystemRegistry.
Expand Down
110 changes: 110 additions & 0 deletions console/src/main/java/org/jline/console/impl/SystemHighlighter.java
@@ -0,0 +1,110 @@
/*
* Copyright (c) 2002-2020, the original author or authors.
*
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
*
* https://opensource.org/licenses/BSD-3-Clause
*/
package org.jline.console.impl;

import org.jline.builtins.Nano.SyntaxHighlighter;
import org.jline.console.SystemRegistry;
import org.jline.reader.LineReader;
import org.jline.reader.Parser;
import org.jline.reader.impl.DefaultHighlighter;
import org.jline.utils.AttributedString;
import org.jline.utils.AttributedStringBuilder;

import java.util.regex.Pattern;

/**
* Highlight command and language syntax using nanorc highlighter.
*
* @author <a href="mailto:matti.rintanikkola@gmail.com">Matti Rinta-Nikkola</a>
*/
public class SystemHighlighter extends DefaultHighlighter {
private final SyntaxHighlighter commandHighlighter;
private final SyntaxHighlighter argsHighlighter;
private final SyntaxHighlighter langHighlighter;
private Pattern errorPattern;
private int errorIndex = -1;

public SystemHighlighter(SyntaxHighlighter commandHighlighter, SyntaxHighlighter argsHighlighter
, SyntaxHighlighter langHighlighter) {
this.commandHighlighter = commandHighlighter;
this.argsHighlighter = argsHighlighter;
this.langHighlighter = langHighlighter;
}

@Override
public void setErrorPattern(Pattern errorPattern) {
this.errorPattern = errorPattern;
super.setErrorPattern(errorPattern);
}

@Override
public void setErrorIndex(int errorIndex) {
this.errorIndex = errorIndex;
super.setErrorIndex(errorIndex);
}

@Override
public AttributedString highlight(LineReader reader, String buffer) {
return doDefaultHighlight(reader) ? super.highlight(reader, buffer) : systemHighlight(reader.getParser(), buffer);
}

private boolean doDefaultHighlight(LineReader reader) {
String search = reader.getSearchTerm();
return ((search != null && search.length() > 0) || reader.getRegionActive() != LineReader.RegionType.NONE
|| errorIndex > -1 || errorPattern != null);
}

private AttributedString systemHighlight(Parser parser, String buffer) {
AttributedString out;
if (buffer.trim().isEmpty()) {
out = new AttributedStringBuilder().append(buffer).toAttributedString();
} else if (SystemRegistry.get().isCommandOrScript(parser.getCommand(buffer.trim().split("\\s+")[0]))) {
if (commandHighlighter != null || argsHighlighter != null) {
int idx = -1;
boolean cmdFound = false;
for (int i = 0; i < buffer.length(); i++) {
char c = buffer.charAt(i);
if (c != ' ') {
cmdFound = true;
} else if (cmdFound) {
idx = i;
break;
}
}
AttributedStringBuilder asb = new AttributedStringBuilder();
if (idx < 0) {
highlightCommand(buffer, asb);
} else {
highlightCommand(buffer.substring(0, idx), asb);
if (argsHighlighter != null) {
asb.append(argsHighlighter.highlight(buffer.substring(idx)));
} else {
asb.append(buffer.substring(idx));
}
}
out = asb.toAttributedString();
} else {
out = new AttributedStringBuilder().append(buffer).toAttributedString();
}
} else if (langHighlighter != null) {
out = langHighlighter.highlight(buffer);
} else {
out = new AttributedStringBuilder().append(buffer).toAttributedString();
}
return out;
}

private void highlightCommand(String command, AttributedStringBuilder asb) {
if (commandHighlighter != null) {
asb.append(commandHighlighter.highlight(command));
} else {
asb.append(command);
}
}
}
Expand Up @@ -233,7 +233,8 @@ public boolean isCommandOrScript(ParsedLine line) {
return isCommandOrScript(parser.getCommand(line.words().get(0)));
}

private boolean isCommandOrScript(String command) {
@Override
public boolean isCommandOrScript(String command) {
if (hasCommand(command)) {
return true;
}
Expand Down
30 changes: 19 additions & 11 deletions demo/src/main/java/org/jline/demo/Repl.java
Expand Up @@ -8,10 +8,7 @@
*/
package org.jline.demo;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
Expand All @@ -24,17 +21,14 @@
import java.util.function.Supplier;

import org.jline.builtins.*;
import org.jline.builtins.Nano.SyntaxHighlighter;
import org.jline.builtins.Completers.OptionCompleter;
import org.jline.console.impl.Builtins;
import org.jline.console.impl.ConsoleEngineImpl;
import org.jline.console.impl.DefaultPrinter;
import org.jline.console.impl.SystemRegistryImpl;
import org.jline.console.impl.*;
import org.jline.console.CommandInput;
import org.jline.console.CommandMethods;
import org.jline.console.CommandRegistry;
import org.jline.console.ConsoleEngine;
import org.jline.console.Printer;
import org.jline.console.impl.JlineCommandRegistry;
import org.jline.keymap.KeyMap;
import org.jline.reader.*;
import org.jline.reader.LineReader.Option;
Expand Down Expand Up @@ -265,10 +259,19 @@ public static void main(String[] args) {
Thread executeThread = Thread.currentThread();
terminal.handle(Signal.INT, signal -> executeThread.interrupt());
//
// ScriptEngine and command registeries
// Create jnanorc config file for demo
//
File file = new File(Repl.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
String root = file.getCanonicalPath().replace("classes", "").replaceAll("\\\\", "/"); // forward slashes works better also in windows!
File jnanorcFile = Paths.get(root, "jnanorc").toFile();
if (!jnanorcFile.exists()) {
FileWriter fw = new FileWriter(jnanorcFile);
fw.write("include " + root + "nanorc/*.nanorc\n");
fw.close();
}
//
// ScriptEngine and command registries
//
GroovyEngine scriptEngine = new GroovyEngine();
scriptEngine.put("ROOT", root);
ConfigurationPath configPath = new ConfigurationPath(Paths.get(root), Paths.get(root));
Expand All @@ -286,10 +289,15 @@ public static void main(String[] args) {
//
// LineReader
//
Path jnanorc = configPath.getConfig("jnanorc");
SyntaxHighlighter commandHighlighter = SyntaxHighlighter.build(jnanorc,"COMMAND");
SyntaxHighlighter argsHighlighter = SyntaxHighlighter.build(jnanorc,"ARGS");
SyntaxHighlighter groovyHighlighter = SyntaxHighlighter.build(jnanorc,"Groovy");
LineReader reader = LineReaderBuilder.builder()
.terminal(terminal)
.completer(systemRegistry.completer())
.parser(parser)
.highlighter(new SystemHighlighter(commandHighlighter, argsHighlighter, groovyHighlighter))
.variable(LineReader.SECONDARY_PROMPT_PATTERN, "%M%P > ")
.variable(LineReader.INDENTATION, 2)
.variable(LineReader.LIST_MAX, 100)
Expand All @@ -303,7 +311,7 @@ public static void main(String[] args) {
reader.setVariable(LineReader.BLINK_MATCHING_PAREN, 0); // if enabled cursor remains in begin parenthesis (gitbash)
}
//
// complete command registeries
// complete command registries
//
consoleEngine.setLineReader(reader);
builtins.setLineReader(reader);
Expand Down
11 changes: 11 additions & 0 deletions demo/src/main/scripts/args.nanorc
@@ -0,0 +1,11 @@
syntax "ARGS"

color brightblue "\<[-]?[0-9]*([Ee][+-]?[0-9]+)?\>" "\<[-]?[0](\.[0-9]+)?\>"
color yellow ""(\\.|[^"])*"|'(\\.|[^'])*'|[a-zA-Z]+[a-zA-Z0-9]*"
color green "\<(console|grab|inspect)\>"
color cyan "\<null\>"
color brightcyan "\<(true|false)\>"
color brightyellow "\"(\\"|[^"])*\"\s*:" "'(\'|[^'])*'\s*:" "(\[|,)\s*[a-zA-Z0-9]*\s*:"
color white "(:|\[|,|\])"
color magenta "\\u[0-9a-fA-F]{4}|\\[bfnrt'"/\\]"
color ,red " + +| + +"
5 changes: 5 additions & 0 deletions demo/src/main/scripts/command.nanorc
@@ -0,0 +1,5 @@
syntax "COMMAND"

color green "[a-zA-Z]+[a-zA-Z0-9]*"
color yellow ".*="
color white "(\"|'|\.|=|:|\[|,|\])"
17 changes: 17 additions & 0 deletions demo/src/main/scripts/groovy.nanorc
@@ -0,0 +1,17 @@
## Here is an example for Groovy.
##
syntax "Groovy" "\.groovy$"
color green "\<(boolean|byte|char|double|float|int|long|new|short|this|transient|void|def|it)\>"
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,,faint "\<(print|println|sleep)\>"
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)"
6 changes: 0 additions & 6 deletions demo/src/main/scripts/init.jline
Expand Up @@ -6,12 +6,6 @@ import java.util.regex.*
import org.jline.utils.*

PATH = [ROOT + 'scripts']

#
# create jnanorc configuration file
#
_jnanorc = Paths.get(ROOT, 'jnanorc').toFile()
_jnanorc << 'include ' + ROOT + 'nanorc/*.nanorc\n' > null
#
# console options
#
Expand Down

0 comments on commit ca381ee

Please sign in to comment.