
de.lessvoid.nifty.controls.ConsoleCommands Maven / Gradle / Ivy
package de.lessvoid.nifty.controls;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.elements.Element;
import de.lessvoid.nifty.input.NiftyInputEvent;
import de.lessvoid.nifty.input.NiftyStandardInputEvent;
import de.lessvoid.nifty.screen.KeyInputHandler;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
/**
* This adds all the nifty command line features to the console control:
* - command line completion (for all registered commands)
* - command history
* - command processing which detects commands and directly calls your registered commands (via the ConsoleCommand
* interface)
*
* @author void
*/
public class ConsoleCommands implements KeyInputHandler {
private boolean commandCompletion = false;
@Nonnull
private final ConsoleCommandSplitter splitter = new ConsoleCommandSplitter();
@Nonnull
private final Map commands = new TreeMap();
@Nonnull
private final List commandHistory = new ArrayList();
private int commandHistoryLastCommand = -1;
@Nonnull
private final Nifty nifty;
@Nonnull
private final Console console;
@Nullable
private final TextField textfield;
/**
* You can implement this interface for individual commands and Nifty will call them
* when the registered command has been detected.
*
* @author void
*/
public interface ConsoleCommand {
/**
* Execute the command. You'll get an array of all parameters. This works the
* same as with java main, which means the first entry in the array will be the
* command and all other array entries are the actual parameters.
*
* @param args command and arguments
*/
void execute(@Nonnull String... args);
}
/**
* Create and attach this to the given console.
*/
public ConsoleCommands(@Nonnull final Nifty nifty, @Nonnull final Console console) {
this.nifty = nifty;
this.console = console;
textfield = console.getTextField();
if (textfield != null) {
Element textFieldElement = textfield.getElement();
if (textFieldElement != null) {
textFieldElement.addPreInputHandler(this);
}
}
}
/**
* When the command completion is enabled pressing TAB will check for all known
* commands. Use registerCommand() to register commands for this feature to work.
* Please note that in this case you can't TAB away from the textfield.
*
* @param enabled true when command completion should be enabled and false if not
*/
public void enableCommandCompletion(final boolean enabled) {
commandCompletion = enabled;
}
/**
* Register a command for the command completion feature.
*
* @param command the command to make known
*/
public void registerCommand(@Nonnull final String commandText, @Nonnull final ConsoleCommand command) {
commands.put(commandText, command);
}
/**
* Get all commands that are registered.
*
* @return list of all commands that have been registered
*/
@Nonnull
public List getRegisteredCommands() {
Set var = commands.keySet();
return Collections.unmodifiableList(Arrays.asList(var.toArray(new String[var.size()])));
}
@Override
public boolean keyEvent(@Nonnull final NiftyInputEvent inputEvent) {
if (!commandCompletion || textfield == null) {
return false;
}
if (NiftyStandardInputEvent.NextInputElement.equals(inputEvent)) {
List matches = findMatches(textfield.getRealText());
if (matches.size() == 1) {
changeText(matches.get(0));
return true;
} else if (matches.size() > 1) {
String shortest = findShortestMatch(matches);
if (shortest.length() == textfield.getRealText().length()) {
StringBuilder buffer = new StringBuilder("\n");
for (String match : matches) {
buffer.append("\\#cccf#").append(match).append("\n");
}
console.output(buffer.toString());
}
changeText(shortest);
}
return true;
} else if (NiftyStandardInputEvent.MoveCursorUp.equals(inputEvent)) {
if (commandHistoryLastCommand > 0) {
commandHistoryLastCommand--;
changeText(commandHistory.get(commandHistoryLastCommand));
}
return true;
} else if (NiftyStandardInputEvent.MoveCursorDown.equals(inputEvent)) {
if (commandHistoryLastCommand < commandHistory.size() - 1) {
commandHistoryLastCommand++;
changeText(commandHistory.get(commandHistoryLastCommand));
} else {
commandHistoryLastCommand = commandHistory.size();
changeText("");
}
return true;
} else if (NiftyStandardInputEvent.SubmitText.equals(inputEvent)) {
String text = textfield.getRealText();
console.output(text);
textfield.setText("");
// find command
String[] split = splitter.split(text);
if (split.length != 0) {
String command = split[0];
// is there a command that starts with this "command" string?
for (Map.Entry registeredCommand : commands.entrySet()) {
String[] s = registeredCommand.getKey().split(" ");
if (s.length != 0) {
String start = s[0];
if (command.equals(start)) {
ConsoleCommand consoleCommand = registeredCommand.getValue();
consoleCommand.execute(split);
addCommandToHistory(text);
return true;
}
}
}
}
console.outputError("Unknown command: " + text);
// this means we have not found an appropriate command in the registered commands
// we'll publish this now as the original console would do. this way you can still
// subscribe for it (if you need to).
String id = console.getId();
if (id != null) {
nifty.publishEvent(id, new ConsoleExecuteCommandEvent(console, text));
}
addCommandToHistory(text);
return true;
}
return false;
}
/**
* Find a ConsoleCommand with the given commandText. This will find commands that
* begin with the given commandText as well.
*
* @param commandText the command to return
* @return the ConsoleCommand or null if command does not exist
*/
@Nullable
public ConsoleCommand findCommand(@Nonnull final String commandText) {
ConsoleCommand command = commands.get(commandText);
if (command != null) {
return command;
}
List commandMatches = findMatches(commandText);
if (commandMatches.size() == 1) {
return commands.get(commandMatches.get(0));
}
return null;
}
private void changeText(@Nonnull final String newText) {
if (textfield != null) {
textfield.setText(newText);
textfield.setCursorPosition(textfield.getRealText().length());
}
}
private void addCommandToHistory(@Nonnull final String text) {
commandHistory.add(text);
commandHistoryLastCommand = commandHistory.size();
}
@Nonnull
List findMatches(@Nullable final String text) {
if (text == null || text.length() == 0) {
return Collections.emptyList();
}
List result = new ArrayList();
for (String command : commands.keySet()) {
if (command.equals(text)) {
result.add(command);
} else if (command.startsWith(text)) {
result.add(command);
}
}
return result;
}
/**
* We know that all Strings in the given List start with the same string
* that is at least one char long. This method will find the longest
* substring that exists in all of the Strings in the List.
*/
@Nonnull
String findShortestMatch(@Nonnull final List matches) {
// step 1: first longest string
String longest = "";
for (String match : matches) {
if (match.length() > longest.length()) {
longest = match;
}
}
// step 2: scan the longest string char by char and check if it is
// contained in all string of the list
String lastCheck = longest.substring(0, 1);
for (int i = 1; i < longest.length(); i++) {
String check = longest.substring(0, i);
for (String match : matches) {
if (!match.startsWith(check)) {
return lastCheck;
}
}
// woo hoo they all match, we can update lastCheck
lastCheck = check;
}
return lastCheck;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy