diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java index 2d28761..4d69fe2 100644 --- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java +++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java @@ -23,6 +23,12 @@ 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; @@ -285,11 +291,8 @@ public class CommandDispatcher { return self; } - public CommandSuggestions getCompletionSuggestions(final ParseResults parse) { + public CompletableFuture getCompletionSuggestions(final ParseResults parse) { final CommandContextBuilder context = parse.getContext(); - - final Set suggestions = new LinkedHashSet<>(); - final CommandNode parent; final int start; @@ -309,13 +312,24 @@ public class CommandDispatcher { start = 0; } + @SuppressWarnings("unchecked") final CompletableFuture>[] futures = new CompletableFuture[parent.getChildren().size()]; + int i = 0; for (final CommandNode node : parent.getChildren()) { - node.listSuggestions(parse.getReader().getString().substring(start), suggestions, context); + futures[i++] = node.listSuggestions(parse.getReader().getString().substring(start)); } - final List result = new ArrayList<>(suggestions); - Collections.sort(result); - return new CommandSuggestions(new StringRange(start, parse.getReader().getTotalLength()), result); + final CompletableFuture result = new CompletableFuture<>(); + CompletableFuture.allOf(futures).thenRun(() -> { + final Set suggestions = Sets.newHashSet(); + for (final CompletableFuture> future : futures) { + suggestions.addAll(future.join()); + } + final List sorted = new ArrayList<>(suggestions); + Collections.sort(sorted); + result.complete(new CommandSuggestions(new StringRange(start, parse.getReader().getTotalLength()), sorted)); + }); + + return result; } public RootCommandNode getRoot() { diff --git a/src/main/java/com/mojang/brigadier/arguments/ArgumentType.java b/src/main/java/com/mojang/brigadier/arguments/ArgumentType.java index c7701ee..343757c 100644 --- a/src/main/java/com/mojang/brigadier/arguments/ArgumentType.java +++ b/src/main/java/com/mojang/brigadier/arguments/ArgumentType.java @@ -4,11 +4,14 @@ import com.mojang.brigadier.StringReader; import com.mojang.brigadier.context.CommandContextBuilder; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import java.util.Set; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; public interface ArgumentType { T parse(StringReader reader, CommandContextBuilder contextBuilder) throws CommandSyntaxException; - default void listSuggestions(final String command, final Set output, final CommandContextBuilder contextBuilder) { + default CompletableFuture> listSuggestions(final String command) { + return CompletableFuture.completedFuture(Collections.emptyList()); } } diff --git a/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java b/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java index b9ef2b9..6e60765 100644 --- a/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java @@ -5,14 +5,12 @@ 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.Set; -import java.util.function.Function; +import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; public class ArgumentCommandNode extends CommandNode { @@ -57,8 +55,8 @@ public class ArgumentCommandNode extends CommandNode { } @Override - public void listSuggestions(final String command, final Set output, final CommandContextBuilder contextBuilder) { - type.listSuggestions(command, output, contextBuilder); + public CompletableFuture> listSuggestions(final String command) { + return type.listSuggestions(command); } @Override diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java index a75f824..a5f1262 100644 --- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java @@ -14,6 +14,8 @@ 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; @@ -97,7 +99,7 @@ public abstract class CommandNode implements Comparable> { public abstract void parse(StringReader reader, CommandContextBuilder contextBuilder) throws CommandSyntaxException; - public abstract void listSuggestions(String command, Set output, CommandContextBuilder contextBuilder); + public abstract CompletableFuture> listSuggestions(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 c0bb9fe..1e1c20e 100644 --- a/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java @@ -4,15 +4,16 @@ 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; import com.mojang.brigadier.exceptions.ParameterizedCommandExceptionType; import java.util.Collection; +import java.util.Collections; import java.util.Set; -import java.util.function.Function; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; import java.util.function.Predicate; public class LiteralCommandNode extends CommandNode { @@ -50,9 +51,11 @@ public class LiteralCommandNode extends CommandNode { } @Override - public void listSuggestions(final String command, final Set output, final CommandContextBuilder contextBuilder) { + public CompletableFuture> listSuggestions(final String command) { if (literal.startsWith(command)) { - output.add(literal); + return CompletableFuture.completedFuture(Collections.singleton(literal)); + } else { + return CompletableFuture.completedFuture(Collections.emptyList()); } } diff --git a/src/main/java/com/mojang/brigadier/tree/RootCommandNode.java b/src/main/java/com/mojang/brigadier/tree/RootCommandNode.java index 01e2703..b531b91 100644 --- a/src/main/java/com/mojang/brigadier/tree/RootCommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/RootCommandNode.java @@ -5,8 +5,9 @@ import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.context.CommandContextBuilder; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.util.Collection; import java.util.Collections; -import java.util.Set; +import java.util.concurrent.CompletableFuture; public class RootCommandNode extends CommandNode { public RootCommandNode() { @@ -28,7 +29,8 @@ public class RootCommandNode extends CommandNode { } @Override - public void listSuggestions(final String command, final Set output, final CommandContextBuilder contextBuilder) { + public CompletableFuture> listSuggestions(final String command) { + return CompletableFuture.completedFuture(Collections.emptyList()); } @Override diff --git a/src/test/java/com/mojang/brigadier/CommandSuggestionsTest.java b/src/test/java/com/mojang/brigadier/CommandSuggestionsTest.java index e0eaf67..be01a55 100644 --- a/src/test/java/com/mojang/brigadier/CommandSuggestionsTest.java +++ b/src/test/java/com/mojang/brigadier/CommandSuggestionsTest.java @@ -29,7 +29,7 @@ public class CommandSuggestionsTest { subject.register(literal("bar")); subject.register(literal("baz")); - final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("", source)); + final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("", source)).join(); assertThat(result.getRange(), equalTo(new StringRange(0, 0))); assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz", "foo"))); @@ -41,7 +41,7 @@ public class CommandSuggestionsTest { subject.register(literal("bar")); subject.register(literal("baz")); - final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("b", source)); + final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("b", source)).join(); assertThat(result.getRange(), equalTo(new StringRange(0, 1))); assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz"))); @@ -56,7 +56,7 @@ public class CommandSuggestionsTest { .then(literal("baz")) ); - final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("parent ", source)); + final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("parent ", source)).join(); assertThat(result.getRange(), equalTo(new StringRange(7, 7))); assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz", "foo"))); @@ -71,7 +71,7 @@ public class CommandSuggestionsTest { .then(literal("baz")) ); - final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("parent b", source)); + final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("parent b", source)).join(); assertThat(result.getRange(), equalTo(new StringRange(7, 8))); assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz"))); diff --git a/src/test/java/com/mojang/brigadier/arguments/FloatArgumentTypeTest.java b/src/test/java/com/mojang/brigadier/arguments/FloatArgumentTypeTest.java index c6a7c31..d0cef81 100644 --- a/src/test/java/com/mojang/brigadier/arguments/FloatArgumentTypeTest.java +++ b/src/test/java/com/mojang/brigadier/arguments/FloatArgumentTypeTest.java @@ -67,14 +67,6 @@ public class FloatArgumentTypeTest { } } - @Test - public void testSuggestions() throws Exception { - final Set set = Sets.newHashSet(); - @SuppressWarnings("unchecked") final CommandContextBuilder context = Mockito.mock(CommandContextBuilder.class); - type.listSuggestions("", set, context); - assertThat(set, is(empty())); - } - @Test public void testEquals() throws Exception { new EqualsTester() diff --git a/src/test/java/com/mojang/brigadier/arguments/IntegerArgumentTypeTest.java b/src/test/java/com/mojang/brigadier/arguments/IntegerArgumentTypeTest.java index 6dd3820..ea8bf08 100644 --- a/src/test/java/com/mojang/brigadier/arguments/IntegerArgumentTypeTest.java +++ b/src/test/java/com/mojang/brigadier/arguments/IntegerArgumentTypeTest.java @@ -13,6 +13,7 @@ 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; @@ -69,10 +70,8 @@ public class IntegerArgumentTypeTest { @Test public void testSuggestions() throws Exception { - final Set set = Sets.newHashSet(); - @SuppressWarnings("unchecked") final CommandContextBuilder context = Mockito.mock(CommandContextBuilder.class); - type.listSuggestions("", set, context); - assertThat(set, is(empty())); + final Collection result = type.listSuggestions("").join(); + assertThat(result, is(empty())); } @Test diff --git a/src/test/java/com/mojang/brigadier/arguments/StringArgumentTypeTest.java b/src/test/java/com/mojang/brigadier/arguments/StringArgumentTypeTest.java index ec5f0ed..6e4eff1 100644 --- a/src/test/java/com/mojang/brigadier/arguments/StringArgumentTypeTest.java +++ b/src/test/java/com/mojang/brigadier/arguments/StringArgumentTypeTest.java @@ -51,13 +51,6 @@ public class StringArgumentTypeTest { assertThat(reader.canRead(), is(false)); } - @Test - public void testSuggestions() throws Exception { - final Set set = Sets.newHashSet(); - string().listSuggestions("", set, context); - assertThat(set, is(empty())); - } - @Test public void testToString() throws Exception { assertThat(string(), hasToString("string()")); diff --git a/src/test/java/com/mojang/brigadier/tree/ArgumentCommandNodeTest.java b/src/test/java/com/mojang/brigadier/tree/ArgumentCommandNodeTest.java index ec11cfb..aff7b10 100644 --- a/src/test/java/com/mojang/brigadier/tree/ArgumentCommandNodeTest.java +++ b/src/test/java/com/mojang/brigadier/tree/ArgumentCommandNodeTest.java @@ -12,6 +12,7 @@ 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; @@ -53,10 +54,8 @@ public class ArgumentCommandNodeTest extends AbstractCommandNodeTest { @Test public void testSuggestions() throws Exception { - final Set set = Sets.newHashSet(); - @SuppressWarnings("unchecked") final CommandContextBuilder context = Mockito.mock(CommandContextBuilder.class); - node.listSuggestions("", set, context); - assertThat(set, is(empty())); + final Collection result = node.listSuggestions("").join(); + assertThat(result, is(empty())); } @Test diff --git a/src/test/java/com/mojang/brigadier/tree/LiteralCommandNodeTest.java b/src/test/java/com/mojang/brigadier/tree/LiteralCommandNodeTest.java index b719213..ed49a54 100644 --- a/src/test/java/com/mojang/brigadier/tree/LiteralCommandNodeTest.java +++ b/src/test/java/com/mojang/brigadier/tree/LiteralCommandNodeTest.java @@ -13,6 +13,7 @@ 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; @@ -80,23 +81,17 @@ public class LiteralCommandNodeTest extends AbstractCommandNodeTest { @Test public void testSuggestions() throws Exception { - final Set set = Sets.newHashSet(); - @SuppressWarnings("unchecked") final CommandContextBuilder context = Mockito.mock(CommandContextBuilder.class); + final Collection empty = node.listSuggestions("").join(); + assertThat(empty, equalTo(Sets.newHashSet("foo"))); - node.listSuggestions("", set, context); - assertThat(set, equalTo(Sets.newHashSet("foo"))); + final Collection foo = node.listSuggestions("foo").join(); + assertThat(foo, equalTo(Sets.newHashSet("foo"))); - set.clear(); - node.listSuggestions("foo", set, context); - assertThat(set, equalTo(Sets.newHashSet("foo"))); + final Collection food = node.listSuggestions("food").join(); + assertThat(food, is(empty())); - set.clear(); - node.listSuggestions("food", set, context); - assertThat(set, is(empty())); - - set.clear(); - node.listSuggestions("b", set, context); - assertThat(set, is(empty())); + final Collection b = node.listSuggestions("b").join(); + assertThat(b, is(empty())); } @Test diff --git a/src/test/java/com/mojang/brigadier/tree/RootCommandNodeTest.java b/src/test/java/com/mojang/brigadier/tree/RootCommandNodeTest.java index ab183fa..8de1fcb 100644 --- a/src/test/java/com/mojang/brigadier/tree/RootCommandNodeTest.java +++ b/src/test/java/com/mojang/brigadier/tree/RootCommandNodeTest.java @@ -9,6 +9,7 @@ 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; @@ -48,10 +49,8 @@ public class RootCommandNodeTest extends AbstractCommandNodeTest { @Test public void testSuggestions() throws Exception { - final Set set = Sets.newHashSet(); - @SuppressWarnings("unchecked") final CommandContextBuilder context = Mockito.mock(CommandContextBuilder.class); - node.listSuggestions("", set, context); - assertThat(set, is(empty())); + final Collection result = node.listSuggestions("").join(); + assertThat(result, is(empty())); } @Test(expected = IllegalStateException.class)