1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
package bjc.utils.cli.fds;
import java.io.PrintStream;
import bjc.utils.cli.CommandHelp;
import bjc.utils.cli.fds.FDSState.InputMode;
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 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.
*
* @return The final state of the mode.
*
* @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()) {
Block comBlock = blockSource.next();
handleCommandString(comBlock, blockSource, datain, printer, state);
}
return state.state;
}
private static <S> void handleCommandString(Block comBlock, BlockReader blockSource, BlockReader datain,
PrintStream printer, FDSState<S> state) throws FDSException {
String comString = comBlock.contents.trim();
switch(state.mode) {
case CHORD:
chordCommand(comBlock, state, comString);
case NORMAL:
handleCommand(comString.charAt(0), blockSource, datain, printer, state);
break;
case INLINE:
break;
case CHARINLINE:
break;
default:
throw new FDSException(String.format("Unknown input mode '%s'", state.mode));
}
}
private static <S> void chordCommand(Block comBlock, FDSState<S> state, String comString) {
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);
}
}
private static <S> void handleCommand(char com, BlockReader blockSource, BlockReader datain,
PrintStream printer, FDSState<S> state) throws FDSException {
if(state.modes.empty()) return;
/*
* Handle built-in commands over user commands.
*/
switch(com) {
case 'x':
if(state.mode == InputMode.CHORD) {
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.
*/
break;
case 'q':
state.modes.drop();
break;
case 'Q':
state.modes.drop(state.modes.size());
break;
case 'm':
helpSummary(printer, state);
break;
default:
FDSMode<S> curMode = state.modes.top();
if(curMode.hasSubmode(com)) {
curMode.getCommand(com).run(state.state, datain);
} else if(curMode.hasCommand(com)) {
state.modes.push(curMode.getSubmode(com));
} else {
printer.printf("? UBC '%s'\n", com);
}
}
}
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());
}
}
}
|