From be0090873b16408ea64b1beac85377234dcfce11 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Wed, 8 Nov 2017 15:17:59 +0100 Subject: [PATCH] Allow overriding of suggestion providers per argument --- build.gradle | 2 +- .../mojang/brigadier/CommandDispatcher.java | 8 +------- .../mojang/brigadier/CommandSuggestions.java | 9 +++++++++ .../brigadier/arguments/ArgumentType.java | 3 ++- .../brigadier/arguments/BoolArgumentType.java | 19 +++++++++++++++++++ .../brigadier/builder/ArgumentBuilder.java | 2 +- .../builder/RequiredArgumentBuilder.java | 18 +++++++++++++++++- .../brigadier/tree/ArgumentCommandNode.java | 12 +++++++++--- .../mojang/brigadier/tree/CommandNode.java | 5 +---- .../brigadier/tree/LiteralCommandNode.java | 5 ++--- .../brigadier/tree/RootCommandNode.java | 3 ++- .../arguments/IntegerArgumentTypeTest.java | 12 ------------ .../builder/RequiredArgumentBuilderTest.java | 3 +++ .../tree/ArgumentCommandNodeTest.java | 8 ++------ .../tree/LiteralCommandNodeTest.java | 10 ++++------ .../brigadier/tree/RootCommandNodeTest.java | 8 ++++---- 16 files changed, 77 insertions(+), 50 deletions(-) diff --git a/build.gradle b/build.gradle index 0f838ab..45e26e5 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ import groovy.io.FileType apply plugin: 'java-library' apply plugin: 'maven' -version = '0.1.4' +version = '0.1.5' group = 'com.mojang' task wrapper(type: Wrapper) { diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java index 4d69fe2..5fbeec2 100644 --- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java +++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java @@ -19,16 +19,10 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Deque; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -315,7 +309,7 @@ public class CommandDispatcher { @SuppressWarnings("unchecked") final CompletableFuture>[] futures = new CompletableFuture[parent.getChildren().size()]; int i = 0; for (final CommandNode node : parent.getChildren()) { - futures[i++] = node.listSuggestions(parse.getReader().getString().substring(start)); + futures[i++] = node.listSuggestions(context.build(), parse.getReader().getString().substring(start)); } final CompletableFuture result = new CompletableFuture<>(); diff --git a/src/main/java/com/mojang/brigadier/CommandSuggestions.java b/src/main/java/com/mojang/brigadier/CommandSuggestions.java index 24ee52d..25a945b 100644 --- a/src/main/java/com/mojang/brigadier/CommandSuggestions.java +++ b/src/main/java/com/mojang/brigadier/CommandSuggestions.java @@ -1,9 +1,13 @@ package com.mojang.brigadier; +import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.StringRange; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.concurrent.CompletableFuture; public class CommandSuggestions { private final StringRange range; @@ -42,4 +46,9 @@ public class CommandSuggestions { public boolean isEmpty() { return suggestions.isEmpty(); } + + @FunctionalInterface + public interface Provider { + CompletableFuture> getSuggestions(final CommandContext context, final String prefix); + } } diff --git a/src/main/java/com/mojang/brigadier/arguments/ArgumentType.java b/src/main/java/com/mojang/brigadier/arguments/ArgumentType.java index 343757c..8780390 100644 --- a/src/main/java/com/mojang/brigadier/arguments/ArgumentType.java +++ b/src/main/java/com/mojang/brigadier/arguments/ArgumentType.java @@ -1,6 +1,7 @@ package com.mojang.brigadier.arguments; import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContextBuilder; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -11,7 +12,7 @@ import java.util.concurrent.CompletableFuture; public interface ArgumentType { T parse(StringReader reader, CommandContextBuilder contextBuilder) throws CommandSyntaxException; - default CompletableFuture> listSuggestions(final String command) { + default CompletableFuture> listSuggestions(final CommandContext context, final String command) { return CompletableFuture.completedFuture(Collections.emptyList()); } } diff --git a/src/main/java/com/mojang/brigadier/arguments/BoolArgumentType.java b/src/main/java/com/mojang/brigadier/arguments/BoolArgumentType.java index be79ea9..fbc59a0 100644 --- a/src/main/java/com/mojang/brigadier/arguments/BoolArgumentType.java +++ b/src/main/java/com/mojang/brigadier/arguments/BoolArgumentType.java @@ -1,10 +1,15 @@ package com.mojang.brigadier.arguments; +import com.google.common.collect.Lists; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContextBuilder; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; + public class BoolArgumentType implements ArgumentType { private BoolArgumentType() { } @@ -21,4 +26,18 @@ public class BoolArgumentType implements ArgumentType { public Boolean parse(final StringReader reader, final CommandContextBuilder contextBuilder) throws CommandSyntaxException { return reader.readBoolean(); } + + @Override + public CompletableFuture> listSuggestions(final CommandContext context, final String command) { + final List result = Lists.newArrayList(); + + if ("true".startsWith(command)) { + result.add("true"); + } + if ("false".startsWith(command)) { + result.add("false"); + } + + return CompletableFuture.completedFuture(result); + } } diff --git a/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java b/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java index dbc3d49..d8bf453 100644 --- a/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java +++ b/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java @@ -2,12 +2,12 @@ package com.mojang.brigadier.builder; import com.mojang.brigadier.Command; import com.mojang.brigadier.RedirectModifier; -import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.RootCommandNode; import java.util.Collection; import java.util.Collections; +import java.util.concurrent.CompletableFuture; import java.util.function.Function; import java.util.function.Predicate; diff --git a/src/main/java/com/mojang/brigadier/builder/RequiredArgumentBuilder.java b/src/main/java/com/mojang/brigadier/builder/RequiredArgumentBuilder.java index 493c26e..694f256 100644 --- a/src/main/java/com/mojang/brigadier/builder/RequiredArgumentBuilder.java +++ b/src/main/java/com/mojang/brigadier/builder/RequiredArgumentBuilder.java @@ -1,12 +1,19 @@ package com.mojang.brigadier.builder; +import com.mojang.brigadier.CommandSuggestions; import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.tree.ArgumentCommandNode; import com.mojang.brigadier.tree.CommandNode; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + public class RequiredArgumentBuilder extends ArgumentBuilder> { private final String name; private final ArgumentType type; + private CommandSuggestions.Provider suggestionsProvider = null; private RequiredArgumentBuilder(final String name, final ArgumentType type) { this.name = name; @@ -17,6 +24,15 @@ public class RequiredArgumentBuilder extends ArgumentBuilder(name, type); } + public RequiredArgumentBuilder suggests(final CommandSuggestions.Provider provider) { + this.suggestionsProvider = provider; + return getThis(); + } + + public CommandSuggestions.Provider getSuggestionsProvider() { + return suggestionsProvider == null ? type::listSuggestions : suggestionsProvider; + } + @Override protected RequiredArgumentBuilder getThis() { return this; @@ -31,7 +47,7 @@ public class RequiredArgumentBuilder extends ArgumentBuilder build() { - final ArgumentCommandNode result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier()); + final ArgumentCommandNode result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier(), getSuggestionsProvider()); 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 6e60765..ee60174 100644 --- a/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java @@ -1,16 +1,19 @@ package com.mojang.brigadier.tree; import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandSuggestions; import com.mojang.brigadier.RedirectModifier; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContextBuilder; import com.mojang.brigadier.context.ParsedArgument; import com.mojang.brigadier.exceptions.CommandSyntaxException; import java.util.Collection; import java.util.concurrent.CompletableFuture; +import java.util.function.Function; import java.util.function.Predicate; public class ArgumentCommandNode extends CommandNode { @@ -19,11 +22,13 @@ public class ArgumentCommandNode extends CommandNode { private final String name; private final ArgumentType type; + private final CommandSuggestions.Provider suggestionsProvider; - public ArgumentCommandNode(final String name, final ArgumentType type, final Command command, final Predicate requirement, final CommandNode redirect, final RedirectModifier modifier) { + public ArgumentCommandNode(final String name, final ArgumentType type, final Command command, final Predicate requirement, final CommandNode redirect, final RedirectModifier modifier, final CommandSuggestions.Provider suggestionsProvider) { super(command, requirement, redirect, modifier); this.name = name; this.type = type; + this.suggestionsProvider = suggestionsProvider; } public String getName() { @@ -55,8 +60,8 @@ public class ArgumentCommandNode extends CommandNode { } @Override - public CompletableFuture> listSuggestions(final String command) { - return type.listSuggestions(command); + public CompletableFuture> listSuggestions(final CommandContext context, final String command) { + return suggestionsProvider.getSuggestions(context, command); } @Override @@ -64,6 +69,7 @@ public class ArgumentCommandNode extends CommandNode { final RequiredArgumentBuilder builder = RequiredArgumentBuilder.argument(name, type); builder.requires(getRequirement()); builder.redirect(getRedirect(), getRedirectModifier()); + builder.suggests(suggestionsProvider); if (getCommand() != null) { builder.executes(getCommand()); } diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java index a5f1262..73438fc 100644 --- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java @@ -13,10 +13,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; -import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -99,7 +96,7 @@ public abstract class CommandNode implements Comparable> { public abstract void parse(StringReader reader, CommandContextBuilder contextBuilder) throws CommandSyntaxException; - public abstract CompletableFuture> listSuggestions(String command); + public abstract CompletableFuture> listSuggestions(CommandContext context, String command); public abstract ArgumentBuilder createBuilder(); diff --git a/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java b/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java index 1e1c20e..0c74536 100644 --- a/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java @@ -4,6 +4,7 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.RedirectModifier; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContextBuilder; import com.mojang.brigadier.context.StringRange; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -11,9 +12,7 @@ import com.mojang.brigadier.exceptions.ParameterizedCommandExceptionType; import java.util.Collection; import java.util.Collections; -import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; import java.util.function.Predicate; public class LiteralCommandNode extends CommandNode { @@ -51,7 +50,7 @@ public class LiteralCommandNode extends CommandNode { } @Override - public CompletableFuture> listSuggestions(final String command) { + public CompletableFuture> listSuggestions(CommandContext context, final String command) { if (literal.startsWith(command)) { return CompletableFuture.completedFuture(Collections.singleton(literal)); } else { diff --git a/src/main/java/com/mojang/brigadier/tree/RootCommandNode.java b/src/main/java/com/mojang/brigadier/tree/RootCommandNode.java index b531b91..f42e37d 100644 --- a/src/main/java/com/mojang/brigadier/tree/RootCommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/RootCommandNode.java @@ -2,6 +2,7 @@ package com.mojang.brigadier.tree; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContextBuilder; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -29,7 +30,7 @@ public class RootCommandNode extends CommandNode { } @Override - public CompletableFuture> listSuggestions(final String command) { + public CompletableFuture> listSuggestions(CommandContext context, final String command) { return CompletableFuture.completedFuture(Collections.emptyList()); } diff --git a/src/test/java/com/mojang/brigadier/arguments/IntegerArgumentTypeTest.java b/src/test/java/com/mojang/brigadier/arguments/IntegerArgumentTypeTest.java index ea8bf08..20f05c5 100644 --- a/src/test/java/com/mojang/brigadier/arguments/IntegerArgumentTypeTest.java +++ b/src/test/java/com/mojang/brigadier/arguments/IntegerArgumentTypeTest.java @@ -1,7 +1,6 @@ package com.mojang.brigadier.arguments; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Sets; import com.google.common.testing.EqualsTester; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.context.CommandContextBuilder; @@ -10,14 +9,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; -import java.util.Collection; -import java.util.Set; - import static com.mojang.brigadier.arguments.IntegerArgumentType.integer; -import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasToString; import static org.hamcrest.Matchers.is; @@ -68,12 +62,6 @@ public class IntegerArgumentTypeTest { } } - @Test - public void testSuggestions() throws Exception { - final Collection result = type.listSuggestions("").join(); - assertThat(result, is(empty())); - } - @Test public void testEquals() throws Exception { new EqualsTester() diff --git a/src/test/java/com/mojang/brigadier/builder/RequiredArgumentBuilderTest.java b/src/test/java/com/mojang/brigadier/builder/RequiredArgumentBuilderTest.java index 3104a9e..6a19adf 100644 --- a/src/test/java/com/mojang/brigadier/builder/RequiredArgumentBuilderTest.java +++ b/src/test/java/com/mojang/brigadier/builder/RequiredArgumentBuilderTest.java @@ -5,7 +5,9 @@ import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.tree.ArgumentCommandNode; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import static com.mojang.brigadier.arguments.IntegerArgumentType.integer; import static com.mojang.brigadier.builder.RequiredArgumentBuilder.argument; @@ -13,6 +15,7 @@ import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; +@RunWith(MockitoJUnitRunner.class) public class RequiredArgumentBuilderTest { @Mock private ArgumentType type; diff --git a/src/test/java/com/mojang/brigadier/tree/ArgumentCommandNodeTest.java b/src/test/java/com/mojang/brigadier/tree/ArgumentCommandNodeTest.java index aff7b10..1b38852 100644 --- a/src/test/java/com/mojang/brigadier/tree/ArgumentCommandNodeTest.java +++ b/src/test/java/com/mojang/brigadier/tree/ArgumentCommandNodeTest.java @@ -1,19 +1,16 @@ package com.mojang.brigadier.tree; -import com.google.common.collect.Sets; import com.google.common.testing.EqualsTester; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContextBuilder; import org.junit.Before; import org.junit.Test; -import org.mockito.Mockito; import java.util.Collection; -import java.util.Set; import static com.mojang.brigadier.arguments.IntegerArgumentType.integer; import static com.mojang.brigadier.builder.RequiredArgumentBuilder.argument; @@ -21,7 +18,6 @@ import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class ArgumentCommandNodeTest extends AbstractCommandNodeTest { private ArgumentCommandNode node; @@ -54,7 +50,7 @@ public class ArgumentCommandNodeTest extends AbstractCommandNodeTest { @Test public void testSuggestions() throws Exception { - final Collection result = node.listSuggestions("").join(); + final Collection result = node.listSuggestions(contextBuilder.build(), "").join(); assertThat(result, is(empty())); } diff --git a/src/test/java/com/mojang/brigadier/tree/LiteralCommandNodeTest.java b/src/test/java/com/mojang/brigadier/tree/LiteralCommandNodeTest.java index ed49a54..d130147 100644 --- a/src/test/java/com/mojang/brigadier/tree/LiteralCommandNodeTest.java +++ b/src/test/java/com/mojang/brigadier/tree/LiteralCommandNodeTest.java @@ -11,10 +11,8 @@ import com.mojang.brigadier.context.CommandContextBuilder; import com.mojang.brigadier.exceptions.CommandSyntaxException; import org.junit.Before; import org.junit.Test; -import org.mockito.Mockito; import java.util.Collection; -import java.util.Set; import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal; import static org.hamcrest.Matchers.empty; @@ -81,16 +79,16 @@ public class LiteralCommandNodeTest extends AbstractCommandNodeTest { @Test public void testSuggestions() throws Exception { - final Collection empty = node.listSuggestions("").join(); + final Collection empty = node.listSuggestions(contextBuilder.build(), "").join(); assertThat(empty, equalTo(Sets.newHashSet("foo"))); - final Collection foo = node.listSuggestions("foo").join(); + final Collection foo = node.listSuggestions(contextBuilder.build(), "foo").join(); assertThat(foo, equalTo(Sets.newHashSet("foo"))); - final Collection food = node.listSuggestions("food").join(); + final Collection food = node.listSuggestions(contextBuilder.build(), "food").join(); assertThat(food, is(empty())); - final Collection b = node.listSuggestions("b").join(); + final Collection b = node.listSuggestions(contextBuilder.build(), "b").join(); assertThat(b, is(empty())); } diff --git a/src/test/java/com/mojang/brigadier/tree/RootCommandNodeTest.java b/src/test/java/com/mojang/brigadier/tree/RootCommandNodeTest.java index 8de1fcb..a49f00b 100644 --- a/src/test/java/com/mojang/brigadier/tree/RootCommandNodeTest.java +++ b/src/test/java/com/mojang/brigadier/tree/RootCommandNodeTest.java @@ -1,21 +1,20 @@ package com.mojang.brigadier.tree; -import com.google.common.collect.Sets; import com.google.common.testing.EqualsTester; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContextBuilder; import org.junit.Before; import org.junit.Test; -import org.mockito.Mockito; import java.util.Collection; -import java.util.Set; import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; public class RootCommandNodeTest extends AbstractCommandNodeTest { private RootCommandNode node; @@ -49,7 +48,8 @@ public class RootCommandNodeTest extends AbstractCommandNodeTest { @Test public void testSuggestions() throws Exception { - final Collection result = node.listSuggestions("").join(); + final CommandContext context = mock(CommandContext.class); + final Collection result = node.listSuggestions(context, "").join(); assertThat(result, is(empty())); }