diff options
Diffstat (limited to 'BJC-Utils2')
7 files changed, 204 insertions, 112 deletions
diff --git a/BJC-Utils2/src/examples/java/bjc/utils/examples/cli/FDSExample.java b/BJC-Utils2/src/examples/java/bjc/utils/examples/cli/FDSExample.java index f9cf08e..e01e87e 100644 --- a/BJC-Utils2/src/examples/java/bjc/utils/examples/cli/FDSExample.java +++ b/BJC-Utils2/src/examples/java/bjc/utils/examples/cli/FDSExample.java @@ -2,16 +2,10 @@ package bjc.utils.examples.cli; import java.io.InputStreamReader; -import bjc.utils.cli.fds.FDS; import bjc.utils.cli.fds.FDSException; import bjc.utils.cli.fds.FDSMode; -import bjc.utils.cli.fds.FDSState; +import bjc.utils.cli.fds.FDSUtils; import bjc.utils.cli.fds.SimpleFDSMode; -import bjc.utils.cli.fds.FDSState.InputMode; -import bjc.utils.ioutils.BlockReader; -import bjc.utils.ioutils.PushbackBlockReader; - -import static bjc.utils.ioutils.BlockReaders.*; /** * Simple example for FDS. @@ -20,18 +14,11 @@ import static bjc.utils.ioutils.BlockReaders.*; * */ public class FDSExample { - private static final class Prompter implements Runnable { - @Override - public void run() { - System.out.print("Enter a command (m to exit): "); - } - } - /** * Main method. * * @param args - * Unused CLI arguments. + * Unused CLI arguments. */ public static void main(String[] args) { System.out.println("Entering rudimentary FDS"); @@ -43,22 +30,7 @@ public class FDSExample { InputStreamReader reader = new InputStreamReader(System.in); try { - BlockReader input = simple("\\R", reader); - - Prompter comPrompter = new Prompter(); - Prompter dataPrompter = new Prompter(); - - BlockReader rawComInput = trigger(input, comPrompter); - BlockReader rawDataInput = trigger(input, dataPrompter); - - PushbackBlockReader comInput = pushback(rawComInput); - PushbackBlockReader dataInput = pushback(rawDataInput); - - FDSState<TestContext> fdsState = new FDSState<>(ctx, InputMode.CHORD, comInput::addBlock, - dataInput::addBlock); - fdsState.modes.push(testMode); - - FDS.runFDS(comInput, dataInput, System.out, fdsState); + FDSUtils.runFromReader(reader, System.out, testMode, ctx); } catch (FDSException fex) { fex.printStackTrace(); } 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 |
