diff --git a/console/src/main/java/org/jline/console/SystemRegistry.java b/console/src/main/java/org/jline/console/SystemRegistry.java
index 95611419a..c79382a09 100644
--- a/console/src/main/java/org/jline/console/SystemRegistry.java
+++ b/console/src/main/java/org/jline/console/SystemRegistry.java
@@ -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);
@@ -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.
diff --git a/console/src/main/java/org/jline/console/impl/SystemHighlighter.java b/console/src/main/java/org/jline/console/impl/SystemHighlighter.java
new file mode 100644
index 000000000..c925a1393
--- /dev/null
+++ b/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 Matti Rinta-Nikkola
+ */
+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);
+ }
+ }
+}
diff --git a/console/src/main/java/org/jline/console/impl/SystemRegistryImpl.java b/console/src/main/java/org/jline/console/impl/SystemRegistryImpl.java
index 9415aa05e..924b659c1 100644
--- a/console/src/main/java/org/jline/console/impl/SystemRegistryImpl.java
+++ b/console/src/main/java/org/jline/console/impl/SystemRegistryImpl.java
@@ -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;
}
diff --git a/demo/src/main/java/org/jline/demo/Repl.java b/demo/src/main/java/org/jline/demo/Repl.java
index cecada8d4..8d8927366 100644
--- a/demo/src/main/java/org/jline/demo/Repl.java
+++ b/demo/src/main/java/org/jline/demo/Repl.java
@@ -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;
@@ -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;
@@ -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));
@@ -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)
@@ -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);
diff --git a/demo/src/main/scripts/args.nanorc b/demo/src/main/scripts/args.nanorc
new file mode 100644
index 000000000..e94e6c5b5
--- /dev/null
+++ b/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 "\"
+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 " + +| + +"
\ No newline at end of file
diff --git a/demo/src/main/scripts/command.nanorc b/demo/src/main/scripts/command.nanorc
new file mode 100644
index 000000000..2f48d612b
--- /dev/null
+++ b/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 "(\"|'|\.|=|:|\[|,|\])"
diff --git a/demo/src/main/scripts/groovy.nanorc b/demo/src/main/scripts/groovy.nanorc
new file mode 100644
index 000000000..175942388
--- /dev/null
+++ b/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)"
diff --git a/demo/src/main/scripts/init.jline b/demo/src/main/scripts/init.jline
index 52de82a1c..34866ca27 100644
--- a/demo/src/main/scripts/init.jline
+++ b/demo/src/main/scripts/init.jline
@@ -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
#