From 98cdf435d4974f4cca8f7b4eb4026da2c88cbc4c Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Sun, 26 Mar 2017 11:30:43 -0400 Subject: Update --- .../src/main/java/bjc/utils/cli/CLICommander.java | 6 +- .../src/main/java/bjc/utils/cli/Command.java | 39 ++++++ .../main/java/bjc/utils/cli/CommandHandler.java | 24 ++++ .../src/main/java/bjc/utils/cli/CommandHelp.java | 27 ++++ .../src/main/java/bjc/utils/cli/CommandMode.java | 72 +++++++++++ .../main/java/bjc/utils/cli/DelegatingCommand.java | 12 +- .../main/java/bjc/utils/cli/GenericCommand.java | 14 +- .../java/bjc/utils/cli/GenericCommandMode.java | 26 ++-- .../src/main/java/bjc/utils/cli/GenericHelp.java | 2 +- .../src/main/java/bjc/utils/cli/ICommand.java | 39 ------ .../main/java/bjc/utils/cli/ICommandHandler.java | 24 ---- .../src/main/java/bjc/utils/cli/ICommandHelp.java | 27 ---- .../src/main/java/bjc/utils/cli/ICommandMode.java | 72 ----------- .../src/main/java/bjc/utils/cli/NullHelp.java | 2 +- .../src/main/java/bjc/utils/cli/fds/FDS.java | 69 ++++++++++ .../main/java/bjc/utils/cli/fds/FDSCommand.java | 26 ++++ .../main/java/bjc/utils/cli/fds/FDSException.java | 32 +++++ .../src/main/java/bjc/utils/cli/fds/FDSMode.java | 94 ++++++++++++++ .../main/java/bjc/utils/cli/fds/SimpleFDSMode.java | 142 +++++++++++++++++++++ 19 files changed, 556 insertions(+), 193 deletions(-) create mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/Command.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/CommandHandler.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/CommandHelp.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/CommandMode.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/ICommand.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHandler.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHelp.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/ICommandMode.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDS.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSCommand.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSException.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSMode.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/fds/SimpleFDSMode.java (limited to 'BJC-Utils2/src/main/java/bjc/utils/cli') 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 719d6ca..56a4be0 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/cli/CLICommander.java +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/CLICommander.java @@ -23,7 +23,7 @@ public class CLICommander { /* * The command mode to start execution in. */ - private ICommandMode initialMode; + private CommandMode initialMode; /** * Create a new CLI interface powered by streams. @@ -69,7 +69,7 @@ public class CLICommander { * * Used to preserve the initial mode. */ - ICommandMode currentMode = initialMode; + CommandMode currentMode = initialMode; /* * Process commands until we're told to stop. @@ -124,7 +124,7 @@ public class CLICommander { * @param initialMode * The initial command mode to use. */ - public void setInitialCommandMode(ICommandMode initialMode) { + public void setInitialCommandMode(CommandMode initialMode) { if(initialMode == null) throw new NullPointerException("Initial mode must be non-zero"); this.initialMode = initialMode; diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/Command.java b/BJC-Utils2/src/main/java/bjc/utils/cli/Command.java new file mode 100644 index 0000000..02bc061 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/Command.java @@ -0,0 +1,39 @@ +package bjc.utils.cli; + +/** + * Represents a command that can be invoked from a {@link CommandMode} + * + * @author ben + * + */ +public interface Command { + /** + * Create a command that serves as an alias to this one + * + * @return A command that serves as an alias to this one + */ + Command aliased(); + + /** + * Get the handler that executes this command + * + * @return The handler that executes this command + */ + CommandHandler getHandler(); + + /** + * Get the help entry for this command + * + * @return The help entry for this command + */ + CommandHelp getHelp(); + + /** + * Check if this command is an alias of another command + * + * @return Whether or not this command is an alias of another + */ + default boolean isAlias() { + return false; + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/CommandHandler.java b/BJC-Utils2/src/main/java/bjc/utils/cli/CommandHandler.java new file mode 100644 index 0000000..0a3534f --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/CommandHandler.java @@ -0,0 +1,24 @@ +package bjc.utils.cli; + +import java.util.function.Function; + +/** + * A handler for a command + * + * @author ben + * + */ +@FunctionalInterface +public interface CommandHandler extends Function { + /** + * Execute this command + * + * @param args + * The arguments for this command + * @return The command mode to switch to after this command, or null to + * stop executing commands + */ + default CommandMode handle(String[] args) { + return this.apply(args); + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/CommandHelp.java b/BJC-Utils2/src/main/java/bjc/utils/cli/CommandHelp.java new file mode 100644 index 0000000..327fb75 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/CommandHelp.java @@ -0,0 +1,27 @@ +package bjc.utils.cli; + +/** + * Interface for the help entry for a command + * + * @author ben + * + */ +public interface CommandHelp { + /** + * Get the description of a command. + * + * @return The description of a command + */ + String getDescription(); + + /** + * Get the summary line for a command. + * + * A summary line should consist of a string of the following format + * "\t" where anything in angle brackets + * should be filled in. + * + * @return The summary line line for a command + */ + String getSummary(); +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/CommandMode.java b/BJC-Utils2/src/main/java/bjc/utils/cli/CommandMode.java new file mode 100644 index 0000000..d26b176 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/CommandMode.java @@ -0,0 +1,72 @@ +package bjc.utils.cli; + +/** + * A mode for determining the commands that are valid to enter, and then + * handling those commands + * + * @author ben + * + */ +public interface CommandMode extends Comparable { + /** + * Check to see if this mode can handle the specified command + * + * @param command + * The command to check + * @return Whether or not this mode can handle the command. It is + * assumed not by default + */ + default boolean canHandle(String command) { + return false; + }; + + /** + * Get the custom prompt for this mode + * + * @return the custom prompt for this mode + * + * @throws UnsupportedOperationException + * if this mode doesn't support a custom prompt + */ + default String getCustomPrompt() { + throw new UnsupportedOperationException("This mode doesn't support a custom prompt"); + } + + /** + * Get the name of this command mode + * + * @return The name of this command mode, which is the empty string by + * default + */ + public default String getName() { + return ""; + } + + /** + * Check if this mode uses a custom prompt + * + * @return Whether or not this mode uses a custom prompt + */ + default boolean isCustomPromptEnabled() { + return false; + } + + /** + * Process a command in this mode + * + * @param command + * The command to process + * @param args + * A list of arguments to the command + * @return The command mode to use for the next command. Defaults to + * returning this, and doing nothing else + */ + default CommandMode process(String command, String[] args) { + return this; + } + + @Override + default int compareTo(CommandMode o) { + return getName().compareTo(o.getName()); + } +} 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 99d7e43..dbbb047 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/cli/DelegatingCommand.java +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/DelegatingCommand.java @@ -6,11 +6,11 @@ package bjc.utils.cli; * @author ben * */ -class DelegatingCommand implements ICommand { +class DelegatingCommand implements Command { /* * The command to delegate to. */ - private ICommand delegate; + private Command delegate; /** * Create a new command that delegates to another command. @@ -18,22 +18,22 @@ class DelegatingCommand implements ICommand { * @param delegate * The command to delegate to. */ - public DelegatingCommand(ICommand delegate) { + public DelegatingCommand(Command delegate) { this.delegate = delegate; } @Override - public ICommand aliased() { + public Command aliased() { return new DelegatingCommand(delegate); } @Override - public ICommandHandler getHandler() { + public CommandHandler getHandler() { return delegate.getHandler(); } @Override - public ICommandHelp getHelp() { + public CommandHelp getHelp() { return delegate.getHelp(); } 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 ea10108..c49b4b9 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java @@ -6,16 +6,16 @@ package bjc.utils.cli; * @author ben * */ -public class GenericCommand implements ICommand { +public class GenericCommand implements Command { /* * The behavior for invoking the command. */ - private ICommandHandler handler; + private CommandHandler handler; /* * The help for the command. */ - private ICommandHelp help; + private CommandHelp help; /** * Create a new generic command. @@ -30,7 +30,7 @@ public class GenericCommand implements ICommand { * null, in which case the description is repeated for * the detailed help. */ - public GenericCommand(ICommandHandler handler, String description, String help) { + public GenericCommand(CommandHandler handler, String description, String help) { if(handler == null) throw new NullPointerException("Command handler must not be null"); this.handler = handler; @@ -43,17 +43,17 @@ public class GenericCommand implements ICommand { } @Override - public ICommand aliased() { + public Command aliased() { return new DelegatingCommand(this); } @Override - public ICommandHandler getHandler() { + public CommandHandler getHandler() { return handler; } @Override - public ICommandHelp getHelp() { + public CommandHelp getHelp() { return help; } 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 ee2bdbb..7977391 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommandMode.java +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommandMode.java @@ -17,17 +17,17 @@ import java.util.function.Consumer; * @author ben * */ -public class GenericCommandMode implements ICommandMode { +public class GenericCommandMode implements CommandMode { /* * Contains the commands this mode handles */ - private IMap commandHandlers; - private IMap defaultHandlers; + private IMap commandHandlers; + private IMap defaultHandlers; /* * Contains help topics without an associated command */ - private IMap helpTopics; + private IMap helpTopics; /* * The action to execute upon encountering an unknown command @@ -103,7 +103,7 @@ public class GenericCommandMode implements ICommandMode { throw new IllegalArgumentException( "Cannot bind alias '" + aliasName + "' to a command with a bound handler"); else { - ICommand aliasedCommand; + Command aliasedCommand; if(defaultHandlers.containsKey(commandName)) { aliasedCommand = defaultHandlers.get(commandName).aliased(); @@ -127,7 +127,7 @@ public class GenericCommandMode implements ICommandMode { * if the specified command already has a handler * registered */ - public void addCommandHandler(String command, ICommand handler) { + public void addCommandHandler(String command, Command handler) { if(command == null) throw new NullPointerException("Command must not be null"); else if(handler == null) @@ -147,7 +147,7 @@ public class GenericCommandMode implements ICommandMode { * @param topic * The contents of the topic */ - public void addHelpTopic(String topicName, ICommandHelp topic) { + public void addHelpTopic(String topicName, CommandHelp topic) { helpTopics.put(topicName, topic); } @@ -274,7 +274,7 @@ public class GenericCommandMode implements ICommandMode { private void doHelpSummary() { normalOutput.accept("Help topics for this command mode are as follows:\n"); - if(commandHandlers.getSize() > 0) { + if(commandHandlers.size() > 0) { commandHandlers.forEachValue(command -> { if(!command.isAlias()) { normalOutput.accept("\t" + command.getHelp().getSummary() + "\n"); @@ -285,7 +285,7 @@ public class GenericCommandMode implements ICommandMode { } normalOutput.accept("\nHelp topics available in all command modes are as follows\n"); - if(defaultHandlers.getSize() > 0) { + if(defaultHandlers.size() > 0) { defaultHandlers.forEachValue(command -> { if(!command.isAlias()) { normalOutput.accept("\t" + command.getHelp().getSummary() + "\n"); @@ -296,7 +296,7 @@ public class GenericCommandMode implements ICommandMode { } normalOutput.accept("\nHelp topics not associated with a command are as follows\n"); - if(helpTopics.getSize() > 0) { + if(helpTopics.size() > 0) { helpTopics.forEachValue(topic -> { normalOutput.accept("\t" + topic.getSummary() + "\n"); }); @@ -324,14 +324,14 @@ public class GenericCommandMode implements ICommandMode { public String getCustomPrompt() { if(customPrompt != null) return customPrompt; - return ICommandMode.super.getCustomPrompt(); + return CommandMode.super.getCustomPrompt(); } @Override public String getName() { if(modeName != null) return modeName; - return ICommandMode.super.getName(); + return CommandMode.super.getName(); } @Override @@ -340,7 +340,7 @@ public class GenericCommandMode implements ICommandMode { } @Override - public ICommandMode process(String command, String[] args) { + public CommandMode process(String command, String[] args) { normalOutput.accept("\n"); if(defaultHandlers.containsKey(command)) 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 bbdd1fc..edda5c0 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericHelp.java +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericHelp.java @@ -6,7 +6,7 @@ package bjc.utils.cli; * @author ben * */ -public class GenericHelp implements ICommandHelp { +public class GenericHelp implements CommandHelp { // The strings for this help topic private String summary; private String 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 deleted file mode 100644 index 6d30c6a..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommand.java +++ /dev/null @@ -1,39 +0,0 @@ -package bjc.utils.cli; - -/** - * Represents a command that can be invoked from a {@link ICommandMode} - * - * @author ben - * - */ -public interface ICommand { - /** - * Create a command that serves as an alias to this one - * - * @return A command that serves as an alias to this one - */ - ICommand aliased(); - - /** - * Get the handler that executes this command - * - * @return The handler that executes this command - */ - ICommandHandler getHandler(); - - /** - * Get the help entry for this command - * - * @return The help entry for this command - */ - ICommandHelp getHelp(); - - /** - * Check if this command is an alias of another command - * - * @return Whether or not this command is an alias of another - */ - default boolean isAlias() { - return false; - } -} diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHandler.java b/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHandler.java deleted file mode 100644 index d1f7f77..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHandler.java +++ /dev/null @@ -1,24 +0,0 @@ -package bjc.utils.cli; - -import java.util.function.Function; - -/** - * A handler for a command - * - * @author ben - * - */ -@FunctionalInterface -public interface ICommandHandler extends Function { - /** - * Execute this command - * - * @param args - * The arguments for this command - * @return The command mode to switch to after this command, or null to - * stop executing commands - */ - 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 deleted file mode 100644 index f267594..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHelp.java +++ /dev/null @@ -1,27 +0,0 @@ -package bjc.utils.cli; - -/** - * Interface for the help entry for a command - * - * @author ben - * - */ -public interface ICommandHelp { - /** - * Get the description of a command. - * - * @return The description of a command - */ - String getDescription(); - - /** - * Get the summary line for a command. - * - * A summary line should consist of a string of the following format - * "\t" where anything in angle brackets - * should be filled in. - * - * @return The summary line line for a command - */ - 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 deleted file mode 100644 index 431a8cf..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandMode.java +++ /dev/null @@ -1,72 +0,0 @@ -package bjc.utils.cli; - -/** - * A mode for determining the commands that are valid to enter, and then - * handling those commands - * - * @author ben - * - */ -public interface ICommandMode extends Comparable { - /** - * Check to see if this mode can handle the specified command - * - * @param command - * The command to check - * @return Whether or not this mode can handle the command. It is - * assumed not by default - */ - default boolean canHandle(String command) { - return false; - }; - - /** - * Get the custom prompt for this mode - * - * @return the custom prompt for this mode - * - * @throws UnsupportedOperationException - * if this mode doesn't support a custom prompt - */ - default String getCustomPrompt() { - throw new UnsupportedOperationException("This mode doesn't support a custom prompt"); - } - - /** - * Get the name of this command mode - * - * @return The name of this command mode, which is the empty string by - * default - */ - public default String getName() { - return ""; - } - - /** - * Check if this mode uses a custom prompt - * - * @return Whether or not this mode uses a custom prompt - */ - default boolean isCustomPromptEnabled() { - return false; - } - - /** - * Process a command in this mode - * - * @param command - * The command to process - * @param args - * A list of arguments to the command - * @return The command mode to use for the next command. Defaults to - * returning this, and doing nothing else - */ - default ICommandMode process(String command, String[] args) { - return this; - } - - @Override - default int compareTo(ICommandMode o) { - return getName().compareTo(o.getName()); - } -} diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/NullHelp.java b/BJC-Utils2/src/main/java/bjc/utils/cli/NullHelp.java index 0d511a4..289d9c1 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/cli/NullHelp.java +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/NullHelp.java @@ -6,7 +6,7 @@ package bjc.utils.cli; * @author ben * */ -public class NullHelp implements ICommandHelp { +public class NullHelp implements CommandHelp { @Override public String getDescription() { return "No description provided"; diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDS.java b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDS.java new file mode 100644 index 0000000..6dc0337 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDS.java @@ -0,0 +1,69 @@ +package bjc.utils.cli.fds; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintStream; +import bjc.utils.ioutils.Block; +import bjc.utils.ioutils.BlockReader; + +/** + * Runs a FDS (FDiskScript) interface. + * + * This is a rudimentary console interface inspired heavily by FDisk's interface + * style. + * + * Commands are denoted by a single character, but can invoke submodes. + * + * @author bjculkin + * + */ +public class FDS { + /** + * Run a provided FDS mode until it is exited or there is no more input. + * + * @param comin + * The command input source for the FDS mode. + * + * @param datain + * The data input source for the FDS mode. + * + * @param out + * The output source for the FDS mode. + * + * @param initialMode + * The mode to start in. + * + * @param initialState + * The initial state for the mode. + * + * @return The final state of the mode. + * + * @throws FDSException + * If something went wrong during mode execution. + */ + public static S runFDS(InputStream comin, InputStream datain, OutputStream out, FDSMode initialMode, + S initialState) throws FDSException { + PrintStream printer = new PrintStream(out); + + try (BlockReader blockSource = new BlockReader("\\R", new InputStreamReader(comin))) { + printer.print("Enter a command (m for help): "); + + while (blockSource.hasNext()) { + Block comBlock = blockSource.next(); + + String comString = comBlock.contents.trim(); + + char comChar = comString.charAt(0); + + printer.println(String.format("\nRecieved command '%s'\n", comChar)); + + printer.print("Enter a command (m for help): "); + } + } catch (Exception ex) { + throw new FDSException("Unexpected I/O error", ex); + } + + return initialState; + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSCommand.java b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSCommand.java new file mode 100644 index 0000000..0a6d29c --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSCommand.java @@ -0,0 +1,26 @@ +package bjc.utils.cli.fds; + +import java.util.Iterator; + +/** + * A command attached to an FDS interface. + * + * @author bjculkin + * + * @param + * The state type of the interface. + */ +public interface FDSCommand { + /** + * Run this command. + * + * @param state + * The current FDS state. + * + * @param input + * The source for data input. + * + * @return The new state, after running the command. + */ + S run(S state, Iterator input); +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSException.java b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSException.java new file mode 100644 index 0000000..7569d95 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSException.java @@ -0,0 +1,32 @@ +package bjc.utils.cli.fds; + +/** + * Exception thrown when something goes wrong with FDS. + * + * @author bjculkin + * + */ +public class FDSException extends Exception { + /** + * Create a new FDS exception with a message and a cause. + * + * @param message + * The message for the exception. + * + * @param cause + * The cause of the exception. + */ + public FDSException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Create a new FDS exception with a message. + * + * @param message + * The message for the exception. + */ + public FDSException(String message) { + super(message); + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSMode.java b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSMode.java new file mode 100644 index 0000000..acdcbcb --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSMode.java @@ -0,0 +1,94 @@ +package bjc.utils.cli.fds; + +import bjc.utils.cli.CommandHelp; +import bjc.utils.cli.NullHelp; + +/** + * A collection of related FDS commands. + * + * @author bjculkin + * + * @param + * The FDS state type. + */ +public interface FDSMode { + /** + * Get all the characters that are registered to something in this mode. + * + * In this context, something means a command or submode. + * + * @return All of the characters registered to something in this mode. + */ + char[] registeredChars(); + + /* + * Check for the existence of commands/submodes. + */ + + /** + * Check if there is a command registered to the given character. + * + * @param c + * The character to check + * + * @return Whether or not there is a command bound to that character. + */ + boolean hasCommand(char c); + + /** + * Check if there is a submode registered to the given character. + * + * @param c + * The character to check + * + * @return Whether or not there is a submode bound to that character. + */ + boolean hasSubmode(char c); + + /* + * Get commands and submodes. + */ + + /** + * Get the command attached to a given character. + * + * @param c + * The character to get the command for. + * + * @return The command bound to that character. + * + * @throws FDSException + * If there is no command bound to that character. + */ + FDSCommand getCommand(char c) throws FDSException; + + /** + * Get the command attached to a given character. + * + * @param c + * The character to get the command for. + * + * @return The command bound to that character. + * + * @throws FDSException + * If there is no command bound to that character. + */ + FDSMode getSubmode(char c) throws FDSException; + + /* + * Help utilities + */ + /** + * Get the help for what's bound to a character. + * + * This should be one line. + * + * @param c + * The character to look at the help for. + * + * @return The help for what's bound to the character. + */ + default CommandHelp getHelp(char c) { + return new NullHelp(); + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/SimpleFDSMode.java b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/SimpleFDSMode.java new file mode 100644 index 0000000..2f6e660 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/SimpleFDSMode.java @@ -0,0 +1,142 @@ +package bjc.utils.cli.fds; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import bjc.utils.cli.CommandHelp; + +import static java.lang.String.format; + +/** + * Simple implementation of {@link FDSMode}. + * + * @author bjculkin + * + * @param + * The FDS state type. + */ +public class SimpleFDSMode implements FDSMode { + private Map> commands; + private Map> modes; + private Map help; + + private Set registered; + private char[] registeredArray; + private boolean changed; + + /** + * Create a new empty FDS mode. + */ + public SimpleFDSMode() { + commands = new HashMap<>(); + modes = new HashMap<>(); + help = new HashMap<>(); + + registered = new HashSet<>(); + changed = true; + } + + /** + * Add a command to the mode. + * + * @param c + * The character to bind to the command. + * + * @param comm + * The command to add. + * + * @param hlp + * The help for the command. + * + * @throws FDSException + * If the character is already bound to a command. + */ + public void addCommand(char c, FDSCommand comm, CommandHelp hlp) throws FDSException { + if (comm == null) + throw new NullPointerException("Command must not be null"); + else if (commands.containsKey(c) || modes.containsKey(c)) + throw new FDSException(format("Character '%s' is already bound")); + + commands.put(c, comm); + + registered.add(c); + if (!changed) changed = true; + } + + /** + * Add a submode to the mode. + * + * @param c + * The character to bind to the submode. + * + * @param mode + * The submode to add. + * + * @throws FDSException + * If the character is already bound to a submode. + */ + public void addSubmode(char c, FDSMode mode) throws FDSException { + if (mode == null) + throw new NullPointerException("Mode must not be null"); + else if (modes.containsKey(c) || commands.containsKey(c)) + throw new FDSException(format("Character '%s' is already bound")); + + modes.put(c, mode); + + registered.add(c); + if (!changed) changed = true; + } + + @Override + public char[] registeredChars() { + if (!changed) return registeredArray; + + registeredArray = new char[registered.size()]; + + int i = 0; + for (char c : registered) { + registeredArray[i] = c; + + i += 1; + } + + changed = false; + + return registeredArray; + } + + @Override + public boolean hasCommand(char c) { + return commands.containsKey(c); + } + + @Override + public boolean hasSubmode(char c) { + return modes.containsKey(c); + } + + @Override + public FDSCommand getCommand(char c) throws FDSException { + if (!commands.containsKey(c)) { + throw new FDSException(String.format("No command bound to '%s'", c)); + } + + return commands.get(c); + } + + @Override + public FDSMode getSubmode(char c) throws FDSException { + if (!modes.containsKey(c)) { + throw new FDSException(String.format("No mode bound to '%s'", c)); + } + + return modes.get(c); + } + + @Override + public CommandHelp getHelp(char c) { + return help.get(c); + } +} \ No newline at end of file -- cgit v1.2.3