summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main/java/bjc/utils/cli
diff options
context:
space:
mode:
Diffstat (limited to 'BJC-Utils2/src/main/java/bjc/utils/cli')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDS.java121
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSCommand.java10
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSMode.java13
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSState.java45
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSUtils.java61
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/fds/SimpleFDSMode.java32
6 files changed, 201 insertions, 81 deletions
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
index 3076415..e1e3baa 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDS.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDS.java
@@ -1,11 +1,19 @@
package bjc.utils.cli.fds;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStreamReader;
import java.io.PrintStream;
+import java.util.Collection;
import bjc.utils.cli.CommandHelp;
+import bjc.utils.cli.GenericHelp;
import bjc.utils.cli.fds.FDSState.InputMode;
import bjc.utils.ioutils.Block;
import bjc.utils.ioutils.BlockReader;
+import bjc.utils.ioutils.PushbackBlockReader;
+
+import static bjc.utils.ioutils.BlockReaders.*;
/**
* Runs a FDS (FDiskScript) interface.
@@ -19,21 +27,19 @@ import bjc.utils.ioutils.BlockReader;
*
*/
public class FDS {
+ private static SimpleFDSMode<?> miscMode;
+
+ static {
+ miscMode = new SimpleFDSMode<>();
+
+ miscMode.addCommand('X', (stat) -> {
+
+ }, new GenericHelp("load-script\tLoad a script from a file", ""));
+ }
+
/**
* Run a provided FDS mode until it is exited or there is no more input.
*
- * @param blockSource
- * The command input source for the FDS mode.
- *
- * @param datain
- * The data input source for the FDS mode.
- *
- * @param printer
- * The output source for the FDS mode.
- *
- * @param mode
- * The mode to start in.
- *
* @param state
* The initial state for the mode.
*
@@ -42,26 +48,26 @@ public class FDS {
* @throws FDSException
* If something went wrong during mode execution.
*/
- public static <S> S runFDS(BlockReader blockSource, BlockReader datain, PrintStream printer, FDSState<S> state)
- throws FDSException {
- while(blockSource.hasNext() && !state.modes.empty()) {
+ public static <S> S runFDS(FDSState<S> state) throws FDSException {
+ BlockReader blockSource = state.comin;
+
+ while (blockSource.hasNext() && !state.modes.empty()) {
Block comBlock = blockSource.next();
- handleCommandString(comBlock, blockSource, datain, printer, state);
+ handleCommandString(comBlock, state);
}
return state.state;
}
- private static <S> void handleCommandString(Block comBlock, BlockReader blockSource, BlockReader datain,
- PrintStream printer, FDSState<S> state) throws FDSException {
+ private static <S> void handleCommandString(Block comBlock, FDSState<S> state) throws FDSException {
String comString = comBlock.contents.trim();
- switch(state.mode) {
+ switch (state.mode) {
case CHORD:
chordCommand(comBlock, state, comString);
case NORMAL:
- handleCommand(comString.charAt(0), blockSource, datain, printer, state);
+ handleCommand(comString.charAt(0), state);
break;
case INLINE:
break;
@@ -73,39 +79,40 @@ public class FDS {
}
private static <S> void chordCommand(Block comBlock, FDSState<S> state, String comString) {
- for(int i = 1; i < comString.length(); i++) {
+ PushbackBlockReader source = state.comin;
+
+ for (int i = 1; i < comString.length(); i++) {
char c = comString.charAt(i);
Block newCom = new Block(comBlock.blockNo + 1, Character.toString(c), comBlock.startLine,
comBlock.startLine);
- state.enqueCommand.accept(newCom);
+ source.addBlock(newCom);
}
}
- private static <S> void handleCommand(char com, BlockReader blockSource, BlockReader datain,
- PrintStream printer, FDSState<S> state) throws FDSException {
- if(state.modes.empty()) return;
+ @SuppressWarnings("unchecked")
+ private static <S> void handleCommand(char com, FDSState<S> state) throws FDSException {
+ if (state.modes.empty()) return;
+
+ PrintStream printer = state.printer;
/*
* Handle built-in commands over user commands.
*/
- switch(com) {
+ switch (com) {
case 'x':
- if(state.mode == InputMode.CHORD) {
+ if (state.mode == InputMode.CHORD) {
state.mode = InputMode.NORMAL;
- } else if(state.mode == InputMode.NORMAL) {
+ } else if (state.mode == InputMode.NORMAL) {
state.mode = InputMode.CHORD;
} else {
printer.println("? CNV\n");
}
break;
case 'X':
- /*
- * TODO implement loading scripts from file.
- */
+ loadScript(state);
break;
-
case 'q':
state.modes.drop();
break;
@@ -115,28 +122,62 @@ public class FDS {
case 'm':
helpSummary(printer, state);
break;
+ case 'M':
+ /*
+ * We'll see if this cast actually causes any issues.
+ *
+ * None of the commands in misc. mode should depend on
+ * the state type, so it shouldn't matter.
+ */
+ state.modes.push((FDSMode<S>) miscMode);
+ break;
default:
FDSMode<S> curMode = state.modes.top();
- if(curMode.hasSubmode(com)) {
- curMode.getCommand(com).run(state.state, datain);
- } else if(curMode.hasCommand(com)) {
+ if (curMode.hasSubmode(com)) {
state.modes.push(curMode.getSubmode(com));
+ } else if (curMode.hasCommand(com)) {
+ curMode.getCommand(com).run(state);
} else {
printer.printf("? UBC '%s'\n", com);
}
}
}
+ private static <S> void loadScript(FDSState<S> state) {
+ String fileName = state.datain.next().contents.split(" ")[0];
+
+ PrintStream printer = state.printer;
+
+ try {
+ FileInputStream fis = new FileInputStream(fileName);
+
+ BlockReader reader = simple("\\R", new InputStreamReader(fis));
+
+ state.comin = pushback(serial(reader, state.comin));
+ state.datain = pushback(serial(reader, state.datain));
+ } catch (FileNotFoundException fnfex) {
+ printer.printf("? FNF '%s'\n", fileName);
+ }
+ }
+
private static <S> void helpSummary(PrintStream printer, FDSState<S> state) {
FDSMode<S> mode = state.modes.top();
printer.printf("Help for mode %s:\n", mode.getName());
- for(char bound : mode.registeredChars()) {
- CommandHelp help = mode.getHelp(bound);
-
- printer.printf("%s\t-\t%s", help.getSummary());
+ for (char bound : mode.registeredChars()) {
+ Collection<CommandHelp> help = mode.getHelp(bound);
+
+ if (help.size() > 1) {
+ for (CommandHelp hlp : help) {
+ printer.printf("%s\t-\t%s", hlp.getSummary());
+ }
+ } else {
+ CommandHelp hlp = help.iterator().next();
+
+ printer.printf("%s\t-\t%s", hlp.getSummary());
+ }
}
}
-}
+} \ No newline at end of file
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
index ddbb743..bb64cdf 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSCommand.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSCommand.java
@@ -1,7 +1,5 @@
package bjc.utils.cli.fds;
-import bjc.utils.ioutils.BlockReader;
-
/**
* A command attached to an FDS interface.
*
@@ -10,17 +8,13 @@ import bjc.utils.ioutils.BlockReader;
* @param <S>
* The state type of the interface.
*/
+@FunctionalInterface
public interface FDSCommand<S> {
/**
* 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, BlockReader input);
+ void run(FDSState<S> state);
}
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
index 29857e0..b59b345 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSMode.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSMode.java
@@ -1,5 +1,9 @@
package bjc.utils.cli.fds;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
import bjc.utils.cli.CommandHelp;
import bjc.utils.cli.NullHelp;
@@ -13,6 +17,11 @@ import bjc.utils.cli.NullHelp;
*/
public interface FDSMode<S> {
/**
+ * The default help for anything in a mode command.
+ */
+ public static final List<CommandHelp> DEFAULT_HELP = Arrays.asList(new NullHelp());
+
+ /**
* Get the name of this mode.
*
* @return The mode of this name.
@@ -97,7 +106,7 @@ public interface FDSMode<S> {
*
* @return The help for what's bound to the character.
*/
- default CommandHelp getHelp(char c) {
- return new NullHelp();
+ default Collection<CommandHelp> getHelp(char c) {
+ return DEFAULT_HELP;
}
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSState.java b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSState.java
index bef86ae..1627b11 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSState.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSState.java
@@ -1,10 +1,10 @@
package bjc.utils.cli.fds;
-import java.util.function.Consumer;
+import java.io.PrintStream;
import bjc.utils.esodata.SimpleStack;
import bjc.utils.esodata.Stack;
-import bjc.utils.ioutils.Block;
+import bjc.utils.ioutils.PushbackBlockReader;
/**
* Internal state for an FDS interface.
@@ -34,16 +34,16 @@ public class FDSState<S> {
CHORD,
/**
* Reads every character in the block, but after a terminal
- * command, data will be read in-line separated by spaces until a
- * semicolon is read.
+ * command, data will be read in-line separated by spaces until
+ * a semicolon is read.
*
* The semicolon can be escaped with a backslash.
*/
INLINE,
/**
* Reads every character in the block, but after a terminal
- * command, data will be read in-line with each character being a
- * separate item until a semicolon is read.
+ * command, data will be read in-line with each character being
+ * a separate item until a semicolon is read.
*
* The semicolon can be escaped with a backslash.
*/
@@ -65,14 +65,19 @@ public class FDSState<S> {
public Stack<FDSMode<S>> modes;
/**
- * Function to add a command block to be processed.
+ * The source to read command blocks from.
*/
- public Consumer<Block> enqueCommand;
+ public PushbackBlockReader comin;
/**
- * Function to add a data block to be processed.
+ * The source to read data blocks from.
*/
- public Consumer<Block> enqueData;
+ public PushbackBlockReader datain;
+
+ /**
+ * The destination for output.
+ */
+ public PrintStream printer;
/**
* Create a new interface state.
@@ -82,20 +87,24 @@ public class FDSState<S> {
*
* @param inputMode
* The input mode for the interface.
+ * @param cmin
+ * The source of command blocks.
*
- * @param comQueue
- * The function to call to add a command block.
+ * @param datin
+ * The source of data blocks.
*
- * @param dataQueue
- * The function to call to add a data block.
+ * @param print
+ * The destination for output.
*/
- public FDSState(S stat, InputMode inputMode, Consumer<Block> comQueue, Consumer<Block> dataQueue) {
+ public FDSState(S stat, InputMode inputMode, PushbackBlockReader cmin, PushbackBlockReader datin,
+ PrintStream print) {
state = stat;
mode = inputMode;
- modes = new SimpleStack<>();
+ comin = cmin;
+ datain = datin;
+ printer = print;
- enqueCommand = comQueue;
- enqueData = dataQueue;
+ modes = new SimpleStack<>();
}
} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSUtils.java b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSUtils.java
new file mode 100644
index 0000000..ec8cea8
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSUtils.java
@@ -0,0 +1,61 @@
+package bjc.utils.cli.fds;
+
+import static bjc.utils.ioutils.BlockReaders.pushback;
+import static bjc.utils.ioutils.BlockReaders.simple;
+import static bjc.utils.ioutils.BlockReaders.trigger;
+
+import java.io.PrintStream;
+import java.io.Reader;
+
+import bjc.utils.cli.fds.FDSState.InputMode;
+import bjc.utils.ioutils.BlockReader;
+import bjc.utils.ioutils.Prompter;
+import bjc.utils.ioutils.PushbackBlockReader;
+
+/**
+ * Utilities for dealing with FDS
+ *
+ * @author bjculkin
+ *
+ */
+public class FDSUtils {
+ /**
+ * Run a FDS instance from a reader.
+ *
+ * @param reader
+ * The reader to use.
+ *
+ * @param out
+ * The output stream to use.
+ *
+ * @param mode
+ * The mode to use.
+ *
+ * @param ctx
+ * The initial state.
+ *
+ * @return The final state.
+ *
+ * @throws FDSException
+ * If something goes wrong.
+ */
+ public static <S> S runFromReader(Reader reader, PrintStream out, FDSMode<S> mode, S ctx) throws FDSException {
+ BlockReader input = simple("\\R", reader);
+
+ Prompter comPrompter = new Prompter("Enter a command (m for help): ", out);
+ Prompter dataPrompter = new Prompter("> ", out);
+
+ BlockReader rawComInput = trigger(input, comPrompter);
+ BlockReader rawDataInput = trigger(input, dataPrompter);
+
+ PushbackBlockReader comInput = pushback(rawComInput);
+ PushbackBlockReader dataInput = pushback(rawDataInput);
+
+ FDSState<S> fdsState = new FDSState<>(ctx, InputMode.NORMAL, comInput, dataInput, out);
+ fdsState.modes.push(mode);
+
+ FDS.runFDS(fdsState);
+
+ return ctx;
+ }
+} \ No newline at end of file
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
index 2f6e660..1dceb3a 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/SimpleFDSMode.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/SimpleFDSMode.java
@@ -1,10 +1,14 @@
package bjc.utils.cli.fds;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+
import bjc.utils.cli.CommandHelp;
import static java.lang.String.format;
@@ -18,9 +22,9 @@ import static java.lang.String.format;
* The FDS state type.
*/
public class SimpleFDSMode<S> implements FDSMode<S> {
- private Map<Character, FDSCommand<S>> commands;
- private Map<Character, FDSMode<S>> modes;
- private Map<Character, CommandHelp> help;
+ private Map<Character, FDSCommand<S>> commands;
+ private Map<Character, FDSMode<S>> modes;
+ private Multimap<Character, CommandHelp> help;
private Set<Character> registered;
private char[] registeredArray;
@@ -32,7 +36,7 @@ public class SimpleFDSMode<S> implements FDSMode<S> {
public SimpleFDSMode() {
commands = new HashMap<>();
modes = new HashMap<>();
- help = new HashMap<>();
+ help = HashMultimap.create();
registered = new HashSet<>();
changed = true;
@@ -50,16 +54,17 @@ public class SimpleFDSMode<S> implements FDSMode<S> {
* @param hlp
* The help for the command.
*
- * @throws FDSException
+ * @throws IllegalArgumentException
* If the character is already bound to a command.
*/
- public void addCommand(char c, FDSCommand<S> comm, CommandHelp hlp) throws FDSException {
+ public void addCommand(char c, FDSCommand<S> comm, CommandHelp hlp) {
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"));
+ else if (commands.containsKey(c))
+ throw new IllegalArgumentException(format("Character '%s' is already bound"));
commands.put(c, comm);
+ help.put(c, hlp);
registered.add(c);
if (!changed) changed = true;
@@ -74,16 +79,17 @@ public class SimpleFDSMode<S> implements FDSMode<S> {
* @param mode
* The submode to add.
*
- * @throws FDSException
+ * @throws IllegalArgumentException
* If the character is already bound to a submode.
*/
- public void addSubmode(char c, FDSMode<S> mode) throws FDSException {
+ public void addSubmode(char c, FDSMode<S> mode, CommandHelp hlp) {
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"));
+ else if (modes.containsKey(c))
+ throw new IllegalArgumentException(format("Character '%s' is already bound"));
modes.put(c, mode);
+ help.put(c, hlp);
registered.add(c);
if (!changed) changed = true;
@@ -136,7 +142,7 @@ public class SimpleFDSMode<S> implements FDSMode<S> {
}
@Override
- public CommandHelp getHelp(char c) {
+ public Collection<CommandHelp> getHelp(char c) {
return help.get(c);
}
} \ No newline at end of file