summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main/java/bjc/utils/cli
diff options
context:
space:
mode:
authorbculkin2442 <bjculkin@mix.wvu.edu>2016-05-10 16:02:45 -0400
committerbculkin2442 <bjculkin@mix.wvu.edu>2016-05-10 16:02:45 -0400
commit61fd71f69e080790da722e0e03b71ecd7c2538a2 (patch)
treee5c1150b27b84d550f807e44ac82688216451f00 /BJC-Utils2/src/main/java/bjc/utils/cli
parent87ae1dfc8d8cb7b51d7bda4750ce841bbe691cfc (diff)
General update
Diffstat (limited to 'BJC-Utils2/src/main/java/bjc/utils/cli')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/CLICommander.java46
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/DelegatingCommand.java15
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java15
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommandMode.java81
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/GenericHelp.java13
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/ICommand.java2
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHandler.java5
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHelp.java10
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/ICommandMode.java6
9 files changed, 134 insertions, 59 deletions
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/CLICommander.java b/BJC-Utils2/src/main/java/bjc/utils/cli/CLICommander.java
index e1a57c2..5a7f95b 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/CLICommander.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/CLICommander.java
@@ -7,27 +7,33 @@ import java.util.Arrays;
import java.util.Scanner;
/**
- * Runs a CLI interface from the provided set of streams
+ * Runs a CLI interface from the provided set of streams.
*
* @author ben
*
*/
public class CLICommander {
+ /*
+ * The streams used for input and normal/error output
+ */
private InputStream input;
private OutputStream output;
private OutputStream error;
+ /*
+ * The command mode to start execution in
+ */
private ICommandMode initialMode;
/**
- * Create a new CLI interface powered by streams
+ * Create a new CLI interface powered by streams.
*
* @param input
- * The stream to get user input from
+ * The stream to get user input from.
* @param output
- * The stream to send user output to
+ * The stream to send normal output to.
* @param error
- * The stream to send error messages to
+ * The stream to send error output to.
*/
public CLICommander(InputStream input, OutputStream output,
OutputStream error) {
@@ -48,32 +54,51 @@ public class CLICommander {
}
/**
- * Run a set of commands through this commander
+ * Start handling commands from the given input stream.
*/
public void runCommands() {
+ // Setup output streams
PrintStream normalOutput = new PrintStream(output);
PrintStream errorOutput = new PrintStream(error);
+ /*
+ * Set up input streams.
+ *
+ * We're suppressing the warning because we might use the input
+ * stream multiple times
+ */
@SuppressWarnings("resource")
- // We might use this stream multiple times. Don't close it
Scanner inputSource = new Scanner(input);
+ /*
+ * The mode currently being used to handle commands.
+ *
+ * Used to preserve the initial mode
+ */
ICommandMode currentMode = initialMode;
+ // Process commands until we're told to stop
while (currentMode != null) {
- if (currentMode.useCustomPrompt()) {
+ /*
+ * Print out the command prompt, using a custom prompt if one
+ * is specified
+ */
+ if (currentMode.isCustomPromptEnabled()) {
normalOutput.print(currentMode.getCustomPrompt());
} else {
normalOutput.print(currentMode.getName() + ">> ");
}
+ // Read in a command
String currentLine = inputSource.nextLine();
- if (currentMode.canHandleCommand(currentLine)) {
+ // Handle handleable commands
+ if (currentMode.canHandle(currentLine)) {
String[] commandTokens = currentLine.split(" ");
String[] commandArgs;
+ // Parse args if they are present
if (commandTokens.length > 1) {
commandArgs = Arrays.copyOfRange(commandTokens, 1,
commandTokens.length);
@@ -81,7 +106,8 @@ public class CLICommander {
commandArgs = null;
}
- currentMode = currentMode.processCommand(commandTokens[0],
+ // Process command
+ currentMode = currentMode.process(commandTokens[0],
commandArgs);
} else {
errorOutput.print(
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/DelegatingCommand.java b/BJC-Utils2/src/main/java/bjc/utils/cli/DelegatingCommand.java
index 28e0347..ad115d7 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/DelegatingCommand.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/DelegatingCommand.java
@@ -1,14 +1,27 @@
package bjc.utils.cli;
+/**
+ * A class for a command that delegates to another command
+ *
+ * @author ben
+ *
+ */
class DelegatingCommand implements ICommand {
+ // The command to delegate to
private ICommand delegate;
+ /**
+ * Create a new command that delegates to another command
+ *
+ * @param delegate
+ * The command to delegate to
+ */
public DelegatingCommand(ICommand delegate) {
this.delegate = delegate;
}
@Override
- public ICommand createAlias() {
+ public ICommand aliased() {
return new DelegatingCommand(delegate);
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java
index 529635d..1a95018 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java
@@ -7,7 +7,9 @@ package bjc.utils.cli;
*
*/
public class GenericCommand implements ICommand {
+ // The behavior for invoking the command
private ICommandHandler handler;
+ // The help for the command
private ICommandHelp help;
/**
@@ -22,17 +24,16 @@ public class GenericCommand implements ICommand {
*/
public GenericCommand(ICommandHandler handler, String description,
String help) {
+ if(handler == null) {
+ throw new NullPointerException("Command handler must not be null");
+ }
+
this.handler = handler;
this.help = new GenericHelp(description, help);
}
-
- /**
- * Create a command that is an alias to this one
- *
- * @return A command that is an alias to this one
- */
+
@Override
- public ICommand createAlias() {
+ public ICommand aliased() {
return new DelegatingCommand(this);
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommandMode.java b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommandMode.java
index 0007616..59d3dc3 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommandMode.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommandMode.java
@@ -5,7 +5,7 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer;
import bjc.utils.funcdata.FunctionalMap;
-import bjc.utils.funcdata.IFunctionalMap;
+import bjc.utils.funcdata.IMap;
/**
* A general command mode, with a customizable set of commands
@@ -18,18 +18,26 @@ import bjc.utils.funcdata.IFunctionalMap;
*
*/
public class GenericCommandMode implements ICommandMode {
- private IFunctionalMap<String, ICommand> commandHandlers;
- private IFunctionalMap<String, ICommand> defaultHandlers;
+ /*
+ * Contains the commands this mode handles
+ */
+ private IMap<String, ICommand> commandHandlers;
+ private IMap<String, ICommand> defaultHandlers;
- private IFunctionalMap<String, ICommandHelp> helpTopics;
+ // Contains help topics without an associated command
+ private IMap<String, ICommandHelp> helpTopics;
+ // The action to execute upon encountering an unknown command
private BiConsumer<String, String[]> unknownCommandHandler;
+ // The functions to use for input/output
private Consumer<String> errorOutput;
private Consumer<String> normalOutput;
+ // The name of this command mode, or null if it is unnamed
private String modeName;
+ // The custom prompt to use, or null if none is specified
private String customPrompt;
/**
@@ -45,6 +53,7 @@ public class GenericCommandMode implements ICommandMode {
this.normalOutput = normalOutput;
this.errorOutput = errorOutput;
+ // Initialize handler maps so that they sort in alphabetical order
commandHandlers = new FunctionalMap<>(new TreeMap<>());
defaultHandlers = new FunctionalMap<>(new TreeMap<>());
helpTopics = new FunctionalMap<>(new TreeMap<>());
@@ -81,12 +90,13 @@ public class GenericCommandMode implements ICommandMode {
+ aliasName + "' to a command with a bound handler");
} else {
ICommand aliasedCommand;
+
if (defaultHandlers.containsKey(commandName)) {
aliasedCommand = defaultHandlers.get(commandName)
- .createAlias();
+ .aliased();
} else {
aliasedCommand = commandHandlers.get(commandName)
- .createAlias();
+ .aliased();
}
commandHandlers.put(aliasName, aliasedCommand);
@@ -97,7 +107,7 @@ public class GenericCommandMode implements ICommandMode {
* Add a command to this command mode
*
* @param command
- * The command to add
+ * The name of the command to add
* @param handler
* The handler to use for the specified command
*
@@ -110,7 +120,7 @@ public class GenericCommandMode implements ICommandMode {
throw new NullPointerException("Command must not be null");
} else if (handler == null) {
throw new NullPointerException("Handler must not be null");
- } else if (canHandleCommand(command)) {
+ } else if (canHandle(command)) {
throw new IllegalArgumentException("Command " + command
+ " already has a handler registered");
} else {
@@ -123,22 +133,28 @@ public class GenericCommandMode implements ICommandMode {
*
* @param topicName
* The name of the topic
- * @param help
+ * @param topic
* The contents of the topic
*/
- public void addHelpTopic(String topicName, ICommandHelp help) {
- helpTopics.put(topicName, help);
+ public void addHelpTopic(String topicName, ICommandHelp topic) {
+ helpTopics.put(topicName, topic);
}
+ // -------------------------------------------------------------------------
+ /*
+ * Default command builders
+ */
+ // -------------------------------------------------------------------------
+
private GenericCommand buildAliasCommand() {
return new GenericCommand((args) -> {
doAliasCommands(args);
return this;
}, "alias\tAlias one command to another",
- "alias gives a command another name it can be invoked by. It is invoked"
- + " with two arguments, the name of the command to alias"
- + ", and the alias to give that command.");
+ "Gives a command another name it can be invoked by. Invoke"
+ + " with two arguments: the name of the command to alias"
+ + "followed by the name of the alias to give that command.");
}
private GenericCommand buildClearCommands() {
@@ -148,8 +164,8 @@ public class GenericCommandMode implements ICommandMode {
return this;
}, "clear\tClear the screen",
- "clear clears the screen of all the text on it,"
- + " and prepares a fresh prompt.");
+ "Clears the screen of all the text on it,"
+ + " and prints a new prompt.");
}
private GenericCommand buildExitCommand() {
@@ -158,9 +174,9 @@ public class GenericCommandMode implements ICommandMode {
"ERROR: This console doesn't support auto-exiting");
return this;
- }, "exit\tExit the game",
- "exit first prompts the user to make sure they want to exit,"
- + " and if they affirm it, it quits");
+ }, "exit\tExit the console",
+ "First prompts the user to make sure they want to exit,"
+ + " and if they affirm it, it immediately exits");
}
private GenericCommand buildHelpCommand() {
@@ -175,10 +191,10 @@ public class GenericCommandMode implements ICommandMode {
return this;
}, "help\tConsult the help system",
- "help consults the internal help system."
- + " It can be invoked in two ways. Invoking it with no arguments"
- + " causes it to print out all the topics you can ask for details on,"
- + " while invoking it with the name of a topic will print the entry"
+ "Consults the internal help system."
+ + " Invoked in two different ways. Invoking with no arguments"
+ + " causes all the topics you can ask for details on to be list,"
+ + " while invoking with the name of a topic will print the entry"
+ " for that topic");
}
@@ -193,11 +209,17 @@ public class GenericCommandMode implements ICommandMode {
}
@Override
- public boolean canHandleCommand(String command) {
+ public boolean canHandle(String command) {
return commandHandlers.containsKey(command)
|| defaultHandlers.containsKey(command);
}
+ // -------------------------------------------------------------------------
+ /*
+ * Implement default commands
+ */
+ // -------------------------------------------------------------------------
+
private void doAliasCommands(String[] args) {
if (args.length != 2) {
errorOutput.accept("ERROR: Alias requires two arguments. "
@@ -206,10 +228,10 @@ public class GenericCommandMode implements ICommandMode {
String commandName = args[0];
String aliasName = args[1];
- if (!canHandleCommand(commandName)) {
+ if (!canHandle(commandName)) {
errorOutput.accept("ERROR: '" + commandName
+ "' is not a valid command.");
- } else if (canHandleCommand(aliasName)) {
+ } else if (canHandle(aliasName)) {
errorOutput.accept("ERROR: Cannot overwrite command '"
+ aliasName + "'");
} else {
@@ -310,7 +332,7 @@ public class GenericCommandMode implements ICommandMode {
}
@Override
- public ICommandMode processCommand(String command, String[] args) {
+ public ICommandMode process(String command, String[] args) {
normalOutput.accept("\n");
if (defaultHandlers.containsKey(command)) {
@@ -363,7 +385,8 @@ public class GenericCommandMode implements ICommandMode {
* Set the handler to use for unknown commands
*
* @param handler
- * The handler to use for unknown commands
+ * The handler to use for unknown commands, or null to throw
+ * on unknown commands
*/
public void setUnknownCommandHandler(
BiConsumer<String, String[]> handler) {
@@ -393,7 +416,7 @@ public class GenericCommandMode implements ICommandMode {
}
@Override
- public boolean useCustomPrompt() {
+ public boolean isCustomPromptEnabled() {
return customPrompt != null;
}
} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericHelp.java b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericHelp.java
index f2fb146..8742b5d 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericHelp.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericHelp.java
@@ -7,6 +7,7 @@ package bjc.utils.cli;
*
*/
public class GenericHelp implements ICommandHelp {
+ // The strings for this help topic
private String summary;
private String description;
@@ -16,15 +17,25 @@ public class GenericHelp implements ICommandHelp {
* @param summary
* The summary of this help topic
* @param description
- * The description of this help topic
+ * The description of this help topic, or null if this help
+ * topic doesn't have a more detailed description
*/
public GenericHelp(String summary, String description) {
+ if (summary == null) {
+ throw new NullPointerException(
+ "Help summary must be non-null");
+ }
+
this.summary = summary;
this.description = description;
}
@Override
public String getDescription() {
+ if (description == null) {
+ return summary;
+ }
+
return description;
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommand.java b/BJC-Utils2/src/main/java/bjc/utils/cli/ICommand.java
index ff15a37..a72ecdf 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommand.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/ICommand.java
@@ -12,7 +12,7 @@ public interface ICommand {
*
* @return A command that serves as an alias to this one
*/
- public ICommand createAlias();
+ public ICommand aliased();
/**
* Get the handler that executes this command
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHandler.java b/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHandler.java
index f806676..3d451a7 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHandler.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHandler.java
@@ -10,11 +10,12 @@ import java.util.function.Function;
*/
public interface ICommandHandler extends Function<String[], ICommandMode> {
/**
- * Handle the command this handler handles
+ * Execute this command
*
* @param args
* The arguments for this command
- * @return The command mode to go to after this command
+ * @return The command mode to switch to after this command, or null to
+ * stop executing commands
*/
public default ICommandMode handle(String[] args) {
return this.apply(args);
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHelp.java b/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHelp.java
index d475335..bd81537 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHelp.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHelp.java
@@ -8,18 +8,18 @@ package bjc.utils.cli;
*/
public interface ICommandHelp {
/**
- * Get the description of a command
+ * Get the description of a command.
*
* @return The description of a command
*/
public String getDescription();
/**
- * Get the summary line for a command
- *
- * Used for 'help commands' which gives the user a brief idea what all
- * the commands do
+ * Get the summary line for a command.
*
+ * A summary line should consist of a string of the following format
+ * "<command-name>\t<command-summary>"
+ * where anything in angle brackets should be filled in.
* @return The summary line line for a command
*/
public String getSummary();
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandMode.java b/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandMode.java
index 48a741c..f60e571 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandMode.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandMode.java
@@ -16,7 +16,7 @@ public interface ICommandMode {
* @return Whether or not this mode can handle the command. It is
* assumed not by default
*/
- public default boolean canHandleCommand(String command) {
+ public default boolean canHandle(String command) {
return false;
};
@@ -53,7 +53,7 @@ public interface ICommandMode {
* @return The command mode to use for the next command. Defaults to
* returning this, and doing nothing else
*/
- public default ICommandMode processCommand(String command,
+ public default ICommandMode process(String command,
String[] args) {
return this;
}
@@ -63,7 +63,7 @@ public interface ICommandMode {
*
* @return Whether or not this mode uses a custom prompt
*/
- public default boolean useCustomPrompt() {
+ public default boolean isCustomPromptEnabled() {
return false;
}
}