Allow overriding of suggestion providers per argument

This commit is contained in:
Nathan Adams 2017-11-08 15:17:59 +01:00
parent 4f7c6d4e32
commit be0090873b
16 changed files with 77 additions and 50 deletions

View file

@ -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) {

View file

@ -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<S> {
@SuppressWarnings("unchecked") final CompletableFuture<Collection<String>>[] futures = new CompletableFuture[parent.getChildren().size()];
int i = 0;
for (final CommandNode<S> 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<CommandSuggestions> result = new CompletableFuture<>();

View file

@ -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<S> {
CompletableFuture<Collection<String>> getSuggestions(final CommandContext<S> context, final String prefix);
}
}

View file

@ -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> {
<S> T parse(StringReader reader, CommandContextBuilder<S> contextBuilder) throws CommandSyntaxException;
default <S> CompletableFuture<Collection<String>> listSuggestions(final String command) {
default <S> CompletableFuture<Collection<String>> listSuggestions(final CommandContext<S> context, final String command) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
}

View file

@ -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<Boolean> {
private BoolArgumentType() {
}
@ -21,4 +26,18 @@ public class BoolArgumentType implements ArgumentType<Boolean> {
public <S> Boolean parse(final StringReader reader, final CommandContextBuilder<S> contextBuilder) throws CommandSyntaxException {
return reader.readBoolean();
}
@Override
public <S> CompletableFuture<Collection<String>> listSuggestions(final CommandContext<S> context, final String command) {
final List<String> result = Lists.newArrayList();
if ("true".startsWith(command)) {
result.add("true");
}
if ("false".startsWith(command)) {
result.add("false");
}
return CompletableFuture.completedFuture(result);
}
}

View file

@ -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;

View file

@ -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<S, T> extends ArgumentBuilder<S, RequiredArgumentBuilder<S, T>> {
private final String name;
private final ArgumentType<T> type;
private CommandSuggestions.Provider<S> suggestionsProvider = null;
private RequiredArgumentBuilder(final String name, final ArgumentType<T> type) {
this.name = name;
@ -17,6 +24,15 @@ public class RequiredArgumentBuilder<S, T> extends ArgumentBuilder<S, RequiredAr
return new RequiredArgumentBuilder<>(name, type);
}
public RequiredArgumentBuilder<S, T> suggests(final CommandSuggestions.Provider<S> provider) {
this.suggestionsProvider = provider;
return getThis();
}
public CommandSuggestions.Provider<S> getSuggestionsProvider() {
return suggestionsProvider == null ? type::listSuggestions : suggestionsProvider;
}
@Override
protected RequiredArgumentBuilder<S, T> getThis() {
return this;
@ -31,7 +47,7 @@ public class RequiredArgumentBuilder<S, T> extends ArgumentBuilder<S, RequiredAr
}
public ArgumentCommandNode<S, T> build() {
final ArgumentCommandNode<S, T> result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier());
final ArgumentCommandNode<S, T> result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier(), getSuggestionsProvider());
for (final CommandNode<S> argument : getArguments()) {
result.addChild(argument);

View file

@ -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<S, T> extends CommandNode<S> {
@ -19,11 +22,13 @@ public class ArgumentCommandNode<S, T> extends CommandNode<S> {
private final String name;
private final ArgumentType<T> type;
private final CommandSuggestions.Provider<S> suggestionsProvider;
public ArgumentCommandNode(final String name, final ArgumentType<T> type, final Command<S> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier) {
public ArgumentCommandNode(final String name, final ArgumentType<T> type, final Command<S> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier, final CommandSuggestions.Provider<S> 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<S, T> extends CommandNode<S> {
}
@Override
public CompletableFuture<Collection<String>> listSuggestions(final String command) {
return type.listSuggestions(command);
public CompletableFuture<Collection<String>> listSuggestions(final CommandContext<S> context, final String command) {
return suggestionsProvider.getSuggestions(context, command);
}
@Override
@ -64,6 +69,7 @@ public class ArgumentCommandNode<S, T> extends CommandNode<S> {
final RequiredArgumentBuilder<S, T> builder = RequiredArgumentBuilder.argument(name, type);
builder.requires(getRequirement());
builder.redirect(getRedirect(), getRedirectModifier());
builder.suggests(suggestionsProvider);
if (getCommand() != null) {
builder.executes(getCommand());
}

View file

@ -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<S> implements Comparable<CommandNode<S>> {
public abstract void parse(StringReader reader, CommandContextBuilder<S> contextBuilder) throws CommandSyntaxException;
public abstract CompletableFuture<Collection<String>> listSuggestions(String command);
public abstract CompletableFuture<Collection<String>> listSuggestions(CommandContext<S> context, String command);
public abstract ArgumentBuilder<S, ?> createBuilder();

View file

@ -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<S> extends CommandNode<S> {
@ -51,7 +50,7 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
}
@Override
public CompletableFuture<Collection<String>> listSuggestions(final String command) {
public CompletableFuture<Collection<String>> listSuggestions(CommandContext<S> context, final String command) {
if (literal.startsWith(command)) {
return CompletableFuture.completedFuture(Collections.singleton(literal));
} else {

View file

@ -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<S> extends CommandNode<S> {
}
@Override
public CompletableFuture<Collection<String>> listSuggestions(final String command) {
public CompletableFuture<Collection<String>> listSuggestions(CommandContext<S> context, final String command) {
return CompletableFuture.completedFuture(Collections.emptyList());
}

View file

@ -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<String> result = type.listSuggestions("").join();
assertThat(result, is(empty()));
}
@Test
public void testEquals() throws Exception {
new EqualsTester()

View file

@ -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<Integer> type;

View file

@ -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<Object, Integer> node;
@ -54,7 +50,7 @@ public class ArgumentCommandNodeTest extends AbstractCommandNodeTest {
@Test
public void testSuggestions() throws Exception {
final Collection<String> result = node.listSuggestions("").join();
final Collection<String> result = node.listSuggestions(contextBuilder.build(), "").join();
assertThat(result, is(empty()));
}

View file

@ -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<String> empty = node.listSuggestions("").join();
final Collection<String> empty = node.listSuggestions(contextBuilder.build(), "").join();
assertThat(empty, equalTo(Sets.newHashSet("foo")));
final Collection<String> foo = node.listSuggestions("foo").join();
final Collection<String> foo = node.listSuggestions(contextBuilder.build(), "foo").join();
assertThat(foo, equalTo(Sets.newHashSet("foo")));
final Collection<String> food = node.listSuggestions("food").join();
final Collection<String> food = node.listSuggestions(contextBuilder.build(), "food").join();
assertThat(food, is(empty()));
final Collection<String> b = node.listSuggestions("b").join();
final Collection<String> b = node.listSuggestions(contextBuilder.build(), "b").join();
assertThat(b, is(empty()));
}

View file

@ -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<Object> node;
@ -49,7 +48,8 @@ public class RootCommandNodeTest extends AbstractCommandNodeTest {
@Test
public void testSuggestions() throws Exception {
final Collection<String> result = node.listSuggestions("").join();
final CommandContext<Object> context = mock(CommandContext.class);
final Collection<String> result = node.listSuggestions(context, "").join();
assertThat(result, is(empty()));
}