@wq2/brigadier-ts 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/Command.d.ts +1 -1
- package/dist/CommandDispatcher.d.ts +1 -1
- package/dist/CommandDispatcher.js +231 -357
- package/dist/ParseResults.d.ts +1 -1
- package/dist/ParseResults.js +9 -10
- package/dist/StringReader.d.ts +1 -1
- package/dist/StringReader.js +75 -77
- package/dist/arguments/ArgumentType.d.ts +1 -1
- package/dist/arguments/ArgumentType.js +9 -8
- package/dist/arguments/BoolArgumentType.d.ts +5 -1
- package/dist/arguments/BoolArgumentType.js +9 -27
- package/dist/arguments/FloatArgumentType.d.ts +1 -1
- package/dist/arguments/FloatArgumentType.js +11 -30
- package/dist/arguments/IntegerArgumentType.d.ts +1 -1
- package/dist/arguments/IntegerArgumentType.js +11 -30
- package/dist/arguments/LongArgumentType.d.ts +3 -3
- package/dist/arguments/LongArgumentType.js +13 -32
- package/dist/arguments/NumberArgumentType.d.ts +2 -2
- package/dist/arguments/NumberArgumentType.js +15 -33
- package/dist/arguments/StringArgumentType.d.ts +1 -1
- package/dist/arguments/StringArgumentType.js +11 -29
- package/dist/builder/ArgumentBuilder.d.ts +1 -1
- package/dist/builder/ArgumentBuilder.js +31 -71
- package/dist/builder/LiteralArgumentBuilder.js +14 -33
- package/dist/builder/RequiredArgumentBuilder.d.ts +1 -1
- package/dist/builder/RequiredArgumentBuilder.js +18 -37
- package/dist/context/CommandContext.d.ts +1 -1
- package/dist/context/CommandContext.js +31 -32
- package/dist/context/CommandContextBuilder.d.ts +1 -1
- package/dist/context/CommandContextBuilder.js +47 -50
- package/dist/context/ParsedArgument.js +8 -9
- package/dist/context/ParsedCommandNode.d.ts +1 -1
- package/dist/context/ParsedCommandNode.js +7 -8
- package/dist/context/StringRange.js +17 -18
- package/dist/context/SuggestionContext.d.ts +1 -1
- package/dist/context/SuggestionContext.js +3 -4
- package/dist/exceptions/CommandErrorType.d.ts +3 -3
- package/dist/exceptions/CommandErrorType.js +10 -19
- package/dist/exceptions/CommandSyntaxError.js +36 -54
- package/dist/suggestion/Suggestion.d.ts +1 -1
- package/dist/suggestion/Suggestion.js +16 -17
- package/dist/suggestion/Suggestions.d.ts +1 -1
- package/dist/suggestion/Suggestions.js +28 -30
- package/dist/suggestion/SuggestionsBuilder.d.ts +1 -1
- package/dist/suggestion/SuggestionsBuilder.js +22 -23
- package/dist/tree/ArgumentCommandNode.d.ts +1 -1
- package/dist/tree/ArgumentCommandNode.js +22 -40
- package/dist/tree/CommandNode.d.ts +1 -1
- package/dist/tree/CommandNode.js +28 -29
- package/dist/tree/LiteralCommandNode.d.ts +1 -1
- package/dist/tree/LiteralCommandNode.js +28 -41
- package/dist/tree/RootCommandNode.d.ts +1 -1
- package/dist/tree/RootCommandNode.js +17 -69
- package/jest.config.js +5 -5
- package/package.json +32 -32
- package/src/Command.ts +2 -1
- package/src/CommandDispatcher.ts +397 -295
- package/src/ParseResults.ts +26 -22
- package/src/StringReader.ts +212 -193
- package/src/arguments/ArgumentType.ts +13 -8
- package/src/arguments/BoolArgumentType.ts +22 -21
- package/src/arguments/FloatArgumentType.ts +13 -14
- package/src/arguments/IntegerArgumentType.ts +13 -14
- package/src/arguments/LongArgumentType.ts +16 -17
- package/src/arguments/NumberArgumentType.ts +48 -38
- package/src/arguments/StringArgumentType.ts +26 -26
- package/src/builder/ArgumentBuilder.ts +80 -75
- package/src/builder/LiteralArgumentBuilder.ts +31 -21
- package/src/builder/RequiredArgumentBuilder.ts +42 -32
- package/src/context/CommandContext.ts +99 -76
- package/src/context/CommandContextBuilder.ts +169 -143
- package/src/context/ParsedArgument.ts +13 -13
- package/src/context/ParsedCommandNode.ts +14 -14
- package/src/context/StringRange.ts +26 -26
- package/src/context/SuggestionContext.ts +7 -7
- package/src/exceptions/CommandErrorType.ts +20 -13
- package/src/exceptions/CommandSyntaxError.ts +78 -37
- package/src/index.ts +30 -30
- package/src/suggestion/Suggestion.ts +46 -46
- package/src/suggestion/Suggestions.ts +59 -57
- package/src/suggestion/SuggestionsBuilder.ts +59 -57
- package/src/tree/ArgumentCommandNode.ts +51 -40
- package/src/tree/CommandNode.ts +96 -87
- package/src/tree/LiteralCommandNode.ts +78 -57
- package/src/tree/RootCommandNode.ts +33 -23
- package/test/Arguments.test.ts +47 -33
- package/test/CommandDispatcher.test.ts +18 -22
- package/test/StringReader.test.ts +47 -47
- package/tsconfig.json +9 -14
package/src/CommandDispatcher.ts
CHANGED
|
@@ -1,300 +1,402 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
RootCommandNode,
|
|
3
|
+
type LiteralCommandNode,
|
|
4
|
+
StringReader,
|
|
5
|
+
type LiteralArgumentBuilder,
|
|
6
|
+
CommandContextBuilder,
|
|
7
|
+
type CommandNode,
|
|
8
|
+
ParseResults,
|
|
9
|
+
CommandSyntaxError,
|
|
10
|
+
Suggestions,
|
|
11
|
+
SuggestionsBuilder,
|
|
12
12
|
} from ".";
|
|
13
13
|
|
|
14
14
|
export class CommandDispatcher<S> {
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
15
|
+
private root: RootCommandNode<S>;
|
|
16
|
+
|
|
17
|
+
private static USAGE_OPTIONAL_OPEN = "[";
|
|
18
|
+
private static USAGE_OPTIONAL_CLOSE = "]";
|
|
19
|
+
private static USAGE_REQUIRED_OPEN = "(";
|
|
20
|
+
private static USAGE_REQUIRED_CLOSE = ")";
|
|
21
|
+
private static USAGE_OR = "|";
|
|
22
|
+
|
|
23
|
+
constructor() {
|
|
24
|
+
this.root = new RootCommandNode();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
register(command: LiteralArgumentBuilder<S>): LiteralCommandNode<S> {
|
|
28
|
+
const build = command.build();
|
|
29
|
+
this.root.addChild(build);
|
|
30
|
+
return build;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async execute(parse: ParseResults<S> | string, source: S): Promise<number> {
|
|
34
|
+
if (typeof parse === "string") {
|
|
35
|
+
parse = await this.parse(new StringReader(parse), source);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (parse.getReader().canRead()) {
|
|
39
|
+
if (parse.getErrors().size === 1) {
|
|
40
|
+
throw parse.getErrors().values().next();
|
|
41
|
+
} else if (parse.getContext().getRange().isEmpty()) {
|
|
42
|
+
throw CommandSyntaxError.DISPATCHER_UNKNOWN_COMMAND.createWithContext(
|
|
43
|
+
parse.getReader(),
|
|
44
|
+
);
|
|
45
|
+
} else {
|
|
46
|
+
throw CommandSyntaxError.DISPATCHER_UNKNOWN_ARGUMENT.createWithContext(
|
|
47
|
+
parse.getReader(),
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let result = 0;
|
|
53
|
+
let successfulForks = 0;
|
|
54
|
+
let forked = false;
|
|
55
|
+
let foundCommand = false;
|
|
56
|
+
const command = parse.getReader().getString();
|
|
57
|
+
const original = parse.getContext().build(command);
|
|
58
|
+
let contexts = [original];
|
|
59
|
+
let next = [];
|
|
60
|
+
|
|
61
|
+
while (contexts.length > 0) {
|
|
62
|
+
const size = contexts.length;
|
|
63
|
+
for (let i = 0; i < size; i++) {
|
|
64
|
+
const context = contexts[i];
|
|
65
|
+
const child = context.getChild();
|
|
66
|
+
if (child !== null) {
|
|
67
|
+
forked = forked || context.isForked();
|
|
68
|
+
if (child.hasNodes()) {
|
|
69
|
+
foundCommand = true;
|
|
70
|
+
const modifier = context.getRedirectModifier();
|
|
71
|
+
if (modifier === null) {
|
|
72
|
+
next.push(child.copyFor(context.getSource()));
|
|
73
|
+
} else {
|
|
74
|
+
try {
|
|
75
|
+
const results = <S[]>modifier(context);
|
|
76
|
+
results.forEach((source) => {
|
|
77
|
+
next.push(child.copyFor(source));
|
|
78
|
+
});
|
|
79
|
+
} catch (e) {
|
|
80
|
+
if (!forked) throw e;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} else if (context.getCommand()) {
|
|
85
|
+
foundCommand = true;
|
|
86
|
+
try {
|
|
87
|
+
const value = await context.getCommand()(context);
|
|
88
|
+
result += value || value === 0 ? value : 1;
|
|
89
|
+
successfulForks++;
|
|
90
|
+
} catch (e) {
|
|
91
|
+
if (!forked) throw e;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
contexts = next;
|
|
96
|
+
next = [];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!foundCommand) {
|
|
100
|
+
throw CommandSyntaxError.DISPATCHER_UNKNOWN_COMMAND.createWithContext(
|
|
101
|
+
parse.getReader(),
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
return forked ? successfulForks : result;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async parse(
|
|
108
|
+
reader: StringReader | string,
|
|
109
|
+
source: S,
|
|
110
|
+
): Promise<ParseResults<S>> {
|
|
111
|
+
reader = new StringReader(reader);
|
|
112
|
+
const context = new CommandContextBuilder<S>(
|
|
113
|
+
this,
|
|
114
|
+
source,
|
|
115
|
+
this.root,
|
|
116
|
+
reader.getCursor(),
|
|
117
|
+
);
|
|
118
|
+
return this.parseNodes(this.root, reader, context);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private async parseNodes(
|
|
122
|
+
node: CommandNode<S>,
|
|
123
|
+
originalReader: StringReader,
|
|
124
|
+
contextSoFar: CommandContextBuilder<S>,
|
|
125
|
+
): Promise<ParseResults<S>> {
|
|
126
|
+
const source = contextSoFar.getSource();
|
|
127
|
+
const errors = new Map<CommandNode<S>, CommandSyntaxError>();
|
|
128
|
+
const potentials = [];
|
|
129
|
+
const cursor = originalReader.getCursor();
|
|
130
|
+
|
|
131
|
+
for (const child of node.getRelevantNodes(originalReader)) {
|
|
132
|
+
if (!(await child.canUse(source))) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const context = contextSoFar.copy();
|
|
136
|
+
const reader = new StringReader(originalReader);
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
try {
|
|
140
|
+
child.parse(reader, context);
|
|
141
|
+
} catch (e) {
|
|
142
|
+
if (e instanceof CommandSyntaxError) {
|
|
143
|
+
throw e;
|
|
144
|
+
} else {
|
|
145
|
+
throw CommandSyntaxError.DISPATCHER_PARSE_ERROR.createWithContext(
|
|
146
|
+
reader,
|
|
147
|
+
e.message,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (reader.canRead() && reader.peek() !== " ") {
|
|
152
|
+
throw CommandSyntaxError.DISPATCHER_EXPECTED_ARGUMENT_SEPARATOR.createWithContext(
|
|
153
|
+
reader,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
} catch (e) {
|
|
157
|
+
if (e instanceof CommandSyntaxError) {
|
|
158
|
+
errors.set(child, e);
|
|
159
|
+
reader.setCursor(cursor);
|
|
160
|
+
continue;
|
|
161
|
+
} else {
|
|
162
|
+
throw e;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
context.withCommand(child.getCommand());
|
|
167
|
+
if (reader.canRead(child.getRedirect() === null ? 2 : 1)) {
|
|
168
|
+
reader.skip();
|
|
169
|
+
if (child.getRedirect()) {
|
|
170
|
+
const childContext = new CommandContextBuilder<S>(
|
|
171
|
+
this,
|
|
172
|
+
source,
|
|
173
|
+
child.getRedirect(),
|
|
174
|
+
reader.getCursor(),
|
|
175
|
+
);
|
|
176
|
+
const parse = await this.parseNodes(
|
|
177
|
+
child.getRedirect(),
|
|
178
|
+
reader,
|
|
179
|
+
childContext,
|
|
180
|
+
);
|
|
181
|
+
context.withChild(parse.getContext());
|
|
182
|
+
return new ParseResults<S>(
|
|
183
|
+
context,
|
|
184
|
+
parse.getReader(),
|
|
185
|
+
parse.getErrors(),
|
|
186
|
+
);
|
|
187
|
+
} else {
|
|
188
|
+
potentials.push(this.parseNodes(child, reader, context));
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
potentials.push(new ParseResults(context, reader, new Map()));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (potentials.length === 0) {
|
|
195
|
+
potentials.push(new ParseResults(contextSoFar, originalReader, errors));
|
|
196
|
+
}
|
|
197
|
+
return potentials[0];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async getAllUsage(
|
|
201
|
+
node: CommandNode<S>,
|
|
202
|
+
source: S,
|
|
203
|
+
restricted: boolean,
|
|
204
|
+
): Promise<string[]> {
|
|
205
|
+
const result = [];
|
|
206
|
+
await this.getAllUsageImpl(node, source, result, "", restricted);
|
|
207
|
+
return result;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private async getAllUsageImpl(
|
|
211
|
+
node: CommandNode<S>,
|
|
212
|
+
source: S,
|
|
213
|
+
result: string[],
|
|
214
|
+
prefix: string,
|
|
215
|
+
restricted: boolean,
|
|
216
|
+
): Promise<void> {
|
|
217
|
+
if (restricted && !(await node.canUse(source))) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (node.getCommand() != null) {
|
|
222
|
+
result.push(prefix);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (node.getRedirect() != null) {
|
|
226
|
+
const redirect =
|
|
227
|
+
node.getRedirect() === this.root
|
|
228
|
+
? "..."
|
|
229
|
+
: `-> ${node.getRedirect().getUsageText()}`;
|
|
230
|
+
result.push(
|
|
231
|
+
prefix.length === 0
|
|
232
|
+
? `${node.getUsageText()} ${redirect}`
|
|
233
|
+
: `${prefix} ${redirect}`,
|
|
234
|
+
);
|
|
235
|
+
} else if (node.getChildren().length > 0) {
|
|
236
|
+
for (const child of node.getChildren()) {
|
|
237
|
+
const newPrefix =
|
|
238
|
+
prefix.length === 0
|
|
239
|
+
? child.getUsageText()
|
|
240
|
+
: `${prefix} ${child.getUsageText()}`;
|
|
241
|
+
await this.getAllUsageImpl(
|
|
242
|
+
child,
|
|
243
|
+
source,
|
|
244
|
+
result,
|
|
245
|
+
newPrefix,
|
|
246
|
+
restricted,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async getCompletionSuggestions(
|
|
253
|
+
parse: ParseResults<S>,
|
|
254
|
+
cursor?: number,
|
|
255
|
+
): Promise<Suggestions> {
|
|
256
|
+
if (cursor === undefined) {
|
|
257
|
+
cursor = parse.getReader().getTotalLength();
|
|
258
|
+
}
|
|
259
|
+
const context = parse.getContext();
|
|
260
|
+
const nodeBeforeCursor = context.findSuggestionContext(cursor);
|
|
261
|
+
const parent = nodeBeforeCursor.parent;
|
|
262
|
+
const start = Math.min(nodeBeforeCursor.startPos, cursor);
|
|
263
|
+
|
|
264
|
+
const fullInput = parse.getReader().getString();
|
|
265
|
+
const truncatedInput = fullInput.substring(0, cursor);
|
|
266
|
+
const promises: Promise<Suggestions>[] = [];
|
|
267
|
+
for (const node of parent.getChildren()) {
|
|
268
|
+
let promise = Suggestions.empty();
|
|
269
|
+
try {
|
|
270
|
+
promise = node.listSuggestions(
|
|
271
|
+
context.build(truncatedInput),
|
|
272
|
+
new SuggestionsBuilder(truncatedInput, start),
|
|
273
|
+
);
|
|
274
|
+
} catch (ignored) {
|
|
275
|
+
console.log("???", ignored);
|
|
276
|
+
}
|
|
277
|
+
promises.push(promise);
|
|
278
|
+
}
|
|
279
|
+
const suggestions = await Promise.all(promises);
|
|
280
|
+
return Suggestions.merge(fullInput, suggestions);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
getSmartUsage(node: CommandNode<S>, source: S): Map<CommandNode<S>, string>;
|
|
284
|
+
getSmartUsage(
|
|
285
|
+
node: CommandNode<S>,
|
|
286
|
+
source: S,
|
|
287
|
+
optional: boolean,
|
|
288
|
+
deep: boolean,
|
|
289
|
+
): string;
|
|
290
|
+
|
|
291
|
+
getSmartUsage(
|
|
292
|
+
node: CommandNode<S>,
|
|
293
|
+
source: S,
|
|
294
|
+
optional?: boolean,
|
|
295
|
+
deep?: boolean,
|
|
296
|
+
): Map<CommandNode<S>, string> | string {
|
|
297
|
+
if (optional === undefined && deep === undefined) {
|
|
298
|
+
const result = new Map<CommandNode<S>, string>();
|
|
299
|
+
const optional: boolean =
|
|
300
|
+
node.getCommand() !== undefined && node.getCommand() !== null;
|
|
301
|
+
const children = node.getChildren();
|
|
302
|
+
|
|
303
|
+
for (const index in children) {
|
|
304
|
+
const child = children[index];
|
|
305
|
+
const usage = this.getSmartUsage(child, source, optional, false);
|
|
306
|
+
|
|
307
|
+
if (usage !== undefined) {
|
|
308
|
+
result.set(child, usage);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return result;
|
|
313
|
+
} else {
|
|
314
|
+
if (!node.canUse(source)) {
|
|
315
|
+
return undefined;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const self: string = optional
|
|
319
|
+
? CommandDispatcher.USAGE_OPTIONAL_OPEN +
|
|
320
|
+
node.getUsageText() +
|
|
321
|
+
CommandDispatcher.USAGE_OPTIONAL_CLOSE
|
|
322
|
+
: node.getUsageText();
|
|
323
|
+
const childOptional: boolean = node.getCommand() !== undefined;
|
|
324
|
+
const open: string = childOptional
|
|
325
|
+
? CommandDispatcher.USAGE_OPTIONAL_OPEN
|
|
326
|
+
: CommandDispatcher.USAGE_REQUIRED_OPEN;
|
|
327
|
+
const close: string = childOptional
|
|
328
|
+
? CommandDispatcher.USAGE_OPTIONAL_CLOSE
|
|
329
|
+
: CommandDispatcher.USAGE_REQUIRED_CLOSE;
|
|
330
|
+
|
|
331
|
+
if (!deep) {
|
|
332
|
+
if (node.getRedirect() !== undefined) {
|
|
333
|
+
const redirect =
|
|
334
|
+
node.getRedirect() === this.root
|
|
335
|
+
? "..."
|
|
336
|
+
: `-> ${node.getRedirect().getUsageText()}`;
|
|
337
|
+
return `${self} ${redirect}`;
|
|
338
|
+
} else {
|
|
339
|
+
const children: CommandNode<S>[] = node
|
|
340
|
+
.getChildren()
|
|
341
|
+
.filter((c) => c.canUse(source));
|
|
342
|
+
|
|
343
|
+
if (children.length === 1) {
|
|
344
|
+
const usage = String(
|
|
345
|
+
this.getSmartUsage(
|
|
346
|
+
children[0],
|
|
347
|
+
source,
|
|
348
|
+
childOptional,
|
|
349
|
+
childOptional,
|
|
350
|
+
),
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
if (usage !== undefined) {
|
|
354
|
+
return `${self} ${usage}`;
|
|
355
|
+
}
|
|
356
|
+
} else if (children.length > 1) {
|
|
357
|
+
const childUsage = new Set<string>();
|
|
358
|
+
|
|
359
|
+
for (const index in children) {
|
|
360
|
+
const child = children[index];
|
|
361
|
+
const usage = this.getSmartUsage(
|
|
362
|
+
child,
|
|
363
|
+
source,
|
|
364
|
+
childOptional,
|
|
365
|
+
true,
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
if (usage !== undefined) {
|
|
369
|
+
childUsage.add(usage);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (childUsage.size === 1) {
|
|
374
|
+
const usage = childUsage.values().next().value;
|
|
375
|
+
return `${self} ${childOptional ? CommandDispatcher.USAGE_OPTIONAL_OPEN + usage + CommandDispatcher.USAGE_OPTIONAL_CLOSE : usage}`;
|
|
376
|
+
} else if (childUsage.size > 1) {
|
|
377
|
+
let builder = open;
|
|
378
|
+
|
|
379
|
+
for (let index = 0; index < children.length; index++) {
|
|
380
|
+
const child = children[index];
|
|
381
|
+
|
|
382
|
+
if (index > 0) {
|
|
383
|
+
builder += CommandDispatcher.USAGE_OR;
|
|
384
|
+
}
|
|
385
|
+
builder += child.getUsageText();
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (children.length > 0) {
|
|
389
|
+
builder += close;
|
|
390
|
+
return `${self} ${builder}`;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
getRoot(): RootCommandNode<S> {
|
|
400
|
+
return this.root;
|
|
401
|
+
}
|
|
300
402
|
}
|