Fixed issues with suggesting redirects

This commit is contained in:
Nathan Adams 2017-11-15 16:13:52 +01:00
parent 87f65f2bd2
commit 1f201022dd
7 changed files with 142 additions and 10 deletions

View file

@ -3,7 +3,7 @@ import groovy.io.FileType
apply plugin: 'java-library' apply plugin: 'java-library'
apply plugin: 'maven' apply plugin: 'maven'
version = '0.1.10' version = '0.1.11'
group = 'com.mojang' group = 'com.mojang'
task wrapper(type: Wrapper) { task wrapper(type: Wrapper) {

View file

@ -177,11 +177,11 @@ public class CommandDispatcher<S> {
} }
context.withCommand(child.getCommand()); context.withCommand(child.getCommand());
if (reader.canRead(2)) { if (reader.canRead(child.getRedirect() == null ? 2 : 1)) {
reader.skip(); reader.skip();
if (child.getRedirect() != null) { if (child.getRedirect() != null) {
final CommandContextBuilder<S> childContext = new CommandContextBuilder<>(this, source, reader.getCursor()); final CommandContextBuilder<S> childContext = new CommandContextBuilder<>(this, source, reader.getCursor());
childContext.withNode(child.getRedirect(), new StringRange(reader.getCursor(), reader.getCursor())); childContext.withNode(child.getRedirect(), new StringRange(cursor, reader.getCursor() - 1));
final ParseResults<S> parse = parseNodes(child.getRedirect(), reader, childContext); final ParseResults<S> parse = parseNodes(child.getRedirect(), reader, childContext);
context.withChild(parse.getContext()); context.withChild(parse.getContext());
return new ParseResults<>(context, parse.getReader(), parse.getExceptions()); return new ParseResults<>(context, parse.getReader(), parse.getExceptions());
@ -311,7 +311,8 @@ public class CommandDispatcher<S> {
} }
public CompletableFuture<CommandSuggestions> getCompletionSuggestions(final ParseResults<S> parse) { public CompletableFuture<CommandSuggestions> getCompletionSuggestions(final ParseResults<S> parse) {
final CommandContextBuilder<S> context = parse.getContext(); final CommandContextBuilder<S> rootContext = parse.getContext();
final CommandContextBuilder<S> context = rootContext.getLastChild();
final CommandNode<S> parent; final CommandNode<S> parent;
final int start; final int start;
@ -326,6 +327,10 @@ public class CommandDispatcher<S> {
final Map.Entry<CommandNode<S>, StringRange> entry = Iterables.get(context.getNodes().entrySet(), context.getNodes().size() - 2); final Map.Entry<CommandNode<S>, StringRange> entry = Iterables.get(context.getNodes().entrySet(), context.getNodes().size() - 2);
parent = entry.getKey(); parent = entry.getKey();
start = entry.getValue().getEnd() + 1; start = entry.getValue().getEnd() + 1;
} else if (rootContext != context && context.getNodes().size() > 0) {
final Map.Entry<CommandNode<S>, StringRange> entry = Iterables.getLast(context.getNodes().entrySet());
parent = entry.getKey();
start = entry.getValue().getEnd() + 1;
} else { } else {
parent = root; parent = root;
start = 0; start = 0;

View file

@ -30,6 +30,14 @@ public class CommandContext<S> {
return child; return child;
} }
public CommandContext<S> getLastChild() {
CommandContext<S> result = this;
while (result.getChild() != null) {
result = result.getChild();
}
return result;
}
public Command<S> getCommand() { public Command<S> getCommand() {
return command; return command;
} }

View file

@ -70,6 +70,14 @@ public class CommandContextBuilder<S> {
return child; return child;
} }
public CommandContextBuilder<S> getLastChild() {
CommandContextBuilder<S> result = this;
while (result.getChild() != null) {
result = result.getChild();
}
return result;
}
public Command<S> getCommand() { public Command<S> getCommand() {
return command; return command;
} }

View file

@ -50,9 +50,9 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
} }
@Override @Override
public CompletableFuture<Collection<String>> listSuggestions(CommandContext<S> context, final String command) { public CompletableFuture<Collection<String>> listSuggestions(final CommandContext<S> context, final String command) {
if (literal.toLowerCase().startsWith(command.toLowerCase())) { if (literal.toLowerCase().startsWith(command.toLowerCase())) {
return CompletableFuture.completedFuture(Collections.singleton(literal)); return CompletableFuture.completedFuture(Collections.singleton(literal + " "));
} else { } else {
return CompletableFuture.completedFuture(Collections.emptyList()); return CompletableFuture.completedFuture(Collections.emptyList());
} }

View file

@ -259,12 +259,12 @@ public class CommandDispatcherTest {
final CommandContextBuilder<Object> child1 = parse.getContext().getChild(); final CommandContextBuilder<Object> child1 = parse.getContext().getChild();
assertThat(child1, is(notNullValue())); assertThat(child1, is(notNullValue()));
assertThat(child1.getRange().get(input), equalTo("redirected")); assertThat(child1.getRange().get(input), equalTo("redirected redirected"));
assertThat(child1.getNodes().size(), is(2)); assertThat(child1.getNodes().size(), is(2));
final CommandContextBuilder<Object> child2 = child1.getChild(); final CommandContextBuilder<Object> child2 = child1.getChild();
assertThat(child2, is(notNullValue())); assertThat(child2, is(notNullValue()));
assertThat(child2.getRange().get(input), equalTo("actual")); assertThat(child2.getRange().get(input), equalTo("redirected actual"));
assertThat(child2.getNodes().size(), is(2)); assertThat(child2.getNodes().size(), is(2));
assertThat(subject.execute(parse), is(42)); assertThat(subject.execute(parse), is(42));
@ -291,7 +291,7 @@ public class CommandDispatcherTest {
final CommandContextBuilder<Object> parent = parse.getContext().getChild(); final CommandContextBuilder<Object> parent = parse.getContext().getChild();
assertThat(parent, is(notNullValue())); assertThat(parent, is(notNullValue()));
assertThat(parent.getRange().get(input), equalTo("actual")); assertThat(parent.getRange().get(input), equalTo("redirected actual"));
assertThat(parent.getNodes().size(), is(2)); assertThat(parent.getNodes().size(), is(2));
assertThat(parent.getSource(), is(source)); assertThat(parent.getSource(), is(source));

View file

@ -2,13 +2,17 @@ package com.mojang.brigadier;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.mojang.brigadier.context.StringRange; import com.mojang.brigadier.context.StringRange;
import com.mojang.brigadier.tree.LiteralCommandNode;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static com.mojang.brigadier.arguments.StringArgumentType.word;
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal; 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.equalTo;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
@ -71,9 +75,116 @@ public class CommandSuggestionsTest {
.then(literal("baz")) .then(literal("baz"))
); );
final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("parent b", source)).join(); final ParseResults<Object> parse = subject.parse("parent b", source);
final CommandSuggestions result = subject.getCompletionSuggestions(parse).join();
assertThat(result.getRange(), equalTo(new StringRange(7, 8))); assertThat(result.getRange(), equalTo(new StringRange(7, 8)));
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz"))); assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz")));
} }
@Test
public void getCompletionSuggestions_redirect() throws Exception {
final LiteralCommandNode<Object> actual = subject.register(literal("actual").then(literal("sub")));
subject.register(literal("redirect").redirect(actual));
final ParseResults<Object> parse = subject.parse("redirect ", source);
final CommandSuggestions result = subject.getCompletionSuggestions(parse).join();
assertThat(result.getRange(), equalTo(new StringRange(9, 9)));
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("sub")));
}
@Test
public void getCompletionSuggestions_redirectPartial() throws Exception {
final LiteralCommandNode<Object> actual = subject.register(literal("actual").then(literal("sub")));
subject.register(literal("redirect").redirect(actual));
final ParseResults<Object> parse = subject.parse("redirect s", source);
final CommandSuggestions result = subject.getCompletionSuggestions(parse).join();
assertThat(result.getRange(), equalTo(new StringRange(9, 10)));
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("sub")));
}
@Test
public void getCompletionSuggestions_redirect_lots() throws Exception {
final LiteralCommandNode<Object> loop = subject.register(literal("redirect"));
subject.register(
literal("redirect")
.then(
literal("loop")
.then(
argument("loop", integer())
.redirect(loop)
)
)
);
final CommandSuggestions 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")));
}
@Test
public void getCompletionSuggestions_execute_simulation() throws Exception {
final LiteralCommandNode<Object> execute = subject.register(literal("execute"));
subject.register(
literal("execute")
.then(
literal("as")
.then(
argument("name", word())
.redirect(execute)
)
)
.then(
literal("store")
.then(
argument("name", word())
.redirect(execute)
)
)
.then(
literal("run")
.executes(c -> 0)
)
);
final ParseResults<Object> parse = subject.parse("execute as Dinnerbone as", source);
final CommandSuggestions result = subject.getCompletionSuggestions(parse).join();
assertThat(result.getRange(), equalTo(new StringRange(22, 24)));
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("as")));
}
@Test
public void getCompletionSuggestions_execute_simulation_partial() throws Exception {
final LiteralCommandNode<Object> execute = subject.register(literal("execute"));
subject.register(
literal("execute")
.then(
literal("as")
.then(literal("bar").redirect(execute))
.then(literal("baz").redirect(execute))
)
.then(
literal("store")
.then(
argument("name", word())
.redirect(execute)
)
)
.then(
literal("run")
.executes(c -> 0)
)
);
final ParseResults<Object> parse = subject.parse("execute as bar as ", source);
final CommandSuggestions result = subject.getCompletionSuggestions(parse).join();
assertThat(result.getRange(), equalTo(new StringRange(18, 18)));
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz")));
}
} }