cloud
cloud copied to clipboard
Greedy parsers cannot have functioning suggestions
There's a hard limitation that a parser can only provide suggestions for one argument being typed. This is because as input to suggestions, only a single String can be provided. When there are two or more parts in the command queue, it is unclear what part should be sent to the suggestions provider.
A greedy string parser might want to suggest words with spaces in them, while a string[] parser might want to suggest a word for every element.
Because suggestions aren't even asked right now (because it is not clear what should happen), there is no workable solution.
https://github.com/Incendo/cloud/blob/1.4.0-dev/cloud-core/src/main/java/cloud/commandframework/CommandTree.java#L602
CompoundArgument has some special logic tailored to it, but also assumes the last-typed 'element' is what needs suggestions. For greedy parsers that is not valid.
Changing String to Queue<String> for suggestions would make it in parity with parsers, but would also break api compatibility. I know no good solution for this.
Non-breaking solutions
Option A (small behavior change for greedy parsers)
Make it so a greedy or flag-yielding-greedy parser, will receive a string that is concatenating the remaining input with spaces. Non-greedy parsers will not be affected, and the greedy parsers that do get affected were already broken or mostly non-functioning, so this could be an ok solution.
Option B (no behavior change)
The command context could have a property for the currently-parsing-queue, similar to how getRawInput is a thing, would allow the flexibility of using the remaining text for greedy-parser suggestions without compromising breaking behavior anywhere.
Workarround, add it to the context yourself in a preprocessor:
A way to work around this issue is to add the input queue to the command context yourself using a preprocessor, then this becomes available to your suggest method (note: for the method to be called you need flag-yielding greedy, and a dummy flag in the command even if it does nothing.:
Example:
// Put in some file with constants
public static final CloudKey<LinkedList<String>> INPUT_QUEUE =
SimpleCloudKey.of("__someprefix_input_queue__", new TypeToken<LinkedList<String>>(){});
// Do when setting-up the manager
public void managerSetup() {
manager.registerCommandPreProcessor(context ->
context.getCommandContext().store(INPUT_QUEUE, context.getInputQueue()));
}
// Your parser, which can now suggest with the whole input queue!
public @NonNull List<@NonNull String> suggestions(
@NonNull CommandContext<CommandSender> context, @NonNull String input) {
List<String> inputQueue = context.get(INPUT_QUEUE);
// In one case, cloud will call .remove() instead of .peek(), add it back.
if (inputQueue.isEmpty()) inputQueue.add(input);
// Prepare some suggestions based on the input queue!
}
Is there a chance either of the two non-breaking solutions fit the project? I'd be willing to make and PR either of those two solutions if they'll get accepted.