From 1ce9894c07806284c054d1bfdc8ff385330e77ca Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Mon, 13 Nov 2017 12:40:05 +0100 Subject: [PATCH] Added methods for getting path by node & nodes by path --- .../mojang/brigadier/CommandDispatcher.java | 40 +++++++++++++++++++ .../brigadier/builder/ArgumentBuilder.java | 10 ++++- .../brigadier/tree/ArgumentCommandNode.java | 7 +--- .../mojang/brigadier/tree/CommandNode.java | 16 ++++++-- .../brigadier/tree/LiteralCommandNode.java | 2 +- .../brigadier/tree/RootCommandNode.java | 4 +- .../brigadier/CommandDispatcherTest.java | 24 ++++++++++- 7 files changed, 86 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java index 80975fd..7632448 100644 --- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java +++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java @@ -354,4 +354,44 @@ public class CommandDispatcher { public RootCommandNode getRoot() { return root; } + + public Collection getPath(final CommandNode target) { + final List>> nodes = new ArrayList<>(); + addPaths(root, nodes, new ArrayList<>()); + + for (final List> list : nodes) { + if (list.get(list.size() - 1) == target) { + final List result = new ArrayList<>(list.size()); + for (final CommandNode node : list) { + if (node != root) { + result.add(node.getName()); + } + } + return result; + } + } + + return Collections.emptyList(); + } + + public CommandNode findNode(final Collection path) { + CommandNode node = root; + for (final String name : path) { + node = node.getChild(name); + if (node == null) { + return null; + } + } + return node; + } + + private void addPaths(final CommandNode node, final List>> result, final List> parents) { + final List> current = new ArrayList<>(parents); + current.add(node); + result.add(current); + + for (final CommandNode child : node.getChildren()) { + addPaths(child, result, current); + } + } } diff --git a/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java b/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java index d8bf453..ea2ad15 100644 --- a/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java +++ b/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java @@ -7,8 +7,6 @@ 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; public abstract class ArgumentBuilder> { @@ -28,6 +26,14 @@ public abstract class ArgumentBuilder> { return getThis(); } + public T then(final CommandNode argument) { + if (target != null) { + throw new IllegalStateException("Cannot add children to a redirected node"); + } + arguments.addChild(argument); + return getThis(); + } + public Collection> getArguments() { return arguments.getChildren(); } diff --git a/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java b/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java index ee60174..3fa97bc 100644 --- a/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/ArgumentCommandNode.java @@ -13,7 +13,6 @@ 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 extends CommandNode { @@ -31,16 +30,12 @@ public class ArgumentCommandNode extends CommandNode { this.suggestionsProvider = suggestionsProvider; } - public String getName() { - return name; - } - public ArgumentType getType() { return type; } @Override - protected Object getMergeKey() { + public String getName() { return name; } diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java index 73438fc..bc7554a 100644 --- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java @@ -18,7 +18,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; public abstract class CommandNode implements Comparable> { - private Map> children = Maps.newLinkedHashMap(); + private Map> children = Maps.newLinkedHashMap(); private final Predicate requirement; private final CommandNode redirect; private final RedirectModifier modifier; @@ -39,6 +39,10 @@ public abstract class CommandNode implements Comparable> { return children.values(); } + public CommandNode getChild(final String name) { + return children.get(name); + } + public CommandNode getRedirect() { return redirect; } @@ -52,7 +56,11 @@ public abstract class CommandNode implements Comparable> { } public void addChild(final CommandNode node) { - final CommandNode child = children.get(node.getMergeKey()); + if (node instanceof RootCommandNode) { + throw new UnsupportedOperationException("Cannot add a RootCommandNode as a child to any other CommandNode"); + } + + final CommandNode child = children.get(node.getName()); if (child != null) { // We've found something to merge onto if (node.getCommand() != null) { @@ -62,7 +70,7 @@ public abstract class CommandNode implements Comparable> { child.addChild(grandchild); } } else { - children.put(node.getMergeKey(), node); + children.put(node.getName(), node); } children = children.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); @@ -90,7 +98,7 @@ public abstract class CommandNode implements Comparable> { return requirement; } - protected abstract Object getMergeKey(); + public abstract String getName(); public abstract String getUsageText(); diff --git a/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java b/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java index 46ad706..2982a12 100644 --- a/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java @@ -30,7 +30,7 @@ public class LiteralCommandNode extends CommandNode { } @Override - protected Object getMergeKey() { + public String getName() { return literal; } diff --git a/src/main/java/com/mojang/brigadier/tree/RootCommandNode.java b/src/main/java/com/mojang/brigadier/tree/RootCommandNode.java index f42e37d..a21c5ab 100644 --- a/src/main/java/com/mojang/brigadier/tree/RootCommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/RootCommandNode.java @@ -16,8 +16,8 @@ public class RootCommandNode extends CommandNode { } @Override - protected Object getMergeKey() { - throw new UnsupportedOperationException("Cannot add a RootCommandNode as a child to any other CommandNode"); + public String getName() { + return ""; } @Override diff --git a/src/test/java/com/mojang/brigadier/CommandDispatcherTest.java b/src/test/java/com/mojang/brigadier/CommandDispatcherTest.java index 703bdb1..876cc98 100644 --- a/src/test/java/com/mojang/brigadier/CommandDispatcherTest.java +++ b/src/test/java/com/mojang/brigadier/CommandDispatcherTest.java @@ -11,9 +11,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import java.util.Collection; import java.util.Collections; -import java.util.function.Function; import static com.mojang.brigadier.arguments.IntegerArgumentType.integer; import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal; @@ -22,6 +20,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.Matchers.argThat; @@ -357,4 +356,25 @@ public class CommandDispatcherTest { assertThat(ex.getCursor(), is(4)); } } + + @Test + public void testGetPath() { + final LiteralCommandNode bar = literal("bar").build(); + subject.register(literal("foo").then(bar)); + + assertThat(subject.getPath(bar), equalTo(Lists.newArrayList("foo", "bar"))); + } + + @Test + public void testFindNodeExists() { + final LiteralCommandNode bar = literal("bar").build(); + subject.register(literal("foo").then(bar)); + + assertThat(subject.findNode(Lists.newArrayList("foo", "bar")), is(bar)); + } + + @Test + public void testFindNodeDoesntExist() { + assertThat(subject.findNode(Lists.newArrayList("foo", "bar")), is(nullValue())); + } } \ No newline at end of file