From 5f2497dd059c19fa928e9cd728f72ab870e8e2ce Mon Sep 17 00:00:00 2001 From: mattirn Date: Sun, 25 Apr 2021 21:32:24 +0200 Subject: [PATCH] SystemHighlighter: highlight command options file values --- .../jline/console/impl/SystemHighlighter.java | 120 +++++++++++++++--- demo/src/main/java/org/jline/demo/Repl.java | 1 + 2 files changed, 105 insertions(+), 16 deletions(-) diff --git a/console/src/main/java/org/jline/console/impl/SystemHighlighter.java b/console/src/main/java/org/jline/console/impl/SystemHighlighter.java index d342a550b..c391006fc 100644 --- a/console/src/main/java/org/jline/console/impl/SystemHighlighter.java +++ b/console/src/main/java/org/jline/console/impl/SystemHighlighter.java @@ -37,7 +37,7 @@ public class SystemHighlighter extends DefaultHighlighter { protected final SyntaxHighlighter argsHighlighter; protected final SyntaxHighlighter langHighlighter; protected final SystemRegistry systemRegistry; - protected final Set fileHighlight = new HashSet<>(); + protected final Map fileHighlight = new HashMap<>(); public SystemHighlighter(SyntaxHighlighter commandHighlighter, SyntaxHighlighter argsHighlighter , SyntaxHighlighter langHighlighter) { @@ -53,7 +53,13 @@ public AttributedString highlight(LineReader reader, String buffer) { } public void addFileHighlight(String... commands) { - fileHighlight.addAll(Arrays.asList(commands)); + for (String c : commands) { + fileHighlight.put(c, new FileHighlightCommand()); + } + } + + public void addFileHighlight(String command, String subcommand, Collection fileOptions) { + fileHighlight.put(command, new FileHighlightCommand(subcommand, fileOptions)); } private boolean doDefaultHighlight(LineReader reader) { @@ -65,11 +71,16 @@ private boolean doDefaultHighlight(LineReader reader) { protected AttributedString systemHighlight(LineReader reader, String buffer) { AttributedString out; Parser parser = reader.getParser(); - String command = parser.getCommand(buffer.trim().split("\\s+")[0]); + String command = parser.getCommand(buffer); if (buffer.trim().isEmpty()) { out = new AttributedStringBuilder().append(buffer).toAttributedString(); - } else if (fileHighlight.contains(command)) { - out = doFileHighlight(reader, buffer); + } else if (fileHighlight.containsKey(command)) { + FileHighlightCommand fhc = fileHighlight.get(command); + if (!fhc.hasFileOptions()) { + out = doFileArgsHighlight(reader, buffer, fhc); + } else { + out = doFileOptsHighlight(reader, buffer, fhc); + } } else if (systemRegistry.isCommandOrScript(command) || systemRegistry.isCommandAlias(command)) { out = doCommandHighlight(buffer); } else if (langHighlighter != null) { @@ -80,23 +91,70 @@ protected AttributedString systemHighlight(LineReader reader, String buffer) { return out; } - protected AttributedString doFileHighlight(LineReader reader, String buffer) { - int idx = commandIndex(buffer); + protected AttributedString doFileOptsHighlight(LineReader reader, String buffer, FileHighlightCommand fhc) { + int idx0 = commandIndex(buffer); AttributedStringBuilder asb = new AttributedStringBuilder(); - if (idx < 0) { + if (idx0 < 0) { highlightCommand(buffer, asb); } else { - highlightCommand(buffer.substring(0, idx), asb); + highlightCommand(buffer.substring(0, idx0), asb); ParsedLine parsedLine = reader.getParser().parse(buffer, buffer.length() + 1, Parser.ParseContext.COMPLETE); List words = parsedLine.words(); - idx = words.get(0).length(); - for (int i = 1; i < words.size(); i++) { - int nextIdx = buffer.substring(idx).indexOf(words.get(i)) + idx; - for (int j = idx; j < nextIdx; j++) { - asb.append(buffer.charAt(j)); + if (!fhc.isSubcommand() || (words.size() > 2 && fhc.getSubcommand().equals(words.get(1)))) { + int firstArg = fhc.isSubcommand() ? 1 : 0; + int idx = buffer.indexOf(words.get(firstArg)) + words.get(firstArg).length() + 1; + highlightArgs(buffer.substring(idx0, idx), asb); + boolean fileOption = false; + for (int i = firstArg + 1; i < words.size(); i++) { + int nextIdx = buffer.substring(idx).indexOf(words.get(i)) + idx; + for (int j = idx; j < nextIdx; j++) { + asb.append(buffer.charAt(j)); + } + String word = words.get(i); + if (word.contains("=") && fhc.getFileOptions().contains(word.substring(0, word.indexOf("=")))) { + highlightArgs(word.substring(0, word.indexOf("=") + 1), asb); + highlightFileArg(reader, word.substring(word.indexOf("=") + 1), asb); + } else if (fhc.getFileOptions().contains(word)) { + highlightArgs(word, asb); + fileOption = true; + } else if (fileOption) { + highlightFileArg(reader, word, asb); + } else { + highlightArgs(word, asb); + fileOption = false; + } + idx = nextIdx + word.length(); } - highlightFileArg(reader, words.get(i), asb); - idx = nextIdx + words.get(i).length(); + } else { + highlightArgs(buffer.substring(idx0), asb); + } + } + return asb.toAttributedString(); + } + + protected AttributedString doFileArgsHighlight(LineReader reader, String buffer, FileHighlightCommand fhc) { + int idx0 = commandIndex(buffer); + AttributedStringBuilder asb = new AttributedStringBuilder(); + if (idx0 < 0) { + highlightCommand(buffer, asb); + } else { + highlightCommand(buffer.substring(0, idx0), asb); + ParsedLine parsedLine = reader.getParser().parse(buffer, buffer.length() + 1, Parser.ParseContext.COMPLETE); + List words = parsedLine.words(); + if (!fhc.isSubcommand() || (words.size() > 2 && fhc.getSubcommand().equals(words.get(1)))) { + int firstArg = fhc.isSubcommand() ? 1 : 0; + int idx = buffer.indexOf(words.get(firstArg)) + words.get(firstArg).length(); + highlightArgs(buffer.substring(idx0, idx), asb); + for (int i = firstArg + 1; i < words.size(); i++) { + int nextIdx = buffer.substring(idx).indexOf(words.get(i)) + idx; + for (int j = idx; j < nextIdx; j++) { + asb.append(buffer.charAt(j)); + } + highlightFileArg(reader, words.get(i), asb); + idx = nextIdx + words.get(i).length(); + } + } else { + highlightArgs(buffer.substring(idx0), asb); } } return asb.toAttributedString(); @@ -211,4 +269,34 @@ private void highlightCommand(String command, AttributedStringBuilder asb) { asb.append(command); } } + + protected static class FileHighlightCommand { + private final String subcommand; + private final List fileOptions = new ArrayList<>(); + + public FileHighlightCommand() { + this(null, new ArrayList<>()); + } + + public FileHighlightCommand(String subcommand, Collection fileOptions) { + this.subcommand = subcommand; + this.fileOptions.addAll(fileOptions); + } + + public boolean isSubcommand() { + return subcommand != null; + } + + public boolean hasFileOptions() { + return !fileOptions.isEmpty(); + } + + public String getSubcommand() { + return subcommand; + } + + public List getFileOptions() { + return fileOptions; + } + } } diff --git a/demo/src/main/java/org/jline/demo/Repl.java b/demo/src/main/java/org/jline/demo/Repl.java index 087805982..0c6e37522 100644 --- a/demo/src/main/java/org/jline/demo/Repl.java +++ b/demo/src/main/java/org/jline/demo/Repl.java @@ -290,6 +290,7 @@ public static void main(String[] args) { SyntaxHighlighter groovyHighlighter = SyntaxHighlighter.build(jnanorc,"Groovy"); SystemHighlighter highlighter = new SystemHighlighter(commandHighlighter, argsHighlighter, groovyHighlighter); highlighter.addFileHighlight("nano", "less", "slurp"); + highlighter.addFileHighlight("groovy", "classloader", Arrays.asList("-a", "--add")); LineReader reader = LineReaderBuilder.builder() .terminal(terminal) .completer(systemRegistry.completer())