summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main/java/bjc/utils
diff options
context:
space:
mode:
authorbjculkin <bjculkin@mix.wvu.edu>2017-03-28 16:48:43 -0400
committerbjculkin <bjculkin@mix.wvu.edu>2017-03-28 16:48:43 -0400
commitdaceafeeb90680116c289a7c301c42eb3e57eb97 (patch)
tree77e4656d7559bc84ff381fc95f285a41c4c7d867 /BJC-Utils2/src/main/java/bjc/utils
parent32041545ef34fa83aeea682d97be4ca9a94659f2 (diff)
Mostly finish FDS core
The major changes this time are that we have both data/command macros, as well as proper Unicode character support.
Diffstat (limited to 'BJC-Utils2/src/main/java/bjc/utils')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDS.java161
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSMode.java12
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSState.java54
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSUtils.java4
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/fds/MacroFDSMode.java79
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/fds/SimpleFDSMode.java73
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/funcutils/StringUtils.java38
7 files changed, 332 insertions, 89 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 59b673a..d94aae0 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
@@ -5,14 +5,20 @@ import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
import bjc.utils.cli.CommandHelp;
import bjc.utils.cli.GenericHelp;
import bjc.utils.cli.fds.FDSState.InputMode;
+import bjc.utils.funcutils.StringUtils;
import bjc.utils.ioutils.Block;
import bjc.utils.ioutils.BlockReader;
import bjc.utils.ioutils.PushbackBlockReader;
+import com.ibm.icu.text.BreakIterator;
+
import static bjc.utils.ioutils.BlockReaders.*;
/**
@@ -30,24 +36,66 @@ public class FDS {
private static SimpleFDSMode<?> miscMode;
static {
- miscMode = new SimpleFDSMode<>();
+ miscMode = new SimpleFDSMode<>("MSC");
+ configureMiscMode();
+ }
+ private static void configureMiscMode() {
GenericHelp loadScriptHelp = new GenericHelp("load-script\tLoad a script from a file", "");
- miscMode.addCommand('X', FDS::loadScript, loadScriptHelp);
+ miscMode.addCommand("X", FDS::loadScript, loadScriptHelp);
GenericHelp quitProgramHelp = new GenericHelp("quit-program\tQuit the program", "");
- miscMode.addCommand('Q', (state) -> state.modes.drop(state.modes.size()), quitProgramHelp);
+ miscMode.addCommand("Q", (state) -> state.modes.drop(state.modes.size()), quitProgramHelp);
- GenericHelp inlineInputHelp = new GenericHelp("", "");
- miscMode.addCommand('I', (state) -> {
- if (state.mode == InputMode.CHORD) {
+ GenericHelp inlineInputHelp = new GenericHelp("inline-input\tProvide data input inline with commands",
+ "");
+ miscMode.addCommand("I", (state) -> {
+ if(state.mode == InputMode.CHORD) {
state.mode = InputMode.INLINE;
- } else if (state.mode == InputMode.INLINE) {
+ } else if(state.mode == InputMode.INLINE) {
state.mode = InputMode.CHORD;
} else {
state.printer.printf("? MNV\n");
}
}, inlineInputHelp);
+
+ GenericHelp dataMacroHelp = new GenericHelp("input-macro\tDefine a macro for providing data", "");
+ miscMode.addCommand("i", (state) -> createMacro(state, state.dataMacros), dataMacroHelp);
+
+ GenericHelp comMacroHelp = new GenericHelp("command-macro\tDefine a macro for providing commands", "");
+ miscMode.addCommand("c", (state) -> createMacro(state, state.commandMacros), comMacroHelp);
+ }
+
+ private static void createMacro(FDSState<?> state, Map<String, List<Block>> macroStore) {
+ PushbackBlockReader source = state.datain;
+
+ String macroName;
+ List<Block> macroBody = new LinkedList<>();
+
+ state.dataPrompter.accept("Enter macro name: ");
+ Block blk = source.next();
+
+ String blkContents = blk.contents.trim();
+
+ BreakIterator charBreaker = BreakIterator.getCharacterInstance();
+ charBreaker.setText(blkContents);
+
+ macroName = blkContents.substring(0, charBreaker.next());
+
+ state.dataPrompter.accept("Enter macro body (. to end body)");
+ while(source.hasNext()) {
+ blk = source.next();
+
+ blkContents = blk.contents.trim();
+
+ if(blkContents.equals(".")) break;
+
+ macroBody.add(new Block(blk.blockNo, blkContents, blk.startLine, blk.endLine));
+ }
+
+ macroStore.put(macroName, macroBody);
+
+ state.dataPrompter.accept(state.defaultPrompt);
}
/**
@@ -64,7 +112,7 @@ public class FDS {
public static <S> S runFDS(FDSState<S> state) throws FDSException {
BlockReader blockSource = state.comin;
- while (blockSource.hasNext() && !state.modes.empty()) {
+ while(blockSource.hasNext() && !state.modes.empty()) {
Block comBlock = blockSource.next();
handleCommandString(comBlock, state);
@@ -75,22 +123,22 @@ public class FDS {
private static <S> void handleCommandString(Block comBlock, FDSState<S> state) throws FDSException {
String comString = comBlock.contents.trim();
+ BreakIterator charBreaker = BreakIterator.getCharacterInstance();
+ charBreaker.setText(comString);
- switch (state.mode) {
+ switch(state.mode) {
case INLINE:
- if (comString.contains(" ")) {
+ if(comString.contains(" ")) {
handleInlineCommand(comString.split(" "), state, comBlock);
break;
}
case CHORD:
- if (comString.length() > 1) {
+ if(StringUtils.graphemeCount(comString) > 1) {
chordCommand(comBlock, state, comString);
break;
}
case NORMAL:
- handleCommand(comString.charAt(0), state);
- break;
- case CHARINLINE:
+ handleCommand(comString.substring(0, charBreaker.next()), state);
break;
default:
throw new FDSException(String.format("Unknown input mode '%s'", state.mode));
@@ -101,11 +149,11 @@ public class FDS {
throws FDSException {
boolean dataInput = false;
- for (int i = 0; i < commands.length; i++) {
+ for(int i = 0; i < commands.length; i++) {
String strang = commands[i].trim();
- if (dataInput) {
- if (strang.equals(";")) {
+ if(dataInput) {
+ if(strang.equals(";")) {
dataInput = false;
} else {
Block dataBlock = new Block(comBlock.blockNo + i, strang, comBlock.startLine,
@@ -124,42 +172,49 @@ public class FDS {
private static <S> void chordCommand(Block comBlock, FDSState<S> state, String comString) throws FDSException {
PushbackBlockReader source = state.comin;
- for (int i = 0; i < comString.length(); i++) {
- char c = comString.charAt(i);
+ BreakIterator charBreaker = BreakIterator.getCharacterInstance();
+ charBreaker.setText(comString);
- Block newCom = new Block(comBlock.blockNo + 1, Character.toString(c), comBlock.startLine,
- comBlock.startLine);
+ int lastPos = charBreaker.first();
+
+ while(charBreaker.next() != BreakIterator.DONE && lastPos < comString.length()) {
+ String c = comString.substring(lastPos, charBreaker.current());
+
+ Block newCom = new Block(comBlock.blockNo + 1, c, comBlock.startLine, comBlock.startLine);
source.addBlock(newCom);
+
+ lastPos = charBreaker.current();
}
}
@SuppressWarnings("unchecked")
- private static <S> void handleCommand(char com, FDSState<S> state) throws FDSException {
- if (state.modes.empty()) return;
+ private static <S> void handleCommand(String com, FDSState<S> state) throws FDSException {
+ if(state.modes.empty()) return;
PrintStream printer = state.printer;
/*
* Handle built-in commands over user commands.
*/
- switch (com) {
- case 'x':
- if (state.mode == InputMode.CHORD) {
+ switch(com) {
+ case "x":
+ 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("? MNV\n");
}
break;
- case 'q':
- state.modes.drop();
+ case "q":
+ FDSMode<S> md = state.modes.pop();
+ printer.printf("!< %s\n", md.getName());
break;
- case 'm':
+ case "m":
helpSummary(printer, state);
break;
- case 'M':
+ case "M":
/*
* We'll see if this cast actually causes any issues.
*
@@ -167,13 +222,25 @@ public class FDS {
* the state type, so it shouldn't matter.
*/
state.modes.push((FDSMode<S>) miscMode);
+ printer.printf("!> MSC\n");
+ break;
+ case "@":
+ state.modes.push(state.dataMacroMode);
+ printer.printf("!> IDM\n");
+ break;
+ case "#":
+ state.modes.push(state.comMacroMode);
+ printer.printf("!> ICM\n");
break;
default:
FDSMode<S> curMode = state.modes.top();
- if (curMode.hasSubmode(com)) {
- state.modes.push(curMode.getSubmode(com));
- } else if (curMode.hasCommand(com)) {
+ if(curMode.hasSubmode(com)) {
+ FDSMode<S> mode = curMode.getSubmode(com);
+
+ state.modes.push(mode);
+ printer.printf("!> %s\n", mode.getName());
+ } else if(curMode.hasCommand(com)) {
curMode.getCommand(com).run(state);
} else {
printer.printf("? UBC '%s'\n", com);
@@ -182,6 +249,8 @@ public class FDS {
}
private static <S> void loadScript(FDSState<S> state) {
+ state.dataPrompter.accept("Enter a filename: ");
+
String fileName = state.datain.next().contents.split(" ")[0];
PrintStream printer = state.printer;
@@ -193,9 +262,11 @@ public class FDS {
state.comin = pushback(serial(reader, state.comin));
state.datain = pushback(serial(reader, state.datain));
- } catch (FileNotFoundException fnfex) {
+ } catch(FileNotFoundException fnfex) {
printer.printf("? FNF '%s'\n", fileName);
}
+
+ state.dataPrompter.accept(state.defaultPrompt);
}
private static <S> void helpSummary(PrintStream printer, FDSState<S> state) {
@@ -203,18 +274,28 @@ public class FDS {
printer.printf("Help for mode %s:\n", mode.getName());
- for (char bound : mode.registeredChars()) {
+ for(String 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());
+ if(help.size() > 1) {
+ for(CommandHelp hlp : help) {
+ printer.printf("\t%s\t- %s\n", bound, hlp.getSummary());
}
+
+ printer.println();
} else {
CommandHelp hlp = help.iterator().next();
- printer.printf("%s\t-\t%s", hlp.getSummary());
+ printer.printf("\t%s\t- %s\n", bound, hlp.getSummary());
}
}
+
+ printer.printf("\nHelp for global commands:\n");
+ printer.printf("\tx\t- chord mode\tread each character as a seperate command\n");
+ printer.printf("\tq\t- exit mode\texit the current submode\n");
+ printer.printf("\tm\t- show help\tshow this help message\n");
+ printer.printf("\tM\t- misc. mode\tsubmode with misc. commands\n");
+ printer.printf("\t@\t- invoke data macro\tinvoke bound data macros\n");
+ printer.printf("\t#\t- invoke command macro\tinvoke bound command macros\n\n");
}
} \ No newline at end of file
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 b59b345..60aeb38 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
@@ -37,7 +37,7 @@ public interface FDSMode<S> {
*
* @return All of the characters registered to something in this mode.
*/
- char[] registeredChars();
+ String[] registeredChars();
/*
* Check for the existence of commands/submodes.
@@ -51,7 +51,7 @@ public interface FDSMode<S> {
*
* @return Whether or not there is a command bound to that character.
*/
- boolean hasCommand(char c);
+ boolean hasCommand(String c);
/**
* Check if there is a submode registered to the given character.
@@ -61,7 +61,7 @@ public interface FDSMode<S> {
*
* @return Whether or not there is a submode bound to that character.
*/
- boolean hasSubmode(char c);
+ boolean hasSubmode(String c);
/*
* Get commands and submodes.
@@ -78,7 +78,7 @@ public interface FDSMode<S> {
* @throws FDSException
* If there is no command bound to that character.
*/
- FDSCommand<S> getCommand(char c) throws FDSException;
+ FDSCommand<S> getCommand(String c) throws FDSException;
/**
* Get the command attached to a given character.
@@ -91,7 +91,7 @@ public interface FDSMode<S> {
* @throws FDSException
* If there is no command bound to that character.
*/
- FDSMode<S> getSubmode(char c) throws FDSException;
+ FDSMode<S> getSubmode(String c) throws FDSException;
/*
* Help utilities
@@ -106,7 +106,7 @@ public interface FDSMode<S> {
*
* @return The help for what's bound to the character.
*/
- default Collection<CommandHelp> getHelp(char c) {
+ default Collection<CommandHelp> getHelp(String 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 1627b11..e28e6bc 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,9 +1,14 @@
package bjc.utils.cli.fds;
import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
import bjc.utils.esodata.SimpleStack;
import bjc.utils.esodata.Stack;
+import bjc.utils.ioutils.Block;
import bjc.utils.ioutils.PushbackBlockReader;
/**
@@ -39,15 +44,7 @@ public class FDSState<S> {
*
* 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.
- *
- * The semicolon can be escaped with a backslash.
- */
- CHARINLINE,
+ INLINE;
}
/**
@@ -80,6 +77,29 @@ public class FDSState<S> {
public PrintStream printer;
/**
+ * The repository for data macros.
+ */
+ public Map<String, List<Block>> dataMacros;
+
+ /**
+ * The repository for command macros.
+ */
+ public Map<String, List<Block>> commandMacros;
+
+ FDSMode<S> dataMacroMode;
+ FDSMode<S> comMacroMode;
+
+ /**
+ * Function to change the current data prompt.
+ */
+ public Consumer<String> dataPrompter;
+
+ /**
+ * The default data prompt.
+ */
+ public String defaultPrompt;
+
+ /**
* Create a new interface state.
*
* @param stat
@@ -95,9 +115,14 @@ public class FDSState<S> {
*
* @param print
* The destination for output.
+ * @param dataPrompt
+ * The function to use for changing the data prompt.
+ *
+ * @param normalPrompt
+ * The default data prompt.
*/
public FDSState(S stat, InputMode inputMode, PushbackBlockReader cmin, PushbackBlockReader datin,
- PrintStream print) {
+ PrintStream print, Consumer<String> dataPrompt, String normalPrompt) {
state = stat;
mode = inputMode;
@@ -105,6 +130,15 @@ public class FDSState<S> {
datain = datin;
printer = print;
+ dataPrompter = dataPrompt;
+ defaultPrompt = normalPrompt;
+
modes = new SimpleStack<>();
+
+ dataMacros = new HashMap<>();
+ commandMacros = new HashMap<>();
+
+ dataMacroMode = new MacroFDSMode<>(dataMacros, datain::addBlock);
+ comMacroMode = new MacroFDSMode<>(commandMacros, comin::addBlock);
}
} \ 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
index f071671..a245471 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSUtils.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/FDSUtils.java
@@ -51,7 +51,9 @@ public class FDSUtils {
PushbackBlockReader comInput = pushback(rawComInput);
PushbackBlockReader dataInput = pushback(rawDataInput);
- FDSState<S> fdsState = new FDSState<>(ctx, InputMode.INLINE, comInput, dataInput, out);
+ FDSState<S> fdsState = new FDSState<>(ctx, InputMode.NORMAL, comInput, dataInput, out,
+ dataPrompter::setPrompt, "> ");
+
fdsState.modes.push(mode);
FDS.runFDS(fdsState);
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/fds/MacroFDSMode.java b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/MacroFDSMode.java
new file mode 100644
index 0000000..2576ee5
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/fds/MacroFDSMode.java
@@ -0,0 +1,79 @@
+package bjc.utils.cli.fds;
+
+import bjc.utils.ioutils.Block;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+/**
+ * A implementation of FDS mode that invokes macros bound into a map.
+ *
+ * @author EVE
+ *
+ * @param <S>
+ * The FDS state type.
+ */
+public class MacroFDSMode<S> implements FDSMode<S> {
+ private final class MacroFDSCommand implements FDSCommand<S> {
+ private String macroName;
+
+ public MacroFDSCommand(String c) {
+ macroName = c;
+ }
+
+ @Override
+ public void run(FDSState<S> state) {
+ macros.get(macroName).forEach(dest);
+ }
+ }
+
+ /*
+ * The available macros.
+ */
+ private Map<String, List<Block>> macros;
+
+ /*
+ * Where to send blocks from macros.
+ */
+ private Consumer<Block> dest;
+
+ /**
+ * Create a new FDS mode for macros.
+ *
+ * @param macros
+ * The macros to use.
+ *
+ * @param dest
+ * The destination for blocks from the macros.
+ */
+ public MacroFDSMode(Map<String, List<Block>> macros, Consumer<Block> dest) {
+ this.macros = macros;
+ this.dest = dest;
+ }
+
+ @Override
+ public String[] registeredChars() {
+ return macros.keySet().toArray(new String[0]);
+ }
+
+ @Override
+ public boolean hasCommand(String comName) {
+ return macros.containsKey(comName);
+ }
+
+ @Override
+ public boolean hasSubmode(String submodeName) {
+ return false;
+ }
+
+ @Override
+ public FDSCommand<S> getCommand(String comName) throws FDSException {
+ return new MacroFDSCommand(comName);
+ }
+
+ @Override
+ public FDSMode<S> getSubmode(String submodeName) throws FDSException {
+ throw new FDSException("Submodes aren't available in macroName modes");
+ }
+} \ 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 1dceb3a..8854d8e 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
@@ -22,14 +22,16 @@ 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 Multimap<Character, CommandHelp> help;
+ private Map<String, FDSCommand<S>> commands;
+ private Map<String, FDSMode<S>> modes;
+ private Multimap<String, CommandHelp> help;
- private Set<Character> registered;
- private char[] registeredArray;
+ private Set<String> registered;
+ private String[] registeredArray;
private boolean changed;
+ private String modeName;
+
/**
* Create a new empty FDS mode.
*/
@@ -43,6 +45,26 @@ public class SimpleFDSMode<S> implements FDSMode<S> {
}
/**
+ * Create a new empty mode with a given name.
+ *
+ * @param name
+ * The name of the mode.
+ */
+ public SimpleFDSMode(String name) {
+ this();
+
+ modeName = name;
+ }
+
+ @Override
+ public String getName() {
+ if(modeName == null)
+ return FDSMode.super.getName();
+ else
+ return modeName;
+ }
+
+ /**
* Add a command to the mode.
*
* @param c
@@ -57,17 +79,17 @@ public class SimpleFDSMode<S> implements FDSMode<S> {
* @throws IllegalArgumentException
* If the character is already bound to a command.
*/
- public void addCommand(char c, FDSCommand<S> comm, CommandHelp hlp) {
- if (comm == null)
+ public void addCommand(String c, FDSCommand<S> comm, CommandHelp hlp) {
+ if(comm == null)
throw new NullPointerException("Command must not be null");
- else if (commands.containsKey(c))
+ 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;
+ if(!changed) changed = true;
}
/**
@@ -79,30 +101,33 @@ public class SimpleFDSMode<S> implements FDSMode<S> {
* @param mode
* The submode to add.
*
+ * @param hlp
+ * The help for the submode.
+ *
* @throws IllegalArgumentException
* If the character is already bound to a submode.
*/
- public void addSubmode(char c, FDSMode<S> mode, CommandHelp hlp) {
- if (mode == null)
+ public void addSubmode(String c, FDSMode<S> mode, CommandHelp hlp) {
+ if(mode == null)
throw new NullPointerException("Mode must not be null");
- else if (modes.containsKey(c))
+ 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;
+ if(!changed) changed = true;
}
@Override
- public char[] registeredChars() {
- if (!changed) return registeredArray;
+ public String[] registeredChars() {
+ if(!changed) return registeredArray;
- registeredArray = new char[registered.size()];
+ registeredArray = new String[registered.size()];
int i = 0;
- for (char c : registered) {
+ for(String c : registered) {
registeredArray[i] = c;
i += 1;
@@ -114,18 +139,18 @@ public class SimpleFDSMode<S> implements FDSMode<S> {
}
@Override
- public boolean hasCommand(char c) {
+ public boolean hasCommand(String c) {
return commands.containsKey(c);
}
@Override
- public boolean hasSubmode(char c) {
+ public boolean hasSubmode(String c) {
return modes.containsKey(c);
}
@Override
- public FDSCommand<S> getCommand(char c) throws FDSException {
- if (!commands.containsKey(c)) {
+ public FDSCommand<S> getCommand(String c) throws FDSException {
+ if(!commands.containsKey(c)) {
throw new FDSException(String.format("No command bound to '%s'", c));
}
@@ -133,8 +158,8 @@ public class SimpleFDSMode<S> implements FDSMode<S> {
}
@Override
- public FDSMode<S> getSubmode(char c) throws FDSException {
- if (!modes.containsKey(c)) {
+ public FDSMode<S> getSubmode(String c) throws FDSException {
+ if(!modes.containsKey(c)) {
throw new FDSException(String.format("No mode bound to '%s'", c));
}
@@ -142,7 +167,7 @@ public class SimpleFDSMode<S> implements FDSMode<S> {
}
@Override
- public Collection<CommandHelp> getHelp(char c) {
+ public Collection<CommandHelp> getHelp(String c) {
return help.get(c);
}
} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcutils/StringUtils.java b/BJC-Utils2/src/main/java/bjc/utils/funcutils/StringUtils.java
index a35253a..540fb39 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/funcutils/StringUtils.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/StringUtils.java
@@ -1,5 +1,7 @@
package bjc.utils.funcutils;
+import com.ibm.icu.text.BreakIterator;
+
import java.util.Deque;
/**
@@ -22,9 +24,9 @@ public class StringUtils {
* of the provided regex
*/
public static boolean containsOnly(String input, String regex) {
- if (input == null)
+ if(input == null)
throw new NullPointerException("Input must not be null");
- else if (regex == null) throw new NullPointerException("Regex must not be null");
+ else if(regex == null) throw new NullPointerException("Regex must not be null");
/*
* This regular expression is fairly simple.
@@ -46,7 +48,7 @@ public class StringUtils {
* The number of levels to indent
*/
public static void indentNLevels(StringBuilder builder, int levels) {
- for (int i = 0; i < levels; i++) {
+ for(int i = 0; i < levels; i++) {
builder.append("\t");
}
}
@@ -80,7 +82,7 @@ public class StringUtils {
* @return The sequence as an English list.
*/
public static String toEnglishList(Object[] objects, String join, String comma) {
- if (objects == null) {
+ if(objects == null) {
throw new NullPointerException("Sequence must not be null");
}
@@ -89,7 +91,7 @@ public class StringUtils {
String joiner = join;
String coma = comma;
- switch (objects.length) {
+ switch(objects.length) {
case 0:
/*
* Empty list.
@@ -113,7 +115,7 @@ public class StringUtils {
/*
* Three or more items.
*/
- for (int i = 0; i < objects.length - 1; i++) {
+ for(int i = 0; i < objects.length - 1; i++) {
sb.append(objects[i].toString());
sb.append(coma + " ");
}
@@ -157,10 +159,30 @@ public class StringUtils {
* @return The sequence as an English list.
*/
public static String toEnglishList(Object[] objects, boolean and) {
- if (and) {
+ if(and) {
return toEnglishList(objects, "and");
} else {
return toEnglishList(objects, "or");
}
}
-}
+
+ /**
+ * Count the number of graphemes in a string.
+ *
+ * @param value
+ * The string to check.
+ *
+ * @return The number of graphemes in the string.
+ */
+ public static int graphemeCount(String value) {
+ BreakIterator it = BreakIterator.getCharacterInstance();
+ it.setText(value);
+
+ int count = 0;
+ while(it.next() != BreakIterator.DONE) {
+ count++;
+ }
+
+ return count;
+ }
+} \ No newline at end of file