Reimplemented command suggestions
This commit is contained in:
+1
-1
@@ -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.3'
|
version = '0.1.4'
|
||||||
group = 'com.mojang'
|
group = 'com.mojang'
|
||||||
|
|
||||||
task wrapper(type: Wrapper) {
|
task wrapper(type: Wrapper) {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.mojang.brigadier;
|
package com.mojang.brigadier;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Iterators;
|
import com.google.common.collect.Iterators;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
|
||||||
import com.mojang.brigadier.context.CommandContextBuilder;
|
import com.mojang.brigadier.context.CommandContextBuilder;
|
||||||
import com.mojang.brigadier.context.StringRange;
|
import com.mojang.brigadier.context.StringRange;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
@@ -19,10 +19,10 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -285,42 +285,37 @@ public class CommandDispatcher<S> {
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> findSuggestions(final CommandNode<S> node, final StringReader reader, final CommandContextBuilder<S> contextBuilder, final Set<String> result) {
|
public CommandSuggestions getCompletionSuggestions(final ParseResults<S> parse) {
|
||||||
if (node.getRedirect() != null) {
|
final CommandContextBuilder<S> context = parse.getContext();
|
||||||
return findSuggestions(node.getRedirect(), reader, contextBuilder, result);
|
|
||||||
}
|
final Set<String> suggestions = new LinkedHashSet<>();
|
||||||
final S source = contextBuilder.getSource();
|
|
||||||
for (final CommandNode<S> child : node.getChildren()) {
|
final CommandNode<S> parent;
|
||||||
if (!child.canUse(source)) {
|
final int start;
|
||||||
continue;
|
|
||||||
}
|
if (context.getNodes().isEmpty()) {
|
||||||
final CommandContextBuilder<S> context = contextBuilder.copy();
|
parent = root;
|
||||||
final int cursor = reader.getCursor();
|
start = 0;
|
||||||
try {
|
} else if (parse.getReader().canRead()) {
|
||||||
child.parse(reader, context);
|
final Map.Entry<CommandNode<S>, StringRange> entry = Iterables.getLast(context.getNodes().entrySet());
|
||||||
if (reader.canRead()) {
|
parent = entry.getKey();
|
||||||
if (reader.peek() == ARGUMENT_SEPARATOR_CHAR) {
|
start = entry.getValue().getEnd() + 1;
|
||||||
reader.skip();
|
} else if (context.getNodes().size() > 1) {
|
||||||
return findSuggestions(child, reader, context, result);
|
final Map.Entry<CommandNode<S>, StringRange> entry = Iterables.get(context.getNodes().entrySet(), context.getNodes().size() - 2);
|
||||||
}
|
parent = entry.getKey();
|
||||||
|
start = entry.getValue().getEnd() + 1;
|
||||||
} else {
|
} else {
|
||||||
reader.setCursor(cursor);
|
parent = root;
|
||||||
child.listSuggestions(reader.getRemaining(), result, context);
|
start = 0;
|
||||||
}
|
|
||||||
} catch (final CommandSyntaxException e) {
|
|
||||||
reader.setCursor(cursor);
|
|
||||||
child.listSuggestions(reader.getRemaining(), result, context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
for (final CommandNode<S> node : parent.getChildren()) {
|
||||||
|
node.listSuggestions(parse.getReader().getString().substring(start), suggestions, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getCompletionSuggestions(final String command, final S source) {
|
final List<String> result = new ArrayList<>(suggestions);
|
||||||
final StringReader reader = new StringReader(command);
|
Collections.sort(result);
|
||||||
final Set<String> nodes = findSuggestions(root, reader, new CommandContextBuilder<>(this, source, 0), Sets.newLinkedHashSet());
|
return new CommandSuggestions(new StringRange(start, parse.getReader().getTotalLength()), result);
|
||||||
|
|
||||||
return nodes.toArray(new String[nodes.size()]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public RootCommandNode<S> getRoot() {
|
public RootCommandNode<S> getRoot() {
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.mojang.brigadier;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.context.StringRange;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,4 +53,12 @@ public class StringRange {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(start, end);
|
return Objects.hash(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "StringRange{" +
|
||||||
|
"start=" + start +
|
||||||
|
", end=" + end +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
package com.mojang.brigadier;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
|
|
||||||
import static org.hamcrest.Matchers.emptyArray;
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
|
||||||
public class CommandDispatcherCompletionsTest {
|
|
||||||
private CommandDispatcher<Object> subject;
|
|
||||||
@Mock
|
|
||||||
private Object source;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
subject = new CommandDispatcher<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNoCommands() throws Exception {
|
|
||||||
assertThat(subject.getCompletionSuggestions("", source), is(emptyArray()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCommand() throws Exception {
|
|
||||||
subject.register(literal("foo"));
|
|
||||||
subject.register(literal("bar"));
|
|
||||||
subject.register(literal("baz").requires(s -> false));
|
|
||||||
assertThat(subject.getCompletionSuggestions("", source), equalTo(new String[]{"bar", "foo"}));
|
|
||||||
assertThat(subject.getCompletionSuggestions("f", source), equalTo(new String[]{"foo"}));
|
|
||||||
assertThat(subject.getCompletionSuggestions("b", source), equalTo(new String[]{"bar"}));
|
|
||||||
assertThat(subject.getCompletionSuggestions("q", source), is(emptyArray()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCommand_redirect() throws Exception {
|
|
||||||
subject.register(literal("foo"));
|
|
||||||
subject.register(literal("bar"));
|
|
||||||
subject.register(literal("redirect").redirect(subject.getRoot(), Collections::singleton));
|
|
||||||
assertThat(subject.getCompletionSuggestions("redirect ", source), equalTo(new String[]{"bar", "foo", "redirect"}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSubCommand() throws Exception {
|
|
||||||
subject.register(literal("foo").then(literal("abc")).then(literal("def")).then(literal("ghi").requires(s -> false)));
|
|
||||||
subject.register(literal("bar"));
|
|
||||||
assertThat(subject.getCompletionSuggestions("", source), equalTo(new String[]{"bar", "foo"}));
|
|
||||||
assertThat(subject.getCompletionSuggestions("f", source), equalTo(new String[]{"foo"}));
|
|
||||||
assertThat(subject.getCompletionSuggestions("foo", source), equalTo(new String[]{"foo"}));
|
|
||||||
assertThat(subject.getCompletionSuggestions("foo ", source), equalTo(new String[]{"abc", "def"}));
|
|
||||||
assertThat(subject.getCompletionSuggestions("foo a", source), equalTo(new String[]{"abc"}));
|
|
||||||
assertThat(subject.getCompletionSuggestions("foo d", source), equalTo(new String[]{"def"}));
|
|
||||||
assertThat(subject.getCompletionSuggestions("foo g", source), is(emptyArray()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package com.mojang.brigadier;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.mojang.brigadier.context.StringRange;
|
||||||
|
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.builder.LiteralArgumentBuilder.literal;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class CommandSuggestionsTest {
|
||||||
|
private CommandDispatcher<Object> subject;
|
||||||
|
@Mock
|
||||||
|
private Object source;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
subject = new CommandDispatcher<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCompletionSuggestions_rootCommands() throws Exception {
|
||||||
|
subject.register(literal("foo"));
|
||||||
|
subject.register(literal("bar"));
|
||||||
|
subject.register(literal("baz"));
|
||||||
|
|
||||||
|
final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("", source));
|
||||||
|
|
||||||
|
assertThat(result.getRange(), equalTo(new StringRange(0, 0)));
|
||||||
|
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz", "foo")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCompletionSuggestions_rootCommands_partial() throws Exception {
|
||||||
|
subject.register(literal("foo"));
|
||||||
|
subject.register(literal("bar"));
|
||||||
|
subject.register(literal("baz"));
|
||||||
|
|
||||||
|
final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("b", source));
|
||||||
|
|
||||||
|
assertThat(result.getRange(), equalTo(new StringRange(0, 1)));
|
||||||
|
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCompletionSuggestions_subCommands() throws Exception {
|
||||||
|
subject.register(
|
||||||
|
literal("parent")
|
||||||
|
.then(literal("foo"))
|
||||||
|
.then(literal("bar"))
|
||||||
|
.then(literal("baz"))
|
||||||
|
);
|
||||||
|
|
||||||
|
final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("parent ", source));
|
||||||
|
|
||||||
|
assertThat(result.getRange(), equalTo(new StringRange(7, 7)));
|
||||||
|
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz", "foo")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCompletionSuggestions_subCommands_partial() throws Exception {
|
||||||
|
subject.register(
|
||||||
|
literal("parent")
|
||||||
|
.then(literal("foo"))
|
||||||
|
.then(literal("bar"))
|
||||||
|
.then(literal("baz"))
|
||||||
|
);
|
||||||
|
|
||||||
|
final CommandSuggestions result = subject.getCompletionSuggestions(subject.parse("parent b", source));
|
||||||
|
|
||||||
|
assertThat(result.getRange(), equalTo(new StringRange(7, 8)));
|
||||||
|
assertThat(result.getSuggestions(), equalTo(Lists.newArrayList("bar", "baz")));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user