New suggestion API

This commit is contained in:
Nathan Adams
2017-11-20 13:45:05 +01:00
parent 557352f289
commit 095498c94e
21 changed files with 494 additions and 150 deletions
@@ -11,6 +11,8 @@ import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.context.StringRange;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import com.mojang.brigadier.tree.RootCommandNode;
@@ -310,7 +312,7 @@ public class CommandDispatcher<S> {
return self;
}
public CompletableFuture<CommandSuggestions> getCompletionSuggestions(final ParseResults<S> parse) {
public CompletableFuture<Suggestions> getCompletionSuggestions(final ParseResults<S> parse) {
final CommandContextBuilder<S> rootContext = parse.getContext();
final CommandContextBuilder<S> context = rootContext.getLastChild();
final CommandNode<S> parent;
@@ -336,25 +338,23 @@ public class CommandDispatcher<S> {
start = 0;
}
@SuppressWarnings("unchecked") final CompletableFuture<Collection<String>>[] futures = new CompletableFuture[parent.getChildren().size()];
@SuppressWarnings("unchecked") final CompletableFuture<Suggestions>[] futures = new CompletableFuture[parent.getChildren().size()];
int i = 0;
for (final CommandNode<S> node : parent.getChildren()) {
try {
futures[i++] = node.listSuggestions(context.build(parse.getReader().getString()), parse.getReader().getString().substring(start));
futures[i++] = node.listSuggestions(context.build(parse.getReader().getString()), new SuggestionsBuilder(parse.getReader().getString(), start));
} catch (final CommandSyntaxException e) {
futures[i++] = CompletableFuture.completedFuture(Collections.emptyList());
futures[i++] = Suggestions.empty();
}
}
final CompletableFuture<CommandSuggestions> result = new CompletableFuture<>();
final CompletableFuture<Suggestions> result = new CompletableFuture<>();
CompletableFuture.allOf(futures).thenRun(() -> {
final Set<String> suggestions = Sets.newHashSet();
for (final CompletableFuture<Collection<String>> future : futures) {
suggestions.addAll(future.join());
final List<Suggestions> suggestions = Lists.newArrayList();
for (final CompletableFuture<Suggestions> future : futures) {
suggestions.add(future.join());
}
final List<String> sorted = new ArrayList<>(suggestions);
Collections.sort(sorted);
result.complete(new CommandSuggestions(new StringRange(start, parse.getReader().getTotalLength()), sorted));
result.complete(Suggestions.merge(suggestions));
});
return result;
@@ -1,55 +0,0 @@
package com.mojang.brigadier;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.StringRange;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
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;
private final List<String> suggestions;
public CommandSuggestions(final StringRange range, final List<String> suggestions) {
this.range = range;
this.suggestions = suggestions;
}
public StringRange getRange() {
return range;
}
public List<String> getSuggestions() {
return suggestions;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof CommandSuggestions)) {
return false;
}
final CommandSuggestions that = (CommandSuggestions) o;
return Objects.equals(range, that.range) && Objects.equals(suggestions, that.suggestions);
}
@Override
public int hashCode() {
return Objects.hash(range, suggestions);
}
public boolean isEmpty() {
return suggestions.isEmpty();
}
@FunctionalInterface
public interface Provider<S> {
CompletableFuture<Collection<String>> getSuggestions(final CommandContext<S> context, final String prefix) throws CommandSyntaxException;
}
}
@@ -4,15 +4,15 @@ import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import java.util.Collection;
import java.util.Collections;
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 CommandContext<S> context, final String command) {
return CompletableFuture.completedFuture(Collections.emptyList());
default <S> CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) {
return Suggestions.empty();
}
}
@@ -1,13 +1,12 @@
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 com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public class BoolArgumentType implements ArgumentType<Boolean> {
@@ -28,16 +27,13 @@ public class BoolArgumentType implements ArgumentType<Boolean> {
}
@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");
public <S> CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) {
if ("true".startsWith(builder.getRemaining().toLowerCase())) {
builder.suggest("true");
}
if ("false".startsWith(command)) {
result.add("false");
if ("false".startsWith(builder.getRemaining().toLowerCase())) {
builder.suggest("false");
}
return CompletableFuture.completedFuture(result);
return builder.buildFuture();
}
}
@@ -1,14 +1,14 @@
package com.mojang.brigadier.builder;
import com.mojang.brigadier.CommandSuggestions;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.tree.ArgumentCommandNode;
import com.mojang.brigadier.tree.CommandNode;
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 SuggestionProvider<S> suggestionsProvider = null;
private RequiredArgumentBuilder(final String name, final ArgumentType<T> type) {
this.name = name;
@@ -19,12 +19,12 @@ public class RequiredArgumentBuilder<S, T> extends ArgumentBuilder<S, RequiredAr
return new RequiredArgumentBuilder<>(name, type);
}
public RequiredArgumentBuilder<S, T> suggests(final CommandSuggestions.Provider<S> provider) {
public RequiredArgumentBuilder<S, T> suggests(final SuggestionProvider<S> provider) {
this.suggestionsProvider = provider;
return getThis();
}
public CommandSuggestions.Provider<S> getSuggestionsProvider() {
public SuggestionProvider<S> getSuggestionsProvider() {
return suggestionsProvider;
}
@@ -0,0 +1,68 @@
package com.mojang.brigadier.suggestion;
import com.mojang.brigadier.context.StringRange;
import java.util.Objects;
public class Suggestion implements Comparable<Suggestion> {
private final StringRange range;
private final String text;
public Suggestion(final StringRange range, final String text) {
this.range = range;
this.text = text;
}
public StringRange getRange() {
return range;
}
public String getText() {
return text;
}
public String apply(final String input) {
if (range.getStart() == 0 && range.getEnd() == input.length()) {
return text;
}
final StringBuilder result = new StringBuilder();
if (range.getStart() > 0) {
result.append(input.substring(0, range.getStart()));
}
result.append(text);
if (range.getEnd() < input.length()) {
result.append(input.substring(range.getEnd()));
}
return result.toString();
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Suggestion)) {
return false;
}
final Suggestion that = (Suggestion) o;
return Objects.equals(range, that.range) && Objects.equals(text, that.text);
}
@Override
public int hashCode() {
return Objects.hash(range, text);
}
@Override
public String toString() {
return "Suggestion{" +
"range=" + range +
", text='" + text + '\'' +
'}';
}
@Override
public int compareTo(final Suggestion o) {
return text.compareTo(o.text);
}
}
@@ -0,0 +1,11 @@
package com.mojang.brigadier.suggestion;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import java.util.concurrent.CompletableFuture;
@FunctionalInterface
public interface SuggestionProvider<S> {
CompletableFuture<Suggestions> getSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) throws CommandSyntaxException;
}
@@ -0,0 +1,92 @@
package com.mojang.brigadier.suggestion;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
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.Set;
import java.util.concurrent.CompletableFuture;
public class Suggestions {
private static final Suggestions EMPTY = new Suggestions("", Lists.newArrayList());
private final String input;
private final StringRange range;
private final List<Suggestion> suggestions;
public Suggestions(final String input, final List<Suggestion> suggestions) {
this.input = input;
this.suggestions = suggestions;
if (suggestions.isEmpty()) {
range = new StringRange(input.length(), input.length());
} else {
int start = Integer.MAX_VALUE;
int end = Integer.MIN_VALUE;
for (final Suggestion suggestion : suggestions) {
start = Math.min(start, suggestion.getRange().getStart());
end = Math.max(end, suggestion.getRange().getEnd());
}
range = new StringRange(start, end);
}
}
public String getInput() {
return input;
}
public StringRange getRange() {
return range;
}
public List<Suggestion> getList() {
return suggestions;
}
public boolean isEmpty() {
return suggestions.isEmpty();
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Suggestions)) {
return false;
}
final Suggestions that = (Suggestions) o;
return Objects.equals(input, that.input) &&
Objects.equals(range, that.range) &&
Objects.equals(suggestions, that.suggestions);
}
@Override
public int hashCode() {
return Objects.hash(input, range, suggestions);
}
public static CompletableFuture<Suggestions> empty() {
return CompletableFuture.completedFuture(EMPTY);
}
public static Suggestions merge(final Collection<Suggestions> inputs) {
if (inputs.isEmpty()) {
return EMPTY;
} else if (inputs.size() == 1) {
return inputs.iterator().next();
}
final Set<Suggestion> suggestions = Sets.newHashSet();
for (final Suggestions input : inputs) {
suggestions.addAll(input.getList());
}
final List<Suggestion> sorted = Lists.newArrayList(suggestions);
Collections.sort(sorted);
return new Suggestions(inputs.iterator().next().getInput(), sorted);
}
}
@@ -0,0 +1,54 @@
package com.mojang.brigadier.suggestion;
import com.google.common.base.Strings;
import com.mojang.brigadier.context.StringRange;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public class SuggestionsBuilder {
private final String input;
private final int start;
private final String remaining;
private final List<Suggestion> result = new ArrayList<>();
public SuggestionsBuilder(final String input, final int start) {
this.input = input;
this.start = start;
this.remaining = input.substring(start);
}
public String getInput() {
return input;
}
public int getStart() {
return start;
}
public String getRemaining() {
return remaining;
}
public Suggestions build() {
return new Suggestions(input, result);
}
public CompletableFuture<Suggestions> buildFuture() {
return CompletableFuture.completedFuture(new Suggestions(input, result));
}
public SuggestionsBuilder suggest(final String text) {
if (text.equals(remaining)) {
return this;
}
final String prefix = Strings.commonPrefix(text, remaining);
result.add(new Suggestion(new StringRange(start + prefix.length(), input.length()), text.substring(prefix.length())));
return this;
}
public SuggestionsBuilder restart() {
return new SuggestionsBuilder(input, start);
}
}
@@ -1,7 +1,6 @@
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;
@@ -10,8 +9,10 @@ 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 com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
@@ -21,9 +22,9 @@ public class ArgumentCommandNode<S, T> extends CommandNode<S> {
private final String name;
private final ArgumentType<T> type;
private final CommandSuggestions.Provider<S> customSuggestions;
private final SuggestionProvider<S> customSuggestions;
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> customSuggestions) {
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 SuggestionProvider<S> customSuggestions) {
super(command, requirement, redirect, modifier);
this.name = name;
this.type = type;
@@ -44,7 +45,7 @@ public class ArgumentCommandNode<S, T> extends CommandNode<S> {
return USAGE_ARGUMENT_OPEN + name + USAGE_ARGUMENT_CLOSE;
}
public CommandSuggestions.Provider<S> getCustomSuggestions() {
public SuggestionProvider<S> getCustomSuggestions() {
return customSuggestions;
}
@@ -59,11 +60,11 @@ public class ArgumentCommandNode<S, T> extends CommandNode<S> {
}
@Override
public CompletableFuture<Collection<String>> listSuggestions(final CommandContext<S> context, final String command) throws CommandSyntaxException {
public CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) throws CommandSyntaxException {
if (customSuggestions == null) {
return type.listSuggestions(context, command);
return type.listSuggestions(context, builder);
} else {
return customSuggestions.getSuggestions(context, command);
return customSuggestions.getSuggestions(context, builder);
}
}
@@ -9,6 +9,8 @@ import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import java.util.Collection;
import java.util.LinkedHashMap;
@@ -104,7 +106,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(CommandContext<S> context, String command) throws CommandSyntaxException;
public abstract CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) throws CommandSyntaxException;
public abstract ArgumentBuilder<S, ?> createBuilder();
@@ -9,9 +9,9 @@ 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 com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
@@ -50,11 +50,11 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
}
@Override
public CompletableFuture<Collection<String>> listSuggestions(final CommandContext<S> context, final String command) {
if (literal.toLowerCase().startsWith(command.toLowerCase())) {
return CompletableFuture.completedFuture(Collections.singleton(literal));
public CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) {
if (literal.toLowerCase().startsWith(builder.getRemaining().toLowerCase())) {
return builder.suggest(literal).buildFuture();
} else {
return CompletableFuture.completedFuture(Collections.emptyList());
return Suggestions.empty();
}
}
@@ -5,8 +5,9 @@ import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;
@@ -30,8 +31,8 @@ public class RootCommandNode<S> extends CommandNode<S> {
}
@Override
public CompletableFuture<Collection<String>> listSuggestions(CommandContext<S> context, final String command) {
return CompletableFuture.completedFuture(Collections.emptyList());
public CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) {
return Suggestions.empty();
}
@Override
@@ -2,6 +2,8 @@ package com.mojang.brigadier;
import com.google.common.collect.Lists;
import com.mojang.brigadier.context.StringRange;
import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.tree.LiteralCommandNode;
import org.junit.Before;
import org.junit.Test;
@@ -14,6 +16,7 @@ import static com.mojang.brigadier.arguments.StringArgumentType.word;
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
import static com.mojang.brigadier.builder.RequiredArgumentBuilder.argument;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
@RunWith(MockitoJUnitRunner.class)
@@ -33,10 +36,14 @@ public class CommandSuggestionsTest {
subject.register(literal("bar"));
subject.register(literal("baz"));
final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("", source)).join();
final Suggestions result = subject.getCompletionSuggestions(subject.parse("", source)).join();
assertThat(result.getRange(), equalTo(new StringRange(0, 0)));
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz", "foo")));
assertThat(result.getList(), equalTo(Lists.newArrayList(
new Suggestion(new StringRange(0, 0), "bar"),
new Suggestion(new StringRange(0, 0), "baz"),
new Suggestion(new StringRange(0, 0), "foo")
)));
}
@Test
@@ -45,10 +52,13 @@ public class CommandSuggestionsTest {
subject.register(literal("bar"));
subject.register(literal("baz"));
final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("b", source)).join();
final Suggestions result = subject.getCompletionSuggestions(subject.parse("b", source)).join();
assertThat(result.getRange(), equalTo(new StringRange(0, 1)));
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz")));
assertThat(result.getRange(), equalTo(new StringRange(1, 1)));
assertThat(result.getList(), equalTo(Lists.newArrayList(
new Suggestion(new StringRange(1, 1), "ar"),
new Suggestion(new StringRange(1, 1), "az")
)));
}
@Test
@@ -60,10 +70,14 @@ public class CommandSuggestionsTest {
.then(literal("baz"))
);
final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("parent ", source)).join();
final Suggestions 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")));
assertThat(result.getList(), equalTo(Lists.newArrayList(
new Suggestion(new StringRange(7, 7), "bar"),
new Suggestion(new StringRange(7, 7), "baz"),
new Suggestion(new StringRange(7, 7), "foo")
)));
}
@Test
@@ -76,10 +90,13 @@ public class CommandSuggestionsTest {
);
final ParseResults<Object> parse = subject.parse("parent b", source);
final CommandSuggestions result = subject.getCompletionSuggestions(parse).join();
final Suggestions result = subject.getCompletionSuggestions(parse).join();
assertThat(result.getRange(), equalTo(new StringRange(7, 8)));
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz")));
assertThat(result.getRange(), equalTo(new StringRange(8, 8)));
assertThat(result.getList(), equalTo(Lists.newArrayList(
new Suggestion(new StringRange(8, 8), "ar"),
new Suggestion(new StringRange(8, 8), "az")
)));
}
@Test
@@ -88,10 +105,12 @@ public class CommandSuggestionsTest {
subject.register(literal("redirect").redirect(actual));
final ParseResults<Object> parse = subject.parse("redirect ", source);
final CommandSuggestions result = subject.getCompletionSuggestions(parse).join();
final Suggestions result = subject.getCompletionSuggestions(parse).join();
assertThat(result.getRange(), equalTo(new StringRange(9, 9)));
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("sub")));
assertThat(result.getList(), equalTo(Lists.newArrayList(
new Suggestion(new StringRange(9, 9), "sub")
)));
}
@Test
@@ -100,10 +119,12 @@ public class CommandSuggestionsTest {
subject.register(literal("redirect").redirect(actual));
final ParseResults<Object> parse = subject.parse("redirect s", source);
final CommandSuggestions result = subject.getCompletionSuggestions(parse).join();
final Suggestions result = subject.getCompletionSuggestions(parse).join();
assertThat(result.getRange(), equalTo(new StringRange(9, 10)));
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("sub")));
assertThat(result.getRange(), equalTo(new StringRange(10, 10)));
assertThat(result.getList(), equalTo(Lists.newArrayList(
new Suggestion(new StringRange(10, 10), "ub")
)));
}
@Test
@@ -120,10 +141,12 @@ public class CommandSuggestionsTest {
)
);
final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("redirect loop 1 loop 02 loop 003 ", source)).join();
final Suggestions result = subject.getCompletionSuggestions(subject.parse("redirect loop 1 loop 02 loop 003 ", source)).join();
assertThat(result.getRange(), equalTo(new StringRange(33, 33)));
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("loop")));
assertThat(result.getList(), equalTo(Lists.newArrayList(
new Suggestion(new StringRange(33, 33), "loop")
)));
}
@Test
@@ -152,10 +175,9 @@ public class CommandSuggestionsTest {
);
final ParseResults<Object> parse = subject.parse("execute as Dinnerbone as", source);
final CommandSuggestions result = subject.getCompletionSuggestions(parse).join();
final Suggestions result = subject.getCompletionSuggestions(parse).join();
assertThat(result.getRange(), equalTo(new StringRange(22, 24)));
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("as")));
assertThat(result.isEmpty(), is(true));
}
@Test
@@ -182,9 +204,12 @@ public class CommandSuggestionsTest {
);
final ParseResults<Object> parse = subject.parse("execute as bar as ", source);
final CommandSuggestions result = subject.getCompletionSuggestions(parse).join();
final Suggestions result = subject.getCompletionSuggestions(parse).join();
assertThat(result.getRange(), equalTo(new StringRange(18, 18)));
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz")));
assertThat(result.getList(), equalTo(Lists.newArrayList(
new Suggestion(new StringRange(18, 18), "bar"),
new Suggestion(new StringRange(18, 18), "baz")
)));
}
}
@@ -0,0 +1,51 @@
package com.mojang.brigadier.suggestion;
import com.mojang.brigadier.context.StringRange;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
public class SuggestionTest {
@Test
public void apply_insertation_start() {
final Suggestion suggestion = new Suggestion(new StringRange(0, 0), "And so I said: ");
assertThat(suggestion.apply("Hello world!"), equalTo("And so I said: Hello world!"));
}
@Test
public void apply_insertation_middle() {
final Suggestion suggestion = new Suggestion(new StringRange(6, 6), "small ");
assertThat(suggestion.apply("Hello world!"), equalTo("Hello small world!"));
}
@Test
public void apply_insertation_end() {
final Suggestion suggestion = new Suggestion(new StringRange(5, 5), " world!");
assertThat(suggestion.apply("Hello"), equalTo("Hello world!"));
}
@Test
public void apply_replacement_start() {
final Suggestion suggestion = new Suggestion(new StringRange(0, 5), "Goodbye");
assertThat(suggestion.apply("Hello world!"), equalTo("Goodbye world!"));
}
@Test
public void apply_replacement_middle() {
final Suggestion suggestion = new Suggestion(new StringRange(6, 11), "Alex");
assertThat(suggestion.apply("Hello world!"), equalTo("Hello Alex!"));
}
@Test
public void apply_replacement_end() {
final Suggestion suggestion = new Suggestion(new StringRange(6, 12), "Creeper!");
assertThat(suggestion.apply("Hello world!"), equalTo("Hello Creeper!"));
}
@Test
public void apply_replacement_everything() {
final Suggestion suggestion = new Suggestion(new StringRange(0, 12), "Oh dear.");
assertThat(suggestion.apply("Hello world!"), equalTo("Oh dear."));
}
}
@@ -0,0 +1,62 @@
package com.mojang.brigadier.suggestion;
import com.google.common.collect.Lists;
import com.mojang.brigadier.context.StringRange;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
public class SuggestionsBuilderTest {
private SuggestionsBuilder builder;
@Before
public void setUp() throws Exception {
builder = new SuggestionsBuilder("Hello w", 6);
}
@Test
public void suggest_appends() {
final Suggestions result = builder.suggest("world!").build();
assertThat(result.getList(), equalTo(Lists.newArrayList(new Suggestion(new StringRange(7, 7), "orld!"))));
assertThat(result.getRange(), equalTo(new StringRange(7, 7)));
assertThat(result.isEmpty(), is(false));
}
@Test
public void suggest_replaces() {
final Suggestions result = builder.suggest("everybody").build();
assertThat(result.getList(), equalTo(Lists.newArrayList(new Suggestion(new StringRange(6, 7), "everybody"))));
assertThat(result.getRange(), equalTo(new StringRange(6, 7)));
assertThat(result.isEmpty(), is(false));
}
@Test
public void suggest_noop() {
final Suggestions result = builder.suggest("w").build();
assertThat(result.getList(), equalTo(Lists.newArrayList()));
assertThat(result.getRange(), equalTo(new StringRange(7, 7)));
assertThat(result.isEmpty(), is(true));
}
@Test
public void suggest_multiple() {
final Suggestions result = builder.suggest("world!").suggest("everybody").suggest("weekend").build();
assertThat(result.getList(), equalTo(Lists.newArrayList(new Suggestion(new StringRange(7, 7), "orld!"), new Suggestion(new StringRange(6, 7), "everybody"), new Suggestion(new StringRange(7, 7), "eekend"))));
assertThat(result.getRange(), equalTo(new StringRange(6, 7)));
assertThat(result.isEmpty(), is(false));
}
@Test
public void restart() {
builder.suggest("won't be included in restart");
final SuggestionsBuilder other = builder.restart();
assertThat(other, is(not(builder)));
assertThat(other.getInput(), equalTo(builder.getInput()));
assertThat(other.getStart(), is(builder.getStart()));
assertThat(other.getRemaining(), equalTo(builder.getRemaining()));
}
}
@@ -0,0 +1,38 @@
package com.mojang.brigadier.suggestion;
import com.google.common.collect.Lists;
import com.mojang.brigadier.context.StringRange;
import org.junit.Test;
import java.util.Collections;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
public class SuggestionsTest {
@Test
public void merge_empty() {
final Suggestions merged = Suggestions.merge(Collections.emptyList());
assertThat(merged.isEmpty(), is(true));
}
@Test
public void merge_single() {
final Suggestions suggestions = new Suggestions("", Lists.newArrayList(new Suggestion(new StringRange(0, 0), "foo")));
final Suggestions merged = Suggestions.merge(Collections.singleton(suggestions));
assertThat(merged, equalTo(suggestions));
}
@Test
public void merge_multiple() {
final Suggestion foo = new Suggestion(new StringRange(0, 0), "foo");
final Suggestion bar = new Suggestion(new StringRange(0, 0), "bar");
final Suggestion baz = new Suggestion(new StringRange(0, 0), "baz");
final Suggestion qux = new Suggestion(new StringRange(0, 0), "qux");
final Suggestions a = new Suggestions("", Lists.newArrayList(foo, bar));
final Suggestions b = new Suggestions("", Lists.newArrayList(baz, qux));
final Suggestions merged = Suggestions.merge(Lists.newArrayList(a, b));
assertThat(merged.getList(), equalTo(Lists.newArrayList(bar, baz, foo, qux)));
}
}
@@ -5,16 +5,14 @@ import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import org.junit.Before;
import org.junit.Test;
import java.util.Collection;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static com.mojang.brigadier.builder.RequiredArgumentBuilder.argument;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
@@ -50,8 +48,8 @@ public class ArgumentCommandNodeTest extends AbstractCommandNodeTest {
@Test
public void testSuggestions() throws Exception {
final Collection<String> result = node.listSuggestions(contextBuilder.build(""), "").join();
assertThat(result, is(empty()));
final Suggestions result = node.listSuggestions(contextBuilder.build(""), new SuggestionsBuilder("", 0)).join();
assertThat(result.isEmpty(), is(true));
}
@Test
@@ -1,21 +1,22 @@
package com.mojang.brigadier.tree;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.google.common.collect.Lists;
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.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.context.StringRange;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import org.junit.Before;
import org.junit.Test;
import java.util.Collection;
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
@@ -79,17 +80,17 @@ public class LiteralCommandNodeTest extends AbstractCommandNodeTest {
@Test
public void testSuggestions() throws Exception {
final Collection<String> empty = node.listSuggestions(contextBuilder.build(""), "").join();
assertThat(empty, equalTo(Sets.newHashSet("foo")));
final Suggestions empty = node.listSuggestions(contextBuilder.build(""), new SuggestionsBuilder("", 0)).join();
assertThat(empty.getList(), equalTo(Lists.newArrayList(new Suggestion(new StringRange(0, 0), "foo"))));
final Collection<String> foo = node.listSuggestions(contextBuilder.build("foo"), "foo").join();
assertThat(foo, equalTo(Sets.newHashSet("foo")));
final Suggestions foo = node.listSuggestions(contextBuilder.build("foo"), new SuggestionsBuilder("foo", 0)).join();
assertThat(foo.isEmpty(), is(true));
final Collection<String> food = node.listSuggestions(contextBuilder.build("food"), "food").join();
assertThat(food, is(empty()));
final Suggestions food = node.listSuggestions(contextBuilder.build("food"), new SuggestionsBuilder("food", 0)).join();
assertThat(food.isEmpty(), is(true));
final Collection<String> b = node.listSuggestions(contextBuilder.build("b"), "b").join();
assertThat(b, is(empty()));
final Suggestions b = node.listSuggestions(contextBuilder.build("b"), new SuggestionsBuilder("b", 0)).join();
assertThat(food.isEmpty(), is(true));
}
@Test
@@ -5,13 +5,12 @@ import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import org.junit.Before;
import org.junit.Test;
import java.util.Collection;
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;
@@ -49,8 +48,8 @@ public class RootCommandNodeTest extends AbstractCommandNodeTest {
@Test
public void testSuggestions() throws Exception {
final CommandContext<Object> context = mock(CommandContext.class);
final Collection<String> result = node.listSuggestions(context, "").join();
assertThat(result, is(empty()));
final Suggestions result = node.listSuggestions(context, new SuggestionsBuilder("", 0)).join();
assertThat(result.isEmpty(), is(true));
}
@Test(expected = IllegalStateException.class)