org.jline.console.impl.Builtins Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2002-2022, 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.jline.console.impl;
import java.io.IOException;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import org.jline.builtins.Commands;
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.SyntaxHighlighter;
import org.jline.builtins.TTop;
import org.jline.console.CommandInput;
import org.jline.console.CommandMethods;
import org.jline.console.CommandRegistry;
import org.jline.reader.Candidate;
import org.jline.reader.Completer;
import org.jline.reader.LineReader;
import org.jline.reader.LineReader.Option;
import org.jline.reader.Widget;
import org.jline.reader.impl.completer.ArgumentCompleter;
import org.jline.reader.impl.completer.NullCompleter;
import org.jline.reader.impl.completer.StringsCompleter;
import static org.jline.builtins.SyntaxHighlighter.DEFAULT_NANORC_FILE;
import static org.jline.builtins.SyntaxHighlighter.TYPE_NANORCTHEME;
/**
* Builtins: create tab completers, execute and create descriptions for builtins commands.
*
* @author Matti Rinta-Nikkola
*/
public class Builtins extends JlineCommandRegistry implements CommandRegistry {
public enum Command {
NANO,
LESS,
HISTORY,
WIDGET,
KEYMAP,
SETOPT,
SETVAR,
UNSETOPT,
TTOP,
COLORS,
HIGHLIGHTER
}
private final ConfigurationPath configPath;
private final Function widgetCreator;
private final Supplier workDir;
private LineReader reader;
public Builtins(Path workDir, ConfigurationPath configPath, Function widgetCreator) {
this(null, () -> workDir, configPath, widgetCreator);
}
public Builtins(
Set commands, Path workDir, ConfigurationPath configpath, Function widgetCreator) {
this(commands, () -> workDir, configpath, widgetCreator);
}
public Builtins(Supplier workDir, ConfigurationPath configPath, Function widgetCreator) {
this(null, workDir, configPath, widgetCreator);
}
@SuppressWarnings("this-escape")
public Builtins(
Set commands,
Supplier workDir,
ConfigurationPath configpath,
Function widgetCreator) {
super();
Objects.requireNonNull(configpath);
this.configPath = configpath;
this.widgetCreator = widgetCreator;
this.workDir = workDir;
Set cmds;
Map commandName = new HashMap<>();
Map commandExecute = new HashMap<>();
if (commands == null) {
cmds = new HashSet<>(EnumSet.allOf(Command.class));
} else {
cmds = new HashSet<>(commands);
}
for (Command c : cmds) {
commandName.put(c, c.name().toLowerCase());
}
commandExecute.put(Command.NANO, new CommandMethods(this::nano, this::nanoCompleter));
commandExecute.put(Command.LESS, new CommandMethods(this::less, this::lessCompleter));
commandExecute.put(Command.HISTORY, new CommandMethods(this::history, this::historyCompleter));
commandExecute.put(Command.WIDGET, new CommandMethods(this::widget, this::widgetCompleter));
commandExecute.put(Command.KEYMAP, new CommandMethods(this::keymap, this::defaultCompleter));
commandExecute.put(Command.SETOPT, new CommandMethods(this::setopt, this::setoptCompleter));
commandExecute.put(Command.SETVAR, new CommandMethods(this::setvar, this::setvarCompleter));
commandExecute.put(Command.UNSETOPT, new CommandMethods(this::unsetopt, this::unsetoptCompleter));
commandExecute.put(Command.TTOP, new CommandMethods(this::ttop, this::defaultCompleter));
commandExecute.put(Command.COLORS, new CommandMethods(this::colors, this::defaultCompleter));
commandExecute.put(Command.HIGHLIGHTER, new CommandMethods(this::highlighter, this::highlighterCompleter));
registerCommands(commandName, commandExecute);
}
public void setLineReader(LineReader reader) {
this.reader = reader;
}
private void less(CommandInput input) {
try {
Commands.less(
input.terminal(), input.in(), input.out(), input.err(), workDir.get(), input.xargs(), configPath);
} catch (Exception e) {
saveException(e);
}
}
private void nano(CommandInput input) {
try {
Commands.nano(input.terminal(), input.out(), input.err(), workDir.get(), input.args(), configPath);
} catch (Exception e) {
saveException(e);
}
}
private void history(CommandInput input) {
try {
Commands.history(reader, input.out(), input.err(), workDir.get(), input.args());
} catch (Exception e) {
saveException(e);
}
}
private void widget(CommandInput input) {
try {
Commands.widget(reader, input.out(), input.err(), widgetCreator, input.args());
} catch (Exception e) {
saveException(e);
}
}
private void keymap(CommandInput input) {
try {
Commands.keymap(reader, input.out(), input.err(), input.args());
} catch (Exception e) {
saveException(e);
}
}
private void setopt(CommandInput input) {
try {
Commands.setopt(reader, input.out(), input.err(), input.args());
} catch (Exception e) {
saveException(e);
}
}
private void setvar(CommandInput input) {
try {
Commands.setvar(reader, input.out(), input.err(), input.args());
} catch (Exception e) {
saveException(e);
}
}
private void unsetopt(CommandInput input) {
try {
Commands.unsetopt(reader, input.out(), input.err(), input.args());
} catch (Exception e) {
saveException(e);
}
}
private void ttop(CommandInput input) {
try {
TTop.ttop(input.terminal(), input.out(), input.err(), input.args());
} catch (Exception e) {
saveException(e);
}
}
private void colors(CommandInput input) {
try {
Commands.colors(input.terminal(), input.out(), input.args());
} catch (Exception e) {
saveException(e);
}
}
private void highlighter(CommandInput input) {
try {
Commands.highlighter(reader, input.terminal(), input.out(), input.err(), input.args(), configPath);
} catch (Exception e) {
saveException(e);
}
}
private List unsetOptions(boolean set) {
List out = new ArrayList<>();
for (Option option : Option.values()) {
if (set == (reader.isSet(option) == option.isDef())) {
out.add((option.isDef() ? "no-" : "")
+ option.toString().toLowerCase().replace('_', '-'));
}
}
return out;
}
private List highlighterCompleter(String name) {
List completers = new ArrayList<>();
List optDescs = commandOptions(name);
for (OptDesc o : optDescs) {
if (o.shortOption() != null
&& (o.shortOption().equals("-v") || o.shortOption().equals("-s"))) {
Path userConfig = null;
if (o.shortOption().equals("-s")) {
try {
userConfig = configPath.getUserConfig(DEFAULT_NANORC_FILE);
} catch (IOException ignore) {
}
}
if (o.shortOption().equals("-v") || userConfig != null) {
Path ct = SyntaxHighlighter.build(configPath.getConfig(DEFAULT_NANORC_FILE), null)
.getCurrentTheme();
if (ct != null) {
o.setValueCompleter(new FilesCompleter(ct.getParent(), "*" + TYPE_NANORCTHEME));
}
}
}
}
completers.add(new ArgumentCompleter(
NullCompleter.INSTANCE, new OptionCompleter(NullCompleter.INSTANCE, optDescs, 1)));
return completers;
}
private Set allWidgets() {
Set out = new HashSet<>();
for (String s : reader.getWidgets().keySet()) {
out.add(s);
out.add(reader.getWidgets().get(s).toString());
}
return out;
}
private List nanoCompleter(String name) {
List completers = new ArrayList<>();
completers.add(new ArgumentCompleter(
NullCompleter.INSTANCE, new OptionCompleter(new FilesCompleter(workDir), this::commandOptions, 1)));
return completers;
}
private List lessCompleter(String name) {
List completers = new ArrayList<>();
completers.add(new ArgumentCompleter(
NullCompleter.INSTANCE, new OptionCompleter(new FilesCompleter(workDir), this::commandOptions, 1)));
return completers;
}
private List historyCompleter(String name) {
List completers = new ArrayList<>();
List optDescs = commandOptions(name);
for (OptDesc o : optDescs) {
if (o.shortOption() != null
&& (o.shortOption().equals("-A")
|| o.shortOption().equals("-W")
|| o.shortOption().equals("-R"))) {
o.setValueCompleter(new FilesCompleter(workDir));
}
}
completers.add(new ArgumentCompleter(
NullCompleter.INSTANCE, new OptionCompleter(NullCompleter.INSTANCE, optDescs, 1)));
return completers;
}
private List widgetCompleter(String name) {
List completers = new ArrayList<>();
List optDescs = commandOptions(name);
Candidate aliasOption = new Candidate("-A", "-A", null, null, null, null, true);
Iterator i = optDescs.iterator();
while (i.hasNext()) {
OptDesc o = i.next();
if (o.shortOption() != null) {
if (o.shortOption().equals("-D")) {
o.setValueCompleter(
new StringsCompleter(() -> reader.getWidgets().keySet()));
} else if (o.shortOption().equals("-A")) {
aliasOption =
new Candidate(o.shortOption(), o.shortOption(), null, o.description(), null, null, true);
i.remove();
}
}
}
completers.add(new ArgumentCompleter(
NullCompleter.INSTANCE, new OptionCompleter(NullCompleter.INSTANCE, optDescs, 1)));
completers.add(new ArgumentCompleter(
NullCompleter.INSTANCE,
new StringsCompleter(aliasOption),
new StringsCompleter(this::allWidgets),
new StringsCompleter(() -> reader.getWidgets().keySet()),
NullCompleter.INSTANCE));
return completers;
}
private List setvarCompleter(String name) {
List completers = new ArrayList<>();
completers.add(new ArgumentCompleter(
NullCompleter.INSTANCE,
new StringsCompleter(() -> reader.getVariables().keySet()),
NullCompleter.INSTANCE));
return completers;
}
private List setoptCompleter(String name) {
List completers = new ArrayList<>();
completers.add(new ArgumentCompleter(NullCompleter.INSTANCE, new StringsCompleter(() -> unsetOptions(true))));
return completers;
}
private List unsetoptCompleter(String name) {
List completers = new ArrayList<>();
completers.add(new ArgumentCompleter(NullCompleter.INSTANCE, new StringsCompleter(() -> unsetOptions(false))));
return completers;
}
}