This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new e7834f937b Remove duplicated `SystemRegistryImpl` already included in
jline
e7834f937b is described below
commit e7834f937b18666f48dce6bf0ac316e5df902b1f
Author: Daniel Sun <[email protected]>
AuthorDate: Tue May 5 00:32:18 2026 +0900
Remove duplicated `SystemRegistryImpl` already included in jline
---
.../groovysh/jline/GroovySystemRegistry.groovy | 1 +
.../groovy/groovysh/jline/SystemRegistryImpl.java | 2536 --------------------
2 files changed, 1 insertion(+), 2536 deletions(-)
diff --git
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovySystemRegistry.groovy
b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovySystemRegistry.groovy
index b36f05737e..f636a6c80d 100644
---
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovySystemRegistry.groovy
+++
b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovySystemRegistry.groovy
@@ -19,6 +19,7 @@
package org.apache.groovy.groovysh.jline
import org.jline.builtins.ConfigurationPath
+import org.jline.console.impl.SystemRegistryImpl
import org.jline.reader.Parser
import org.jline.terminal.Terminal
diff --git
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/SystemRegistryImpl.java
b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/SystemRegistryImpl.java
deleted file mode 100644
index f05cb65785..0000000000
---
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/SystemRegistryImpl.java
+++ /dev/null
@@ -1,2536 +0,0 @@
-/*
- * Copyright (c) 2002-2025, the original author(s).
- *
- * 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.apache.groovy.groovysh.jline;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-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;
-
-import org.jline.builtins.Completers.FilesCompleter;
-import org.jline.builtins.Completers.OptDesc;
-import org.jline.builtins.Completers.OptionCompleter;
-import org.jline.builtins.ConfigurationPath;
-import org.jline.builtins.Options;
-import org.jline.builtins.Options.HelpException;
-import org.jline.builtins.Styles;
-import org.jline.console.*;
-import org.jline.console.impl.Builtins;
-import org.jline.console.impl.ConsoleEngineImpl;
-import org.jline.console.impl.JlineCommandRegistry;
-import org.jline.reader.*;
-import org.jline.reader.Parser.ParseContext;
-import org.jline.reader.impl.completer.AggregateCompleter;
-import org.jline.reader.impl.completer.ArgumentCompleter;
-import org.jline.reader.impl.completer.NullCompleter;
-import org.jline.reader.impl.completer.StringsCompleter;
-import org.jline.reader.impl.completer.SystemCompleter;
-import org.jline.terminal.Terminal;
-import org.jline.utils.*;
-
-/**
- * Aggregate command registries.
- */
-@SuppressWarnings("deprecation")
-public class SystemRegistryImpl implements SystemRegistry {
- // TODO NOTE: This file can be deleted if the following PRs are merged:
- // https://github.com/jline/jline3/pull/1392
- // https://github.com/jline/jline3/pull/1394
-
- /**
- * Pipe operators used to connect commands in a pipeline.
- */
- public enum Pipe {
- /** Sequential execution, next command runs regardless of previous
result */
- FLIP,
- /** Named pipe */
- NAMED,
- /** Logical AND, next command runs only if previous succeeds */
- AND,
- /** Logical OR, next command runs only if previous fails */
- OR,
- /** Output redirection to file */
- REDIRECT,
- /** Output redirection to file with append */
- APPEND,
- /** Pipe to external process */
- PIPE
- }
-
- private static final Class<?>[] BUILTIN_REGISTRIES = {Builtins.class,
ConsoleEngineImpl.class};
- private CommandRegistry[] commandRegistries;
- private Integer consoleId;
- /** The parser used for command line parsing */
- protected final Parser parser;
- /** Configuration path for storing user-specific settings */
- protected final ConfigurationPath configPath;
- /** Supplier for the working directory */
- protected final Supplier<Path> workDir;
- private final Map<String, CommandRegistry> subcommands = new HashMap<>();
- private final Map<Pipe, String> pipeName = new HashMap<>();
- private final Map<String, CommandMethods> commandExecute = new HashMap<>();
- private final Map<String, List<String>> commandInfos = new HashMap<>();
- private Exception exception;
- private final CommandOutputStream outputStream;
- private ScriptStore scriptStore = new ScriptStore();
- private NamesAndValues names = new NamesAndValues();
- private final SystemCompleter customSystemCompleter = new
SystemCompleter();
- private final AggregateCompleter customAggregateCompleter = new
AggregateCompleter(new ArrayList<>());
- private boolean commandGroups = true;
- private Function<CmdLine, CmdDesc> scriptDescription;
-
- /**
- * Constructs a new SystemRegistryImpl.
- *
- * @param parser the parser for command line parsing
- * @param terminal the terminal to use for input/output
- * @param workDir supplier for the working directory
- * @param configPath configuration path for user-specific settings
- */
- @SuppressWarnings("this-escape")
- public SystemRegistryImpl(Parser parser, Terminal terminal, Supplier<Path>
workDir, ConfigurationPath configPath) {
- this.parser = parser;
- this.workDir = workDir;
- this.configPath = configPath;
- outputStream = new CommandOutputStream(terminal);
- pipeName.put(Pipe.FLIP, "|;");
- pipeName.put(Pipe.NAMED, "|");
- pipeName.put(Pipe.AND, "&&");
- pipeName.put(Pipe.OR, "||");
- pipeName.put(Pipe.PIPE, "|!");
- pipeName.put(Pipe.REDIRECT, ">");
- pipeName.put(Pipe.APPEND, ">>");
- commandExecute.put("exit", new CommandMethods(this::exit,
this::exitCompleter));
- commandExecute.put("help", new CommandMethods(this::help,
this::helpCompleter));
- }
-
- /**
- * Renames a pipe operator.
- *
- * @param pipe the pipe to rename
- * @param name the new name
- * @throws IllegalArgumentException if the name is invalid or already in
use
- */
- public void rename(Pipe pipe, String name) {
- if (name.matches("/w+") || pipeName.containsValue(name)) {
- throw new IllegalArgumentException();
- }
- pipeName.put(pipe, name);
- }
-
- /**
- * Renames a local command.
- *
- * @param command the command to rename
- * @param newName the new name for the command
- */
- public void renameLocal(String command, String newName) {
- CommandMethods old = commandExecute.remove(command);
- if (old != null) {
- commandExecute.put(newName, old);
- }
- }
-
- /**
- * Returns the names of all pipe operators.
- *
- * @return collection of pipe names
- */
- @Override
- public Collection<String> getPipeNames() {
- return pipeName.values();
- }
-
- /**
- * Sets the command registries managed by this system registry.
- *
- * @param commandRegistries the command registries to set
- */
- @Override
- public void setCommandRegistries(CommandRegistry... commandRegistries) {
- this.commandRegistries = commandRegistries;
- for (int i = 0; i < commandRegistries.length; i++) {
- if (commandRegistries[i] instanceof ConsoleEngine) {
- if (consoleId != null) {
- throw new IllegalArgumentException();
- } else {
- this.consoleId = i;
- ((ConsoleEngine)
commandRegistries[i]).setSystemRegistry(this);
- this.scriptStore = new ScriptStore((ConsoleEngine)
commandRegistries[i]);
- this.names = new NamesAndValues(configPath);
- }
- } else if (commandRegistries[i] instanceof SystemRegistry) {
- throw new IllegalArgumentException();
- }
- }
- SystemRegistry.add(this);
- }
-
- /**
- * Initializes the system by executing a startup script.
- *
- * @param script the script file to execute
- */
- @Override
- public void initialize(File script) {
- if (consoleId != null) {
- try {
- consoleEngine().execute(script);
- } catch (Exception e) {
- trace(e);
- }
- }
- }
-
- /**
- * Returns the names of all registered commands.
- *
- * @return set of command names
- */
- @Override
- public Set<String> commandNames() {
- Set<String> out = new HashSet<>();
- for (CommandRegistry r : commandRegistries) {
- out.addAll(r.commandNames());
- }
- out.addAll(localCommandNames());
- return out;
- }
-
- private Set<String> localCommandNames() {
- return commandExecute.keySet();
- }
-
- /**
- * Returns all command aliases.
- *
- * @return map of aliases to command names
- */
- @Override
- public Map<String, String> commandAliases() {
- Map<String, String> out = new HashMap<>();
- for (CommandRegistry r : commandRegistries) {
- out.putAll(r.commandAliases());
- }
- return out;
- }
-
- /**
- * Retrieves a console option value.
- *
- * @param name the option name
- * @return the option value, or {@code null} if not found
- */
- @Override
- public Object consoleOption(String name) {
- return consoleOption(name, null);
- }
-
- /**
- * Retrieves a console option value with a default.
- *
- * @param <T> the option value type
- * @param name the option name
- * @param defVal the default value
- * @return the option value, or the default if not found
- */
- @Override
- public <T> T consoleOption(String name, T defVal) {
- T out = defVal;
- if (consoleId != null) {
- out = consoleEngine().consoleOption(name, defVal);
- }
- return out;
- }
-
- /**
- * Sets a console option value.
- *
- * @param name the option name
- * @param value the option value
- */
- @Override
- public void setConsoleOption(String name, Object value) {
- if (consoleId != null) {
- consoleEngine().setConsoleOption(name, value);
- }
- }
-
- /**
- * Register subcommand registry
- * @param command main command
- * @param subcommandRegistry subcommand registry
- */
- @Override
- public void register(String command, CommandRegistry subcommandRegistry) {
- subcommands.put(command, subcommandRegistry);
- commandExecute.put(command, new CommandMethods(this::subcommand,
this::emptyCompleter));
- }
-
- private List<String> localCommandInfo(String command) {
- try {
- CommandRegistry subCommand = subcommands.get(command);
- if (subCommand != null) {
- registryHelp(subCommand);
- } else {
- localExecute(command, new String[] {"--help"});
- }
- } catch (HelpException e) {
- exception = null;
- return JlineCommandRegistry.compileCommandInfo(e.getMessage());
- } catch (Exception e) {
- trace(e);
- }
- return new ArrayList<>();
- }
-
- /**
- * Returns the help information for a command.
- *
- * @param command the command name
- * @return list of help text lines
- */
- @Override
- public List<String> commandInfo(String command) {
- int id = registryId(command);
- List<String> out = new ArrayList<>();
- if (id > -1) {
- if (!commandInfos.containsKey(command)) {
- commandInfos.put(command,
commandRegistries[id].commandInfo(command));
- }
- out = commandInfos.get(command);
- } else if (scriptStore.hasScript(command) && consoleEngine() != null) {
- out = consoleEngine().commandInfo(command);
- } else if (isLocalCommand(command)) {
- out = localCommandInfo(command);
- }
- return out;
- }
-
- /**
- * Checks if a command exists.
- *
- * @param command the command name
- * @return {@code true} if the command exists, {@code false} otherwise
- */
- @Override
- public boolean hasCommand(String command) {
- return registryId(command) > -1 || isLocalCommand(command);
- }
-
- /**
- * Sets whether commands should be grouped by registry in help output.
- *
- * @param commandGroups true to group commands, false otherwise
- */
- public void setGroupCommandsInHelp(boolean commandGroups) {
- this.commandGroups = commandGroups;
- }
-
- /**
- * Sets whether commands should be grouped by registry in help output.
- *
- * @param commandGroups true to group commands, false otherwise
- * @return this instance for method chaining
- */
- public SystemRegistryImpl groupCommandsInHelp(boolean commandGroups) {
- this.commandGroups = commandGroups;
- return this;
- }
-
- private boolean isLocalCommand(String command) {
- return commandExecute.containsKey(command);
- }
-
- /**
- * Checks if the parsed line represents a command or script.
- *
- * @param line the parsed line to check
- * @return {@code true} if the line is a command or script, {@code false}
otherwise
- */
- @Override
- public boolean isCommandOrScript(ParsedLine line) {
- return isCommandOrScript(parser.getCommand(line.words().get(0)));
- }
-
- /**
- * Checks if the given string represents a command or script.
- *
- * @param command the command name to check
- * @return {@code true} if the command or script exists, {@code false}
otherwise
- */
- @Override
- public boolean isCommandOrScript(String command) {
- if (hasCommand(command)) {
- return true;
- }
- return scriptStore.hasScript(command);
- }
-
- /**
- * Adds a completer to the registry.
- *
- * @param completer the completer to add
- */
- public void addCompleter(Completer completer) {
- if (completer instanceof SystemCompleter sc) {
- if (sc.isCompiled()) {
- customAggregateCompleter.getCompleters().add(sc);
- } else {
- customSystemCompleter.add(sc);
- }
- } else {
- customAggregateCompleter.getCompleters().add(completer);
- }
- }
-
- /**
- * Compiles all registered completers into a system completer.
- *
- * @return the system completer
- * @throws IllegalStateException always; use {@link #completer()} instead
- */
- @Override
- public SystemCompleter compileCompleters() {
- throw new IllegalStateException("Use method completer() to retrieve
Completer!");
- }
-
- private SystemCompleter _compileCompleters() {
- SystemCompleter out =
CommandRegistry.aggregateCompleters(commandRegistries);
- SystemCompleter local = new SystemCompleter();
- for (String command : commandExecute.keySet()) {
- CommandRegistry subCommand = subcommands.get(command);
- if (subCommand != null) {
- for (Entry<String, List<Completer>> entry :
-
subCommand.compileCompleters().getCompleters().entrySet()) {
- for (Completer cc : entry.getValue()) {
- if (!(cc instanceof ArgumentCompleter)) {
- throw new IllegalArgumentException();
- }
- List<Completer> cmps = ((ArgumentCompleter)
cc).getCompleters();
- cmps.add(0, NullCompleter.INSTANCE);
- cmps.set(1, new StringsCompleter(entry.getKey()));
- Completer last = cmps.get(cmps.size() - 1);
- if (last instanceof OptionCompleter) {
- ((OptionCompleter) last).setStartPos(cmps.size() -
1);
- cmps.set(cmps.size() - 1, last);
- }
- local.add(command, new ArgumentCompleter(cmps));
- }
- }
- } else {
- local.add(
- command,
commandExecute.get(command).compileCompleter().apply(command));
- }
- }
- local.add(customSystemCompleter);
- out.add(local);
- out.compile(s -> CommandRegistry.createCandidate(commandRegistries,
s));
- return out;
- }
-
- /**
- * Returns the completer for all registered commands and scripts.
- *
- * @return the completer instance
- */
- @Override
- public Completer completer() {
- List<Completer> completers = new ArrayList<>();
- completers.add(_compileCompleters());
- completers.add(customAggregateCompleter);
- if (consoleId != null) {
- completers.addAll(consoleEngine().scriptCompleters());
- completers.add(new PipelineCompleter(workDir, pipeName,
names).doCompleter());
- }
- return new AggregateCompleter(completers);
- }
-
- private CmdDesc localCommandDescription(String command) {
- if (!isLocalCommand(command)) {
- throw new IllegalArgumentException();
- }
- try {
- localExecute(command, new String[] {"--help"});
- } catch (HelpException e) {
- exception = null;
- return
JlineCommandRegistry.compileCommandDescription(e.getMessage());
- } catch (Exception e) {
- trace(e);
- }
- return null;
- }
-
- /**
- * Returns the description for a command given its arguments.
- *
- * @param args the command arguments
- * @return the command description
- */
- @Override
- public CmdDesc commandDescription(List<String> args) {
- CmdDesc out = new CmdDesc(false);
- String command = args.get(0);
- int id = registryId(command);
- if (id > -1) {
- out = commandRegistries[id].commandDescription(args);
- } else if (scriptStore.hasScript(command) && consoleEngine() != null) {
- out = consoleEngine().commandDescription(args);
- } else if (isLocalCommand(command)) {
- out = localCommandDescription(command);
- }
- return out;
- }
-
- private CmdDesc commandDescription(CommandRegistry subreg) {
- List<AttributedString> main = new ArrayList<>();
- Map<String, List<AttributedString>> options = new HashMap<>();
- StyleResolver helpStyle = Styles.helpStyle();
- for (String sc : new TreeSet<>(subreg.commandNames())) {
- for (String info : subreg.commandInfo(sc)) {
- main.add(HelpException.highlightSyntax(sc + " - " + info,
helpStyle, true));
- break;
- }
- }
- return new CmdDesc(main,
ArgDesc.doArgNames(Collections.singletonList("")), options);
- }
-
- /**
- * Sets the function used to describe scripts for tab completion.
- *
- * @param scriptDescription the script description function
- */
- public void setScriptDescription(Function<CmdLine, CmdDesc>
scriptDescription) {
- this.scriptDescription = scriptDescription;
- }
-
- /**
- * Returns the description for a command line.
- *
- * @param line the command line
- * @return the command description
- */
- @Override
- public CmdDesc commandDescription(CmdLine line) {
- CmdDesc out = null;
- String cmd = parser.getCommand(line.getArgs().get(0));
- switch (line.getDescriptionType()) {
- case COMMAND:
- if (isCommandOrScript(cmd) && !names.hasPipes(line.getArgs()))
{
- List<String> args = line.getArgs();
- CommandRegistry subCommand = subcommands.get(cmd);
- if (subCommand != null) {
- String c = args.size() > 1 ? args.get(1) : null;
- if (c == null || subCommand.hasCommand(c)) {
- if (c != null && c.equals("help")) {
- out = null;
- } else if (c != null) {
- out =
subCommand.commandDescription(Collections.singletonList(c));
- } else {
- out = commandDescription(subCommand);
- }
- } else {
- out = commandDescription(subCommand);
- }
- if (out != null) {
- out.setSubcommand(true);
- }
- } else {
- args.set(0, cmd);
- out = commandDescription(args);
- }
- }
- break;
- case METHOD:
- case SYNTAX:
- if (!isCommandOrScript(cmd) && scriptDescription != null) {
- out = scriptDescription.apply(line);
- }
- break;
- }
- return out;
- }
-
- /**
- * Invokes a command with the given arguments.
- *
- * @param command the command name
- * @param args the command arguments
- * @return the result of command execution
- * @throws Exception if command execution fails
- */
- @Override
- public Object invoke(String command, Object... args) throws Exception {
- Object out = null;
- command = ConsoleEngine.plainCommand(command);
- args = args == null ? new Object[] {null} : args;
- int id = registryId(command);
- if (id > -1) {
- out = commandRegistries[id].invoke(commandSession(), command,
args);
- } else if (isLocalCommand(command)) {
- out = localExecute(command, args);
- } else if (consoleId != null) {
- out = consoleEngine().invoke(commandSession(), command, args);
- }
- return out;
- }
-
- private Object localExecute(String command, Object[] args) throws
Exception {
- if (!isLocalCommand(command)) {
- throw new IllegalArgumentException();
- }
- Object out = commandExecute.get(command).execute().apply(new
CommandInput(command, args, commandSession()));
- if (exception != null) {
- throw exception;
- }
- return out;
- }
-
- /**
- * Returns the terminal associated with this registry.
- *
- * @return the terminal
- */
- public Terminal terminal() {
- return commandSession().terminal();
- }
-
- private CommandSession commandSession() {
- return outputStream.getCommandSession();
- }
-
- private static class CommandOutputStream {
- private final PrintStream origOut;
- private final PrintStream origErr;
- private final Terminal origTerminal;
- private OutputStream outputStream;
- private Terminal terminal;
- private String output;
- private CommandSession commandSession;
- private boolean redirecting = false;
-
- /**
- * Constructs a new CommandOutputStream.
- *
- * @param terminal the terminal to use
- */
- public CommandOutputStream(Terminal terminal) {
- this.origOut = System.out;
- this.origErr = System.err;
- this.origTerminal = terminal;
- this.terminal = terminal;
- PrintStream ps = new PrintStream(terminal.output());
- this.commandSession = new CommandSession(terminal,
terminal.input(), ps, ps);
- }
-
- /**
- * Redirects output to a byte array stream.
- */
- public void redirect() {
- outputStream = new ByteArrayOutputStream();
- }
-
- /**
- * Redirects output to a file.
- *
- * @param file the file to redirect output to
- * @param append whether to append to the file
- * @throws IOException if an I/O error occurs
- */
- public void redirect(File file, boolean append) throws IOException {
- if (!file.exists()) {
- try {
- file.createNewFile();
- } catch (IOException e) {
- (new File(file.getParent())).mkdirs();
- file.createNewFile();
- }
- }
- outputStream = new FileOutputStream(file, append);
- }
-
- /**
- * Opens the redirected output stream.
- *
- * @param redirectColor whether to redirect color output
- * @throws IOException if an I/O error occurs
- */
- public void open(boolean redirectColor) throws IOException {
- if (redirecting || outputStream == null) {
- return;
- }
- output = null;
- PrintStream out = new PrintStream(outputStream);
- System.setOut(out);
- System.setErr(out);
-
- // Use simple streams instead of creating a PTY terminal to avoid
hangs on macOS
- // Create a command session that uses the original terminal for
input but redirected streams for output
- this.commandSession = new CommandSession(origTerminal,
origTerminal.input(), out, out);
- redirecting = true;
- }
-
- /**
- * Closes the redirected output stream and restores original streams.
- */
- public void close() {
- if (!redirecting) {
- return;
- }
- try {
- // Flush the original terminal since we're using it for input
- origTerminal.flush();
- if (outputStream instanceof ByteArrayOutputStream) {
- output = outputStream.toString();
- }
- // No need to close a separate terminal since we're reusing
the original one
- } catch (Exception e) {
- // ignore
- }
- reset();
- }
-
- /**
- * Resets the captured output.
- */
- public void resetOutput() {
- output = null;
- }
-
- private void reset() {
- outputStream = null;
- System.setOut(origOut);
- System.setErr(origErr);
- terminal = origTerminal;
- PrintStream ps = new PrintStream(terminal.output());
- this.commandSession = new CommandSession(terminal,
terminal.input(), ps, ps);
- redirecting = false;
- }
-
- /**
- * Returns the current command session.
- *
- * @return the command session
- */
- public CommandSession getCommandSession() {
- return commandSession;
- }
-
- /**
- * Returns the captured output.
- *
- * @return the captured output, or null if no output was captured
- */
- public String getOutput() {
- return output;
- }
-
- /**
- * Returns whether output is currently being redirected.
- *
- * @return true if redirecting, false otherwise
- */
- public boolean isRedirecting() {
- return redirecting;
- }
-
- /**
- * Returns whether the output stream is a byte array output stream.
- *
- * @return true if byte array output stream, false otherwise
- */
- public boolean isByteOutputStream() {
- return outputStream instanceof ByteArrayOutputStream;
- }
- }
-
- /**
- * Checks if the command is an alias.
- *
- * @param command the command name
- * @return {@code true} if the command is an alias, {@code false} otherwise
- */
- @Override
- public boolean isCommandAlias(String command) {
- if (consoleEngine() == null) {
- return false;
- }
- ConsoleEngine consoleEngine = consoleEngine();
- if (!parser.validCommandName(command) ||
!consoleEngine.hasAlias(command)) {
- return false;
- }
- String value = consoleEngine.getAlias(command).split("\\s+")[0];
- return !names.isPipe(value);
- }
-
- private String replaceCommandAlias(String variable, String command, String
rawLine) {
- ConsoleEngine consoleEngine = consoleEngine();
- assert consoleEngine != null;
- return variable == null
- ? rawLine.replaceFirst(command + "(\\b|$)",
consoleEngine.getAlias(command))
- : rawLine.replaceFirst("=" + command + "(\\b|$)", "=" +
consoleEngine.getAlias(command));
- }
-
- private String replacePipeAlias(
- ArgsParser ap, String pipeAlias, List<String> args, Map<String,
List<String>> customPipes) {
- ConsoleEngine consoleEngine = consoleEngine();
- assert consoleEngine != null;
- String alias = pipeAlias;
- for (int j = 0; j < args.size(); j++) {
- alias = alias.replaceAll("\\s\\$" + j + "\\b", " " + args.get(j));
- alias = alias.replaceAll("\\$\\{" + j + "(|:-.*)}", args.get(j));
- }
- alias = alias.replaceAll("\\$\\{@}", consoleEngine.expandToList(args));
- alias = alias.replaceAll("\\$@", consoleEngine.expandToList(args));
- alias = alias.replaceAll("\\s+\\$\\d\\b", "");
- alias = alias.replaceAll("\\s+\\$\\{\\d+}", "");
- alias = alias.replaceAll("\\$\\{\\d+}", "");
- Matcher matcher = Pattern.compile("\\$\\{\\d+:-(.*?)}").matcher(alias);
- if (matcher.find()) {
- alias = matcher.replaceAll("$1");
- }
- ap.parse(alias);
- List<String> ws = ap.args();
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < ws.size(); i++) {
- if (ws.get(i).equals(pipeName.get(Pipe.NAMED))) {
- if (i + 1 < ws.size() && consoleEngine.hasAlias(ws.get(i +
1))) {
- args.clear();
- String innerPipe = consoleEngine.getAlias(ws.get(++i));
- while (i < ws.size() - 1 && !names.isPipe(ws.get(i + 1),
customPipes.keySet())) {
- args.add(ws.get(++i));
- }
- sb.append(replacePipeAlias(ap, innerPipe, args,
customPipes));
- } else {
- sb.append(ws.get(i)).append(' ');
- }
- } else {
- sb.append(ws.get(i)).append(' ');
- }
- }
- return sb.toString();
- }
-
- private void replacePipeAliases(ConsoleEngine consoleEngine, Map<String,
List<String>> customPipes, ArgsParser ap) {
- List<String> words = ap.args();
- if (consoleEngine != null && words.contains(pipeName.get(Pipe.NAMED)))
{
- StringBuilder sb = new StringBuilder();
- boolean trace = false;
- for (int i = 0; i < words.size(); i++) {
- if (words.get(i).equals(pipeName.get(Pipe.NAMED))) {
- if (i + 1 < words.size() &&
consoleEngine.hasAlias(words.get(i + 1))) {
- trace = true;
- List<String> args = new ArrayList<>();
- String pipeAlias =
consoleEngine.getAlias(words.get(++i));
- while (i < words.size() - 1 &&
!names.isPipe(words.get(i + 1), customPipes.keySet())) {
- args.add(words.get(++i));
- }
- sb.append(replacePipeAlias(ap, pipeAlias, args,
customPipes));
- } else {
- sb.append(words.get(i)).append(' ');
- }
- } else {
- sb.append(words.get(i)).append(' ');
- }
- }
- ap.parse(sb.toString());
- if (trace) {
- consoleEngine.trace(ap.line());
- }
- }
- }
-
- private List<CommandData> compileCommandLine(String commandLine) {
- List<CommandData> out = new ArrayList<>();
- ArgsParser ap = new ArgsParser(parser);
- ap.parse(commandLine);
- ConsoleEngine consoleEngine = consoleEngine();
- Map<String, List<String>> customPipes = consoleEngine != null ?
consoleEngine.getPipes() : new HashMap<>();
- replacePipeAliases(consoleEngine, customPipes, ap);
- List<String> words = ap.args();
- String nextRawLine = ap.line();
- int first = 0;
- int last;
- List<String> pipes = new ArrayList<>();
- String pipeSource = null;
- StringBuilder rawLine = null;
- String pipeResult = null;
- if (isCommandAlias(ap.command())) {
- ap.parse(replaceCommandAlias(ap.variable(), ap.command(),
nextRawLine));
- replacePipeAliases(consoleEngine, customPipes, ap);
- nextRawLine = ap.line();
- words = ap.args();
- }
- if (!names.hasPipes(words)) {
- out.add(new CommandData(ap, false, nextRawLine, ap.variable(),
null, false, ""));
- } else {
- //
- // compile pipe line
- //
- do {
- String rawCommand = parser.getCommand(words.get(first));
- String command = ConsoleEngine.plainCommand(rawCommand);
- String variable = parser.getVariable(words.get(first));
- if (isCommandAlias(command)) {
- ap.parse(replaceCommandAlias(variable, command,
nextRawLine));
- replacePipeAliases(consoleEngine, customPipes, ap);
- rawCommand = ap.rawCommand();
- command = ap.command();
- words = ap.args();
- first = 0;
- }
- if (scriptStore.isConsoleScript(command) &&
!rawCommand.startsWith(":")) {
- throw new IllegalArgumentException("Commands must be used
in pipes with colon prefix!");
- }
- last = words.size();
- File file = null;
- boolean append = false;
- boolean pipeStart = false;
- boolean skipPipe = false;
- List<String> _words = new ArrayList<>();
- //
- // find next pipe
- //
- for (int i = first; i < last; i++) {
- if (words.get(i).equals(pipeName.get(Pipe.REDIRECT))
- || words.get(i).equals(pipeName.get(Pipe.APPEND)))
{
- pipes.add(words.get(i));
- append =
words.get(i).equals(pipeName.get(Pipe.APPEND));
- if (i + 1 >= last) {
- throw new IllegalArgumentException();
- }
- file = redirectFile(words.get(i + 1));
- last = i + 1;
- break;
- } else if (consoleId == null) {
- _words.add(words.get(i));
- } else if (words.get(i).equals(pipeName.get(Pipe.FLIP))) {
- if (variable != null || file != null || pipeResult !=
null || consoleId == null) {
- throw new IllegalArgumentException();
- }
- pipes.add(words.get(i));
- last = i;
- variable = "_pipe" + (pipes.size() - 1);
- break;
- } else if (words.get(i).equals(pipeName.get(Pipe.NAMED))
- || (words.get(i).matches("^.*[^a-zA-Z0-9 ].*$") &&
customPipes.containsKey(words.get(i)))) {
- String pipe = words.get(i);
- if (pipe.equals(pipeName.get(Pipe.NAMED))) {
- if (i + 1 >= last) {
- throw new IllegalArgumentException("Pipe is
NULL!");
- }
- pipe = words.get(i + 1);
- if (!pipe.matches("\\w+") ||
!customPipes.containsKey(pipe)) {
- if (!consoleOption("ignoreUnknownPipes",
false)) {
- throw new
IllegalArgumentException("Unknown or illegal pipe name: " + pipe);
- }
- }
- }
- pipes.add(pipe);
- last = i;
- if (pipeSource == null) {
- pipeSource = "_pipe" + (pipes.size() - 1);
- pipeResult = variable;
- variable = pipeSource;
- pipeStart = true;
- }
- break;
- } else if (words.get(i).equals(pipeName.get(Pipe.OR))
- || words.get(i).equals(pipeName.get(Pipe.AND))||
words.get(i).equals(pipeName.get(Pipe.PIPE))) {
- if (variable != null || pipeSource != null) {
- pipes.add(words.get(i));
- } else if (pipes.size() > 0
- && (pipes.get(pipes.size() -
1).equals(pipeName.get(Pipe.REDIRECT))
- || pipes.get(pipes.size() -
1).equals(pipeName.get(Pipe.APPEND)))) {
- pipes.remove(pipes.size() - 1);
- out.get(out.size() - 1).setPipe(words.get(i));
- skipPipe = true;
- } else {
- pipes.add(words.get(i));
- pipeSource = "_pipe" + (pipes.size() - 1);
- pipeResult = variable;
- variable = pipeSource;
- pipeStart = true;
- }
- last = i;
- break;
- } else {
- _words.add(words.get(i));
- }
- }
- if (last == words.size()) {
- pipes.add("END_PIPE");
- } else if (skipPipe) {
- first = last + 1;
- continue;
- }
- //
- // compose pipe command
- //
- String subLine = last < words.size() || first > 0 ?
String.join(" ", _words) : ap.line();
- if (last + 1 < words.size()) {
- nextRawLine = String.join(" ", words.subList(last + 1,
words.size()));
- }
- boolean done = true;
- boolean statement = false;
- List<String> arglist = new ArrayList<>();
- if (!_words.isEmpty()) {
- arglist.addAll(_words.subList(1, _words.size()));
- }
- if (rawLine != null || (pipes.size() > 1 &&
customPipes.containsKey(pipes.get(pipes.size() - 2)))) {
- done = false;
- if (rawLine == null) {
- rawLine = new StringBuilder(pipeSource);
- }
- if (customPipes.containsKey(pipes.get(pipes.size() - 2))) {
- List<String> fixes =
customPipes.get(pipes.get(pipes.size() - 2));
- if (pipes.get(pipes.size() - 2).matches("\\w+")) {
- int idx = subLine.indexOf(" ");
- subLine = idx > 0 ? subLine.substring(idx + 1) :
"";
- }
- rawLine.append(fixes.get(0)).append(consoleId != null
? consoleEngine().expandCommandLine(subLine) : subLine).append(fixes.get(1));
- statement = true;
- }
- if (pipes.get(pipes.size() -
1).equals(pipeName.get(Pipe.FLIP))
- || pipes.get(pipes.size() -
1).equals(pipeName.get(Pipe.AND))
- || pipes.get(pipes.size() -
1).equals(pipeName.get(Pipe.OR))) {
- done = true;
- pipeSource = null;
- if (variable != null) {
- rawLine.insert(0, variable + " = ");
- }
- }
- if (last + 1 >= words.size() || file != null) {
- done = true;
- pipeSource = null;
- if (pipeResult != null) {
- rawLine.insert(0, pipeResult + " = ");
- }
- }
- } else if (pipes.get(pipes.size() -
1).equals(pipeName.get(Pipe.FLIP)) || pipeStart) {
- if (pipeStart && pipeResult != null) {
- subLine = subLine.substring(subLine.indexOf("=") + 1);
- }
- rawLine = new StringBuilder(flipArgument(command, subLine,
pipes, arglist));
- rawLine.insert(0, variable + "=");
- } else {
- rawLine = new StringBuilder(flipArgument(command, subLine,
pipes, arglist));
- }
- if (done) {
- //
- // add composed command to return list
- //
- out.add(new CommandData(
- ap, statement, rawLine.toString(), variable, file,
append, pipes.get(pipes.size() - 1)));
- if (pipes.get(pipes.size() -
1).equals(pipeName.get(Pipe.AND))
- || pipes.get(pipes.size() -
1).equals(pipeName.get(Pipe.OR))) {
- pipeSource = null;
- pipeResult = null;
- }
- rawLine = null;
- }
- first = last + 1;
- } while (first < words.size());
- }
- return out;
- }
-
- private File redirectFile(String name) {
- File out;
- if (name.equals("null")) {
- out = OSUtils.IS_WINDOWS ? new File("NUL") : new File("/dev/null");
- } else {
- out = new File(name);
- }
- return out;
- }
-
- /**
- * Parses command arguments and handles quote and bracket matching.
- */
- private static class ArgsParser {
- private int round = 0;
- private int curly = 0;
- private int square = 0;
- private boolean quoted;
- private boolean doubleQuoted;
- private String line;
- private String command = "";
- private String variable = "";
- private List<String> args;
- private final Parser parser;
-
- /**
- * Constructs a new ArgsParser.
- *
- * @param parser the parser to use
- */
- public ArgsParser(Parser parser) {
- this.parser = parser;
- }
-
- private void reset() {
- round = 0;
- curly = 0;
- square = 0;
- quoted = false;
- doubleQuoted = false;
- }
-
- private void next(String arg) {
- char prevChar = ' ';
- for (int i = 0; i < arg.length(); i++) {
- char c = arg.charAt(i);
- if (!parser.isEscapeChar(prevChar)) {
- if (!quoted && !doubleQuoted) {
- if (c == '(') {
- round++;
- } else if (c == ')') {
- round--;
- } else if (c == '{') {
- curly++;
- } else if (c == '}') {
- curly--;
- } else if (c == '[') {
- square++;
- } else if (c == ']') {
- square--;
- } else if (c == '"') {
- doubleQuoted = true;
- } else if (c == '\'') {
- quoted = true;
- }
- } else if (quoted && c == '\'') {
- quoted = false;
- } else if (doubleQuoted && c == '"') {
- doubleQuoted = false;
- }
- }
- prevChar = c;
- }
- }
-
- private boolean isEnclosed() {
- return round == 0 && curly == 0 && square == 0 && !quoted &&
!doubleQuoted;
- }
-
- /**
- * Checks whether the supplied fragment has balanced quotes and
brackets.
- *
- * @param arg fragment to inspect
- * @return {@code true} when the fragment is syntactically enclosed
- */
- public boolean isEnclosed(String arg) {
- reset();
- next(arg);
- return isEnclosed();
- }
-
- private void enclosedArgs(List<String> words) {
- args = new ArrayList<>();
- reset();
- boolean first = true;
- StringBuilder sb = new StringBuilder();
- for (String a : words) {
- next(a);
- if (!first) {
- sb.append(" ");
- }
- if (isEnclosed()) {
- sb.append(a);
- args.add(sb.toString());
- sb = new StringBuilder();
- first = true;
- } else {
- sb.append(a);
- first = false;
- }
- }
- if (!first) {
- args.add(sb.toString());
- }
- }
-
- /**
- * Parses a command line into arguments.
- *
- * @param line the command line to parse
- */
- public void parse(String line) {
- this.line = line;
- ParsedLine pl = parser.parse(line, 0, ParseContext.SPLIT_LINE);
- enclosedArgs(pl.words());
- if (!args.isEmpty()) {
- this.command = parser.getCommand(args.get(0));
- if (!parser.validCommandName(command)) {
- this.command = "";
- }
- this.variable = parser.getVariable(args.get(0));
- } else {
- this.line = "";
- }
- }
-
- /**
- * Returns the parsed command line.
- *
- * @return the command line
- */
- public String line() {
- return line;
- }
-
- /**
- * Returns the parsed command name.
- *
- * @return the command name
- */
- public String command() {
- return ConsoleEngine.plainCommand(command);
- }
-
- /**
- * Returns the raw command name (before processing).
- *
- * @return the raw command name
- */
- public String rawCommand() {
- return command;
- }
-
- /**
- * Returns the parsed variable name, if any.
- *
- * @return the variable name, or null
- */
- public String variable() {
- return variable;
- }
-
- /**
- * Returns the parsed arguments.
- *
- * @return the list of arguments
- */
- public List<String> args() {
- return args;
- }
-
- private int closingQuote(String arg) {
- int out = -1;
- char prevChar = ' ';
- for (int i = 1; i < arg.length(); i++) {
- char c = arg.charAt(i);
- if (!parser.isEscapeChar(prevChar)) {
- if (c == arg.charAt(0)) {
- out = i;
- break;
- }
- }
- prevChar = c;
- }
- return out;
- }
-
- private String unquote(String arg) {
- if (arg.length() > 1 && (arg.startsWith("\"") &&
arg.endsWith("\""))
- || (arg.startsWith("'") && arg.endsWith("'"))) {
- if (closingQuote(arg) == arg.length() - 1) {
- return arg.substring(1, arg.length() - 1);
- }
- }
- return arg;
- }
-
- /**
- * Unescapes a string that contains standard Java escape sequences.
- * <ul>
- * <li><strong>\b \f \n \r \t \"
\'</strong> :
- * BS, FF, NL, CR, TAB, double and single quote.</li>
- * <li><strong>\X \XX \XXX</strong> : Octal character
- * specification (0 - 377, 0x00 - 0xFF).</li>
- * <li><strong>\uXXXX</strong> : Hexadecimal based Unicode
character.</li>
- * </ul>
- *
- * @param arg
- * A string optionally containing standard java escape
sequences.
- * @return The translated string.
- *
- * Based on code by Udo Klimaschewski,
https://gist.github.com/uklimaschewski/6741769
- */
- private String unescape(String arg) {
- if (arg == null || !parser.isEscapeChar('\\')) {
- return arg;
- }
- StringBuilder sb = new StringBuilder(arg.length());
- for (int i = 0; i < arg.length(); i++) {
- char ch = arg.charAt(i);
- if (ch == '\\') {
- char nextChar = (i == arg.length() - 1) ? '\\' :
arg.charAt(i + 1);
- // Octal escape?
- if (nextChar >= '0' && nextChar <= '7') {
- String code = "" + nextChar;
- i++;
- if ((i < arg.length() - 1) && arg.charAt(i + 1) >= '0'
&& arg.charAt(i + 1) <= '7') {
- code += arg.charAt(i + 1);
- i++;
- if ((i < arg.length() - 1) && arg.charAt(i + 1) >=
'0' && arg.charAt(i + 1) <= '7') {
- code += arg.charAt(i + 1);
- i++;
- }
- }
- sb.append((char) Integer.parseInt(code, 8));
- continue;
- }
- switch (nextChar) {
- case '\\':
- ch = '\\';
- break;
- case 'b':
- ch = '\b';
- break;
- case 'f':
- ch = '\f';
- break;
- case 'n':
- ch = '\n';
- break;
- case 'r':
- ch = '\r';
- break;
- case 't':
- ch = '\t';
- break;
- case '\"':
- ch = '\"';
- break;
- case '\'':
- ch = '\'';
- break;
- case ' ':
- ch = ' ';
- break;
- // Hex Unicode: u????
- case 'u':
- if (i >= arg.length() - 5) {
- ch = 'u';
- break;
- }
- int code = Integer.parseInt(
- "" + arg.charAt(i + 2) + arg.charAt(i + 3)
+ arg.charAt(i + 4) + arg.charAt(i + 5),
- 16);
- sb.append(Character.toChars(code));
- i += 5;
- continue;
- }
- i++;
- }
- sb.append(ch);
- }
- return sb.toString();
- }
- }
-
- private String flipArgument(
- final String command, final String subLine, final List<String>
pipes, List<String> arglist) {
- String out;
- if (pipes.size() > 1 && pipes.get(pipes.size() -
2).equals(pipeName.get(Pipe.FLIP))) {
- String s = isCommandOrScript(command) ? "$" : "";
- out = subLine + " " + s + "_pipe" + (pipes.size() - 2);
- if (!command.isEmpty()) {
- arglist.add(s + "_pipe" + (pipes.size() - 2));
- }
- } else {
- out = subLine;
- }
- return out;
- }
-
- /**
- * Holds parsed command data for pipeline execution.
- */
- protected static class CommandData {
- private final String rawLine;
- private String command;
- private String[] args;
- private final File file;
- private final boolean append;
- private final String variable;
- private String pipe;
-
- /**
- * Creates a compiled command entry for later execution in a pipeline.
- *
- * @param parser parser used to derive command metadata
- * @param statement whether the raw line should be treated as a script
statement
- * @param rawLine raw command or statement text
- * @param variable target variable for captured output
- * @param file redirect target, when present
- * @param append whether redirected output should be appended
- * @param pipe pipe operator that follows this command
- */
- public CommandData(
- ArgsParser parser,
- boolean statement,
- String rawLine,
- String variable,
- File file,
- boolean append,
- String pipe) {
- this.rawLine = rawLine;
- this.variable = variable;
- this.file = file;
- this.append = append;
- this.pipe = pipe;
- this.args = new String[] {};
- this.command = "";
- if (!statement) {
- parser.parse(rawLine);
- this.command = parser.command();
- if (parser.args().size() > 1) {
- this.args = new String[parser.args().size() - 1];
- for (int i = 1; i < parser.args().size(); i++) {
- args[i - 1] =
-
parser.unescape(parser.unquote(parser.args().get(i)));
- }
- }
- }
- }
-
- /**
- * Sets the pipe operator for this command.
- *
- * @param pipe the pipe operator
- */
- public void setPipe(String pipe) {
- this.pipe = pipe;
- }
-
- /**
- * Returns the redirect target file.
- *
- * @return the file, or null if no redirection
- */
- public File file() {
- return file;
- }
-
- /**
- * Returns whether output should be appended to the file.
- *
- * @return true if append mode, false otherwise
- */
- public boolean append() {
- return append;
- }
-
- /**
- * Returns the variable name for output capture.
- *
- * @return the variable name, or null
- */
- public String variable() {
- return variable;
- }
-
- /**
- * Returns the command name.
- *
- * @return the command name
- */
- public String command() {
- return command;
- }
-
- /**
- * Returns the command arguments.
- *
- * @return the arguments array
- */
- public String[] args() {
- return args;
- }
-
- /**
- * Returns the raw command line.
- *
- * @return the raw command line
- */
- public String rawLine() {
- return rawLine;
- }
-
- /**
- * Returns the pipe operator.
- *
- * @return the pipe operator
- */
- public String pipe() {
- return pipe;
- }
-
- /**
- * Returns a string representation of this command line.
- *
- * @return string representation
- */
- @Override
- public String toString() {
- return "[" + "rawLine:"
- + rawLine + ", " + "command:"
- + command + ", " + "args:"
- + Arrays.asList(args) + ", " + "variable:"
- + variable + ", " + "file:"
- + file + ", " + "append:"
- + append + ", " + "pipe:"
- + pipe + "]";
- }
- }
-
- /**
- * Caches available scripts from the console engine.
- */
- private static class ScriptStore {
- ConsoleEngine engine;
- Map<String, Boolean> scripts = new HashMap<>();
-
- /**
- * Constructs a new ScriptStore with no engine.
- */
- public ScriptStore() {}
-
- /**
- * Constructs a new ScriptStore.
- *
- * @param engine the console engine
- */
- public ScriptStore(ConsoleEngine engine) {
- this.engine = engine;
- }
-
- /**
- * Refreshes the script cache from the engine.
- */
- public void refresh() {
- if (engine != null) {
- scripts = engine.scripts();
- }
- }
-
- /**
- * Checks if a script exists.
- *
- * @param name the script name
- * @return true if the script exists
- */
- public boolean hasScript(String name) {
- return scripts.containsKey(name);
- }
-
- /**
- * Checks if a script is a console script.
- *
- * @param name the script name
- * @return true if it is a console script
- */
- public boolean isConsoleScript(String name) {
- return scripts.getOrDefault(name, false);
- }
-
- /**
- * Returns all available scripts.
- *
- * @return the set of script names
- */
- public Set<String> getScripts() {
- return scripts.keySet();
- }
- }
-
- /**
- * Exception thrown when a command is not recognized.
- */
- @SuppressWarnings("serial")
- public static class UnknownCommandException extends Exception {
- /**
- * Constructs a new UnknownCommandException.
- *
- * @param message the error message
- */
- public UnknownCommandException(String message) {
- super(message);
- }
- }
-
- private Object execute(String command, String rawLine, String[] args)
throws Exception {
- if (!parser.validCommandName(command)) {
- throw new UnknownCommandException("Invalid command: " + rawLine);
- }
- Object out;
- int id = registryId(command);
- if (id > -1) {
- Object[] _args = consoleId != null ?
consoleEngine().expandParameters(args) : args;
- out =
commandRegistries[id].invoke(outputStream.getCommandSession(), command, _args);
- } else if (scriptStore.hasScript(command) && consoleEngine() != null) {
- out = consoleEngine().execute(command, rawLine, args);
- } else if (isLocalCommand(command)) {
- out = localExecute(command, consoleId != null ?
consoleEngine().expandParameters(args) : args);
- } else {
- throw new UnknownCommandException("Unknown command: " + command);
- }
- return out;
- }
-
- /**
- * Executes a command line, including pipes, redirection, and console
statements.
- *
- * @param line command line to execute
- * @return command result, if any
- * @throws Exception if command execution fails
- */
- @Override
- public Object execute(String line) throws Exception {
- if (line.trim().isEmpty() || line.trim().startsWith("#")) {
- return null;
- }
- long start = new Date().getTime();
- Object out = null;
- boolean statement = false;
- boolean postProcessed = false;
- int errorCount = 0;
- scriptStore.refresh();
- List<CommandData> cmds = compileCommandLine(line);
- ConsoleEngine consoleEngine = consoleEngine();
- for (CommandData cmd : cmds) {
- if (cmd.file() != null &&
scriptStore.isConsoleScript(cmd.command())) {
- throw new IllegalArgumentException("Console script output
cannot be redirected!");
- }
- try {
- outputStream.close();
- if (consoleEngine != null && !consoleEngine.isExecuting()) {
- trace(cmd);
- }
- exception = null;
- statement = false;
- postProcessed = false;
- if (cmd.variable() != null || cmd.file() != null) {
- if (cmd.file() != null) {
- outputStream.redirect(cmd.file(), cmd.append());
- } else if (consoleId != null) {
- outputStream.redirect();
- }
- outputStream.open(consoleOption("redirectColor", false));
- }
- boolean consoleScript = false;
- try {
- out = execute(cmd.command(), cmd.rawLine(), cmd.args());
- } catch (UnknownCommandException e) {
- if (consoleEngine == null) {
- throw e;
- }
- consoleScript = true;
- }
- if (consoleEngine != null) {
- if (consoleScript) {
- statement = cmd.command().isEmpty() ||
!scriptStore.hasScript(cmd.command());
- if (statement && outputStream.isByteOutputStream()) {
- outputStream.close();
- }
- out = consoleEngine.execute(cmd.command(),
cmd.rawLine(), cmd.args());
- }
- if (cmd.pipe().equals(pipeName.get(Pipe.OR)) ||
cmd.pipe().equals(pipeName.get(Pipe.AND)) ||
cmd.pipe().equals(pipeName.get(Pipe.PIPE))) {
- if (cmd.pipe().equals(pipeName.get(Pipe.PIPE)) && out
== null) {
- out = outputStream.output;
- }
- ConsoleEngine.ExecutionResult er = postProcess(cmd,
statement, consoleEngine, out);
- postProcessed = true;
- consoleEngine.println(er.result());
- out = null;
- boolean success = er.status() == 0;
- if ((cmd.pipe().equals(pipeName.get(Pipe.OR)) &&
success)
- || (cmd.pipe().equals(pipeName.get(Pipe.AND))
&& !success)) {
- break;
- }
- }
- }
- } catch (HelpException e) {
- trace(e);
- } catch (Exception e) {
- errorCount++;
- if (cmd.pipe().equals(pipeName.get(Pipe.OR))) {
- trace(e);
- postProcessed = true;
- } else {
- throw e;
- }
- } finally {
- if (!postProcessed && consoleEngine != null) {
- out = postProcess(cmd, statement, consoleEngine,
out).result();
- }
- }
- }
- if (errorCount == 0) {
- names.extractNames(line);
- }
- Log.debug("execute: ", new Date().getTime() - start, " msec");
- return out;
- }
-
- private ConsoleEngine.ExecutionResult postProcess(
- CommandData cmd, boolean statement, ConsoleEngine consoleEngine,
Object result) {
- ConsoleEngine.ExecutionResult out;
- if (cmd.file() != null) {
- int status = 1;
- if (cmd.file().exists()) {
- long delta = new Date().getTime() - cmd.file().lastModified();
- status = delta < 100 ? 0 : 1;
- }
- out = new ConsoleEngine.ExecutionResult(status, result);
- } else if (!statement) {
- outputStream.close();
- out = consoleEngine.postProcess(cmd.rawLine(), result,
outputStream.getOutput());
- } else if (cmd.variable() != null) {
- if (consoleEngine.hasVariable(cmd.variable())) {
- out =
consoleEngine.postProcess(consoleEngine.getVariable(cmd.variable()));
- } else {
- out = consoleEngine.postProcess(result);
- }
- out = new ConsoleEngine.ExecutionResult(out.status(), null);
- } else {
- out = consoleEngine.postProcess(result);
- }
- return out;
- }
-
- /**
- * Cleans up output streams and purges temporary data.
- */
- public void cleanUp() {
- outputStream.close();
- outputStream.resetOutput();
- if (consoleEngine() != null) {
- consoleEngine().purge();
- }
- }
-
- private void trace(CommandData commandData) {
- if (consoleEngine() != null) {
- consoleEngine().trace(commandData);
- } else {
- AttributedStringBuilder asb = new AttributedStringBuilder();
- asb.append(commandData.rawLine(),
AttributedStyle.DEFAULT.foreground(AttributedStyle.YELLOW))
- .println(terminal());
- }
- }
-
- /**
- * Reports an exception using the configured console-aware tracing
strategy.
- *
- * @param exception exception to report
- */
- @Override
- public void trace(Throwable exception) {
- outputStream.close();
- ConsoleEngine consoleEngine = consoleEngine();
- if (consoleEngine != null) {
- if (!(exception instanceof HelpException)) {
- consoleEngine.putVariable("exception", exception);
- }
- consoleEngine.trace(exception);
- } else {
- trace(false, exception);
- }
- }
-
- /**
- * Reports an exception, optionally printing its full stack trace.
- *
- * @param stack whether to print the full stack trace
- * @param exception exception to report
- */
- @Override
- public void trace(boolean stack, Throwable exception) {
- if (exception instanceof HelpException) {
- HelpException.highlight((exception).getMessage(),
Styles.helpStyle())
- .print(terminal());
- } else if (exception instanceof UnknownCommandException) {
- AttributedStringBuilder asb = new AttributedStringBuilder();
- asb.append(exception.getMessage(),
Styles.prntStyle().resolve(".em"));
- asb.toAttributedString().println(terminal());
- } else if (stack) {
- exception.printStackTrace();
- } else {
- String message = exception.getMessage();
- AttributedStringBuilder asb = new AttributedStringBuilder();
- asb.style(Styles.prntStyle().resolve(".em"));
- if (message != null) {
- asb.append(exception.getClass().getSimpleName()).append(":
").append(message);
- } else {
- asb.append("Caught exception: ");
- asb.append(exception.getClass().getCanonicalName());
- }
- asb.toAttributedString().println(terminal());
- Log.debug("Stack: ", exception);
- }
- }
-
- /**
- * Persists collected command names before shutdown.
- */
- @Override
- public void close() {
- names.save();
- }
-
- /**
- * Returns the console engine, if available.
- *
- * @return the console engine, or null if not configured
- */
- public ConsoleEngine consoleEngine() {
- return consoleId != null ? (ConsoleEngine)
commandRegistries[consoleId] : null;
- }
-
- private boolean isBuiltinRegistry(CommandRegistry registry) {
- for (Class<?> c : BUILTIN_REGISTRIES) {
- if (c == registry.getClass()) {
- return true;
- }
- }
- return false;
- }
-
- private void printHeader(String header) {
- AttributedStringBuilder asb = new AttributedStringBuilder().tabs(2);
- asb.append("\t");
- asb.append(header, HelpException.defaultStyle().resolve(".ti"));
- asb.append(":");
- asb.toAttributedString().println(terminal());
- }
-
- private void printCommandInfo(String command, String info, int max) {
- AttributedStringBuilder asb = new
AttributedStringBuilder().tabs(Arrays.asList(4, max + 4));
- asb.append("\t");
- asb.append(command, HelpException.defaultStyle().resolve(".co"));
- asb.append("\t");
- asb.append(info, HelpException.defaultStyle().resolve(".de"));
- asb.setLength(terminal().getWidth());
- asb.toAttributedString().println(terminal());
- }
-
- private void printCommands(Collection<String> commands, int max) {
- AttributedStringBuilder asb = new
AttributedStringBuilder().tabs(Arrays.asList(4, max + 4));
- int col = 0;
- asb.append("\t");
- col += 4;
- boolean done = false;
- for (String c : commands) {
- asb.append(c, HelpException.defaultStyle().resolve(".co"));
- asb.append("\t");
- col += max;
- if (col + max > terminal().getWidth()) {
- asb.toAttributedString().println(terminal());
- asb = new AttributedStringBuilder().tabs(Arrays.asList(4, max
+ 4));
- col = 0;
- asb.append("\t");
- col += 4;
- done = true;
- } else {
- done = false;
- }
- }
- if (!done) {
- asb.toAttributedString().println(terminal());
- }
- terminal().flush();
- }
-
- private String doCommandInfo(List<String> info) {
- return info != null && !info.isEmpty() ? info.get(0) : " ";
- }
-
- private boolean isInTopics(List<String> args, String name) {
- return args.isEmpty() || args.contains(name);
- }
-
- private Options parseOptions(String[] usage, Object[] args) throws
HelpException {
- Options opt = Options.compile(usage).parse(args);
- if (opt.isSet("help")) {
- throw new HelpException(opt.usage());
- }
- return opt;
- }
-
- private Object help(CommandInput input) {
- String groupsOption = commandGroups ? "nogroups" : "groups";
- String groupsHelp = commandGroups
- ? " --nogroups Commands are not grouped
by registries"
- : " --groups Commands are grouped by
registries";
- final String[] usage = {
- "help - command help",
- "Usage: help [TOPIC...]",
- " -? --help Displays command help",
- groupsHelp,
- " -i --info List commands with a short
command info"
- };
- try {
- Options opt = parseOptions(usage, input.args());
- boolean doTopic = false;
- boolean cg = commandGroups;
- boolean info = false;
- if (!opt.args().isEmpty() && opt.args().size() == 1) {
- try {
- String[] args = {"--help"};
- String command = opt.args().get(0);
- execute(command, command + " " + args[0], args);
- } catch (UnknownCommandException e) {
- doTopic = true;
- } catch (Exception e) {
- exception = e;
- }
- } else {
- doTopic = true;
- if (opt.isSet(groupsOption)) {
- cg = !cg;
- }
- if (opt.isSet("info")) {
- info = true;
- }
- }
- if (doTopic) {
- helpTopic(opt.args(), cg, info);
- }
- } catch (Exception e) {
- exception = e;
- }
- return null;
- }
-
- private void helpTopic(List<String> topics, boolean commandGroups, boolean
info) {
- Set<String> commands = commandNames();
- commands.addAll(scriptStore.getScripts());
- boolean withInfo = commands.size() < terminal().getHeight() ||
!topics.isEmpty() || info;
- int max =
- Collections.max(commands,
Comparator.comparing(String::length)).length() + 1;
- TreeMap<String, String> builtinCommands = new TreeMap<>();
- TreeMap<String, String> systemCommands = new TreeMap<>();
- if (!commandGroups && topics.isEmpty()) {
- TreeSet<String> ordered = new TreeSet<>(commands);
- if (withInfo) {
- for (String c : ordered) {
- List<String> infos = commandInfo(c);
- String cmdInfo = infos.isEmpty() ? "" : infos.get(0);
- printCommandInfo(c, cmdInfo, max);
- }
- } else {
- printCommands(ordered, max);
- }
- } else {
- for (CommandRegistry r : commandRegistries) {
- if (isBuiltinRegistry(r)) {
- for (String c : r.commandNames()) {
- builtinCommands.put(c, doCommandInfo(commandInfo(c)));
- }
- }
- }
- for (String c : localCommandNames()) {
- systemCommands.put(c, doCommandInfo(commandInfo(c)));
- exception = null;
- }
- if (isInTopics(topics, "System")) {
- printHeader("System");
- if (withInfo) {
- for (Entry<String, String> entry :
systemCommands.entrySet()) {
- printCommandInfo(entry.getKey(), entry.getValue(),
max);
- }
- } else {
- printCommands(systemCommands.keySet(), max);
- }
- }
- if (isInTopics(topics, "Builtins") && !builtinCommands.isEmpty()) {
- printHeader("Builtins");
- if (withInfo) {
- for (Entry<String, String> entry :
builtinCommands.entrySet()) {
- printCommandInfo(entry.getKey(), entry.getValue(),
max);
- }
- } else {
- printCommands(builtinCommands.keySet(), max);
- }
- }
- for (CommandRegistry r : commandRegistries) {
- if (isBuiltinRegistry(r)
- || !isInTopics(topics, r.name())
- || r.commandNames().isEmpty()) {
- continue;
- }
- TreeSet<String> cmds = new TreeSet<>(r.commandNames());
- printHeader(r.name());
- if (withInfo) {
- for (String c : cmds) {
- printCommandInfo(c, doCommandInfo(commandInfo(c)),
max);
- }
- } else {
- printCommands(cmds, max);
- }
- }
- if (consoleId != null
- && isInTopics(topics, "Scripts")
- && !scriptStore.getScripts().isEmpty()) {
- printHeader("Scripts");
- if (withInfo) {
- for (String c : scriptStore.getScripts()) {
- printCommandInfo(c, doCommandInfo(commandInfo(c)),
max);
- }
- } else {
- printCommands(scriptStore.getScripts(), max);
- }
- }
- }
- terminal().flush();
- }
-
- private Object exit(CommandInput input) {
- final String[] usage = {
- "exit - exit from app/script",
- "Usage: exit [OBJECT]",
- " -? --help Displays command help"
- };
- try {
- Options opt = parseOptions(usage, input.xargs());
- ConsoleEngine consoleEngine = consoleEngine();
- if (!opt.argObjects().isEmpty() && consoleEngine != null) {
- try {
- consoleEngine.putVariable(
- "_return",
- opt.argObjects().size() == 1 ?
opt.argObjects().get(0) : opt.argObjects());
- } catch (Exception e) {
- trace(e);
- }
- }
- exception = new EndOfFileException();
- } catch (Exception e) {
- exception = e;
- }
- return null;
- }
-
- private void registryHelp(CommandRegistry registry) throws Exception {
- List<Integer> tabs = new ArrayList<>();
- tabs.add(0);
- tabs.add(9);
- int max = registry.commandNames().stream()
- .map(String::length)
- .max(Integer::compareTo)
- .get();
- tabs.add(10 + max);
- AttributedStringBuilder sb = new AttributedStringBuilder().tabs(tabs);
- sb.append(" - ");
- sb.append(registry.name());
- sb.append(" registry");
- sb.append("\n");
- boolean first = true;
- for (String c : new TreeSet<>(registry.commandNames())) {
- if (first) {
- sb.append("Summary:");
- first = false;
- }
- sb.append("\t");
- sb.append(c);
- sb.append("\t");
- sb.append(registry.commandInfo(c).get(0));
- sb.append("\n");
- }
- throw new HelpException(sb.toString());
- }
-
- private Object subcommand(CommandInput input) {
- Object out = null;
- try {
- if (input.args().length > 0 &&
subcommands.get(input.command()).hasCommand(input.args()[0])) {
- out = subcommands
- .get(input.command())
- .invoke(
- input.session(),
- input.args()[0],
- input.xargs().length > 1
- ? Arrays.copyOfRange(input.xargs(), 1,
input.xargs().length)
- : new Object[] {});
- } else {
- registryHelp(subcommands.get(input.command()));
- }
- } catch (Exception e) {
- exception = e;
- }
- return out;
- }
-
- private List<OptDesc> commandOptions(String command) {
- try {
- localExecute(command, new String[] {"--help"});
- } catch (HelpException e) {
- exception = null;
- return JlineCommandRegistry.compileCommandOptions(e.getMessage());
- } catch (Exception e) {
- trace(e);
- }
- return null;
- }
-
- private List<String> registryNames() {
- List<String> out = new ArrayList<>();
- out.add("System");
- out.add("Builtins");
- if (consoleId != null) {
- out.add("Scripts");
- }
- for (CommandRegistry r : commandRegistries) {
- if (!isBuiltinRegistry(r)) {
- out.add(r.name());
- }
- }
- out.addAll(commandNames());
- out.addAll(scriptStore.getScripts());
- return out;
- }
-
- private List<Completer> emptyCompleter(String command) {
- return new ArrayList<>();
- }
-
- private List<Completer> helpCompleter(String command) {
- List<Completer> completers = new ArrayList<>();
- List<Completer> params = new ArrayList<>();
- params.add(new StringsCompleter(this::registryNames));
- params.add(NullCompleter.INSTANCE);
- completers.add(
- new ArgumentCompleter(NullCompleter.INSTANCE, new
OptionCompleter(params, this::commandOptions, 1)));
- return completers;
- }
-
- private List<Completer> exitCompleter(String command) {
- List<Completer> completers = new ArrayList<>();
- completers.add(new ArgumentCompleter(
- NullCompleter.INSTANCE, new
OptionCompleter(NullCompleter.INSTANCE, this::commandOptions, 1)));
- return completers;
- }
-
- private int registryId(String command) {
- for (int i = 0; i < commandRegistries.length; i++) {
- if (commandRegistries[i].hasCommand(command)) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Completer for pipeline commands and operators.
- */
- private static class PipelineCompleter implements Completer {
- private final NamesAndValues names;
- private final Supplier<Path> workDir;
- private final Map<Pipe, String> pipeName;
-
- /**
- * Constructs a new PipelineCompleter.
- *
- * @param workDir supplier for the working directory
- * @param pipeName map of pipe operators to their names
- * @param names names and values cache
- */
- public PipelineCompleter(Supplier<Path> workDir, Map<Pipe, String>
pipeName, NamesAndValues names) {
- this.workDir = workDir;
- this.pipeName = pipeName;
- this.names = names;
- }
-
- /**
- * Returns the completer wrapped in an ArgumentCompleter.
- *
- * @return the completer
- */
- public Completer doCompleter() {
- ArgumentCompleter out = new ArgumentCompleter(this);
- out.setStrict(false);
- return out;
- }
-
- /**
- * Provides completion candidates for pipeline commands.
- *
- * @param reader the line reader
- * @param commandLine the parsed command line
- * @param candidates the list to populate with candidates
- */
- @Override
- public void complete(LineReader reader, ParsedLine commandLine,
List<Candidate> candidates) {
- assert commandLine != null;
- assert candidates != null;
- ArgsParser ap = new ArgsParser(reader.getParser());
- ap.parse(commandLine.line().substring(0, commandLine.cursor()));
- List<String> args = ap.args();
- if (args.size() < 2 || !names.hasPipes(args)) {
- return;
- }
- boolean enclosed = ap.isEnclosed(args.get(args.size() - 1));
- String pWord = commandLine.words().get(commandLine.wordIndex() -
1);
- if (enclosed && pWord.equals(pipeName.get(Pipe.NAMED))) {
- for (String name : names.namedPipes()) {
- candidates.add(new Candidate(name, name, null, null, null,
null, true));
- }
- } else if (enclosed && pWord.equals(pipeName.get(Pipe.REDIRECT))
- || pWord.equals(pipeName.get(Pipe.APPEND))) {
- Completer c = new FilesCompleter(workDir);
- c.complete(reader, commandLine, candidates);
- } else {
- String buffer = commandLine.word().substring(0,
commandLine.wordCursor());
- String param = buffer;
- String curBuf = "";
- int lastDelim = names.indexOfLastDelim(buffer);
- if (lastDelim > -1) {
- param = buffer.substring(lastDelim + 1);
- curBuf = buffer.substring(0, lastDelim + 1);
- }
- if (curBuf.startsWith("--") && !curBuf.contains("=")) {
- doCandidates(candidates, names.options(), curBuf, "",
param);
- } else if (param.isEmpty()) {
- doCandidates(candidates, names.fieldsAndValues(), curBuf,
"", "");
- } else if (param.contains(".")) {
- int point = buffer.lastIndexOf(".");
- param = buffer.substring(point + 1);
- curBuf = buffer.substring(0, point + 1);
- doCandidates(candidates, names.fields(), curBuf, "",
param);
- } else if (names.encloseBy(param).length() == 1) {
- lastDelim++;
- String postFix = names.encloseBy(param);
- param = buffer.substring(lastDelim + 1);
- curBuf = buffer.substring(0, lastDelim + 1);
- doCandidates(candidates, names.quoted(), curBuf, postFix,
param);
- } else {
- doCandidates(candidates, names.fieldsAndValues(), curBuf,
"", param);
- }
- }
- }
-
- private void doCandidates(
- List<Candidate> candidates, Collection<String> fields, String
curBuf, String postFix, String hint) {
- if (fields == null) {
- return;
- }
- for (String s : fields) {
- if (s != null && s.startsWith(hint)) {
- candidates.add(new Candidate(
- AttributedString.stripAnsi(curBuf + s + postFix),
s, null, null, null, null, false));
- }
- }
- }
- }
-
- /**
- * Manages field, value, and option names for pipeline completion.
- */
- private class NamesAndValues {
- private final String[] delims = {
- "&", "\\|", "\\{", "\\}", "\\[", "\\]", "\\(", "\\)", "\\+", "-",
"\\*", "=", ">", "<", "~", "!", ":", ",",
- ";"
- };
-
- private Path fileNames;
- private final Map<String, List<String>> names = new HashMap<>();
- private List<String> namedPipes;
-
- /**
- * Constructs a new NamesAndValues with no config path.
- */
- public NamesAndValues() {
- this(null);
- }
-
- /**
- * Constructs a new NamesAndValues.
- *
- * @param configPath configuration path for loading saved names
- */
- @SuppressWarnings("unchecked")
- public NamesAndValues(ConfigurationPath configPath) {
- names.put("fields", new ArrayList<>());
- names.put("values", new ArrayList<>());
- names.put("quoted", new ArrayList<>());
- names.put("options", new ArrayList<>());
- ConsoleEngine consoleEngine = consoleEngine();
- if (configPath != null && consoleEngine != null) {
- try {
- fileNames =
configPath.getUserConfig("pipeline-names.json", true);
- Map<String, List<String>> temp = (Map<String,
List<String>>) consoleEngine.slurp(fileNames);
- for (Entry<String, List<String>> entry : temp.entrySet()) {
- names.get(entry.getKey()).addAll(entry.getValue());
- }
- } catch (Exception e) {
- // ignore
- }
- }
- }
-
- /**
- * Checks if an argument is a pipe operator.
- *
- * @param arg the argument to check
- * @return true if it is a pipe operator
- */
- public boolean isPipe(String arg) {
- Map<String, List<String>> customPipes =
- consoleEngine() != null ? consoleEngine().getPipes() : new
HashMap<>();
- return isPipe(arg, customPipes.keySet());
- }
-
- /**
- * Checks if any argument in the collection is a pipe operator.
- *
- * @param args the arguments to check
- * @return true if any argument is a pipe operator
- */
- public boolean hasPipes(Collection<String> args) {
- Map<String, List<String>> customPipes =
- consoleEngine() != null ? consoleEngine().getPipes() : new
HashMap<>();
- for (String a : args) {
- if (isPipe(a, customPipes.keySet())) {
- return true;
- }
- }
- return false;
- }
-
- private boolean isPipe(String arg, Set<String> pipes) {
- return pipeName.containsValue(arg) || pipes.contains(arg);
- }
-
- /**
- * Extracts field and value names from a command line for completion.
- *
- * @param line the command line to parse
- */
- public void extractNames(String line) {
- if (parser.getCommand(line).equals("pipe")) {
- return;
- }
- ArgsParser ap = new ArgsParser(parser);
- ap.parse(line);
- List<String> args = ap.args();
- int pipeId = 0;
- for (String a : args) {
- if (isPipe(a)) {
- break;
- }
- pipeId++;
- }
- if (pipeId < args.size()) {
- StringBuilder sb = new StringBuilder();
- int redirectPipe = -1;
- for (int i = pipeId + 1; i < args.size(); i++) {
- String arg = args.get(i);
- if (!isPipe(arg) && !namedPipes().contains(arg) &&
!arg.matches("\\d+") && redirectPipe != i - 1) {
- if (arg.matches("\\w+(\\(\\))?")) {
- addValues(arg);
- } else if (arg.matches("--\\w+(=.*|)$") &&
arg.length() > 4) {
- int idx = arg.indexOf('=');
- if (idx > 0) {
- if (idx > 4) {
- addOptions(arg.substring(2, idx));
- }
- sb.append(arg.substring(idx + 1));
- sb.append(" ");
- } else if (idx == -1) {
- addOptions(arg.substring(2));
- }
- } else {
- sb.append(arg);
- sb.append(" ");
- }
- } else if (arg.equals(pipeName.get(Pipe.REDIRECT)) ||
arg.equals(pipeName.get(Pipe.APPEND))) {
- redirectPipe = i;
- } else {
- redirectPipe = -1;
- }
- }
- if (sb.length() > 0) {
- String rest = sb.toString();
- for (String d : delims) {
- rest = rest.replaceAll(d, " ");
- }
- String[] words = rest.split("\\s+");
- for (String w : words) {
- if (w.length() < 3 || w.matches("\\d+")) {
- continue;
- }
- if (isQuoted(w)) {
- addQuoted(w.substring(1, w.length() - 1));
- } else if (w.contains(".")) {
- for (String f : w.split("\\.")) {
- if (!f.matches("\\d+") && f.matches("\\w+")) {
- addFields(f);
- }
- }
- } else if (w.matches("\\w+")) {
- addValues(w);
- }
- }
- }
- }
- namedPipes = null;
- }
-
- /**
- * Returns the quote/delimiter character that encloses a parameter, if
any.
- *
- * @param param the parameter to check
- * @return the enclosing character, or empty string if not enclosed
- */
- public String encloseBy(String param) {
- boolean quoted =
- !param.isEmpty() && (param.startsWith("\"") ||
param.startsWith("'") || param.startsWith("/"));
- if (quoted && param.length() > 1) {
- quoted = !param.endsWith(Character.toString(param.charAt(0)));
- }
- return quoted ? Character.toString(param.charAt(0)) : "";
- }
-
- private boolean isQuoted(String word) {
- return word.length() > 1
- && ((word.startsWith("\"") && word.endsWith("\""))
- || (word.startsWith("'") && word.endsWith("'"))
- || (word.startsWith("/") && word.endsWith("/")));
- }
-
- /**
- * Returns the index of the last delimiter in a word.
- *
- * @param word the word to search
- * @return the index, or -1 if no delimiter found
- */
- public int indexOfLastDelim(String word) {
- int out = -1;
- for (String d : delims) {
- int x = word.lastIndexOf(d.replace("\\", ""));
- if (x > out) {
- out = x;
- }
- }
- return out;
- }
-
- private void addFields(String field) {
- add("fields", field);
- }
-
- private void addValues(String arg) {
- add("values", arg);
- }
-
- private void addQuoted(String arg) {
- add("quoted", arg);
- }
-
- private void addOptions(String arg) {
- add("options", arg);
- }
-
- private void add(String where, String value) {
- if (value.length() < 3) {
- return;
- }
- names.get(where).remove(value);
- names.get(where).add(0, value);
- }
-
- /**
- * Returns the list of named pipes.
- *
- * @return the list of named pipe names
- */
- public List<String> namedPipes() {
- if (namedPipes == null) {
- namedPipes = consoleId != null ?
consoleEngine().getNamedPipes() : new ArrayList<>();
- }
- return namedPipes;
- }
-
- /**
- * Returns the list of value names.
- *
- * @return the list of values
- */
- public List<String> values() {
- return names.get("values");
- }
-
- /**
- * Returns the list of field names.
- *
- * @return the list of fields
- */
- public List<String> fields() {
- return names.get("fields");
- }
-
- /**
- * Returns the list of quoted strings.
- *
- * @return the list of quoted strings
- */
- public List<String> quoted() {
- return names.get("quoted");
- }
-
- /**
- * Returns the list of option names.
- *
- * @return the list of options
- */
- public List<String> options() {
- return names.get("options");
- }
-
- private Set<String> fieldsAndValues() {
- Set<String> out = new HashSet<>();
- out.addAll(fields());
- out.addAll(values());
- return out;
- }
-
- private void truncate(String where, int maxSize) {
- if (names.get(where).size() > maxSize) {
- names.put(where, names.get(where).subList(0, maxSize));
- }
- }
-
- /**
- * Saves the collected names to persistent storage.
- */
- public void save() {
- ConsoleEngine consoleEngine = consoleEngine();
- if (consoleEngine != null && fileNames != null) {
- int maxSize = consoleEngine.consoleOption("maxValueNames",
100);
- truncate("fields", maxSize);
- truncate("values", maxSize);
- truncate("quoted", maxSize);
- truncate("options", maxSize);
- consoleEngine.persist(fileNames, names);
- }
- }
- }
-}