diff options
| author | bculkin2442 <bjculkin@mix.wvu.edu> | 2016-05-10 16:02:45 -0400 |
|---|---|---|
| committer | bculkin2442 <bjculkin@mix.wvu.edu> | 2016-05-10 16:02:45 -0400 |
| commit | 61fd71f69e080790da722e0e03b71ecd7c2538a2 (patch) | |
| tree | e5c1150b27b84d550f807e44ac82688216451f00 /BJC-Utils2/src/main/java/bjc/utils/cli | |
| parent | 87ae1dfc8d8cb7b51d7bda4750ce841bbe691cfc (diff) | |
General update
Diffstat (limited to 'BJC-Utils2/src/main/java/bjc/utils/cli')
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; } } |
