diff --git a/src/main/java/com/mojang/brigadier/builder/RequiredArgumentBuilder.java b/src/main/java/com/mojang/brigadier/builder/RequiredArgumentBuilder.java index a09b9e157..6fba01840 100644 --- a/src/main/java/com/mojang/brigadier/builder/RequiredArgumentBuilder.java +++ b/src/main/java/com/mojang/brigadier/builder/RequiredArgumentBuilder.java @@ -11,15 +11,21 @@ public class RequiredArgumentBuilder extends ArgumentBuilder> { private final String name; private final ArgumentType type; + private final boolean list; private SuggestionProvider suggestionsProvider = null; - private RequiredArgumentBuilder(final String name, final ArgumentType type) { + private RequiredArgumentBuilder(final String name, final ArgumentType type, boolean list) { this.name = name; this.type = type; + this.list = list; } public static RequiredArgumentBuilder argument(final String name, final ArgumentType type) { - return new RequiredArgumentBuilder<>(name, type); + return new RequiredArgumentBuilder<>(name, type, false); + } + + public static RequiredArgumentBuilder list(final String name, final ArgumentType type) { + return new RequiredArgumentBuilder<>(name, type, true); } public RequiredArgumentBuilder suggests(final SuggestionProvider provider) { @@ -44,8 +50,10 @@ public String getName() { return name; } + public boolean isList() { return list; } + public ArgumentCommandNode build() { - final ArgumentCommandNode result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier(), isFork(), getSuggestionsProvider()); + final ArgumentCommandNode result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier(), isFork(), getSuggestionsProvider(), isList()); for (final CommandNode argument : getArguments()) { result.addChild(argument); diff --git a/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java b/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java index 6018eb006..ab078b224 100644 --- a/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java @@ -11,12 +11,15 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContextBuilder; import com.mojang.brigadier.context.ParsedArgument; +import com.mojang.brigadier.context.StringRange; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; @@ -27,12 +30,21 @@ public class ArgumentCommandNode extends CommandNode { private final String name; private final ArgumentType type; private final SuggestionProvider customSuggestions; + private final boolean list; + private Collection> cached; + private Collection> cachedOut; + @Deprecated public ArgumentCommandNode(final String name, final ArgumentType type, final Command command, final Predicate requirement, final CommandNode redirect, final RedirectModifier modifier, final boolean forks, final SuggestionProvider customSuggestions) { + this(name, type, command, requirement, redirect, modifier, forks, customSuggestions, false); + } + + public ArgumentCommandNode(final String name, final ArgumentType type, final Command command, final Predicate requirement, final CommandNode redirect, final RedirectModifier modifier, final boolean forks, final SuggestionProvider customSuggestions, boolean list) { super(command, requirement, redirect, modifier, forks); this.name = name; this.type = type; this.customSuggestions = customSuggestions; + this.list = list; } public ArgumentType getType() { @@ -57,10 +69,24 @@ public SuggestionProvider getCustomSuggestions() { public void parse(final StringReader reader, final CommandContextBuilder contextBuilder) throws CommandSyntaxException { final int start = reader.getCursor(); final T result = type.parse(reader); - final ParsedArgument parsed = new ParsedArgument<>(start, reader.getCursor(), result); - contextBuilder.withArgument(name, parsed); - contextBuilder.withNode(this, parsed.getRange()); + if (!list) { + final ParsedArgument parsed = new ParsedArgument<>(start, reader.getCursor(), result); + + contextBuilder.withArgument(name, parsed); + } else { + ParsedArgument> parsed = (ParsedArgument>) contextBuilder.getArguments().get(name); + if (parsed == null) { + parsed = new ParsedArgument<>(start, reader.getCursor(), new ArrayList<>()); + } else { + parsed = new ParsedArgument<>(parsed.getRange().getStart(), reader.getCursor(), parsed.getResult()); + } + parsed.getResult().add(result); + + contextBuilder.withArgument(name, parsed); + } + + contextBuilder.withNode(this, new StringRange(start, reader.getCursor())); } @Override @@ -74,7 +100,7 @@ public CompletableFuture listSuggestions(final CommandContext co @Override public RequiredArgumentBuilder createBuilder() { - final RequiredArgumentBuilder builder = RequiredArgumentBuilder.argument(name, type); + final RequiredArgumentBuilder builder = list ? RequiredArgumentBuilder.list(name, type) : RequiredArgumentBuilder.argument(name, type); builder.requires(getRequirement()); builder.forward(getRedirect(), getRedirectModifier(), isFork()); builder.suggests(customSuggestions); @@ -128,4 +154,24 @@ public Collection getExamples() { public String toString() { return ""; } + + @Override + public Collection> getRelevantNodes(StringReader input) { + if (!list) { + return super.getRelevantNodes(input); + } else { + Collection> relevantNodes = super.getRelevantNodes(input); + if (relevantNodes.size() == 1 && relevantNodes.stream().allMatch(node -> node instanceof LiteralCommandNode)) { + return relevantNodes; + } else { + if (cached != relevantNodes) { + cached = relevantNodes; + ArrayList> commandNodes = new ArrayList<>(cached); + commandNodes.add(this); + cachedOut = commandNodes; + } + return cachedOut; + } + } + } }