diff --git a/src/main/java/com/intellectualsites/commands/CommandTree.java b/src/main/java/com/intellectualsites/commands/CommandTree.java index 03311385..15388639 100644 --- a/src/main/java/com/intellectualsites/commands/CommandTree.java +++ b/src/main/java/com/intellectualsites/commands/CommandTree.java @@ -27,6 +27,7 @@ import com.google.common.base.Objects; import com.google.common.collect.Lists; import com.intellectualsites.commands.components.CommandComponent; import com.intellectualsites.commands.components.StaticComponent; +import com.intellectualsites.commands.exceptions.NoSuchCommandException; import com.intellectualsites.commands.parser.ComponentParseResult; import com.intellectualsites.commands.sender.CommandSender; @@ -37,8 +38,10 @@ import java.util.stream.Collectors; /** * Tree containing all commands and command paths + * + * @param Command sender type */ -public class CommandTree { +public class CommandTree { private final Node> internalTree = new Node<>(null); @@ -48,22 +51,21 @@ public class CommandTree { /** * Create a new command tree instance * + * @param Command sender type * @return New command tree */ - @Nonnull public static CommandTree newTree() { - return new CommandTree(); + @Nonnull + public static CommandTree newTree() { + return new CommandTree<>(); } - public Optional parse(@Nonnull final String[] args) { - final CommandSender tempSender = new CommandSender() { - }; - + public Optional parse(@Nonnull final C commandSender, @Nonnull final String[] args) throws NoSuchCommandException { final Queue commandQueue = new LinkedList<>(Arrays.asList(args)); - return parseCommand(tempSender, commandQueue, this.internalTree); + return parseCommand(commandSender, commandQueue, this.internalTree); } - private Optional parseCommand(@Nonnull final CommandSender commandSender, @Nonnull final Queue commandQueue, - @Nonnull final Node> root) { + private Optional parseCommand(@Nonnull final C commandSender, @Nonnull final Queue commandQueue, + @Nonnull final Node> root) throws NoSuchCommandException { final List>> children = root.getChildren(); if (children.size() == 1 && !(children.get(0).getValue() instanceof StaticComponent)) { @@ -126,7 +128,7 @@ public class CommandTree { } /* We could not find a match */ - /* TODO: Send "No Such Command" */ + throw new NoSuchCommandException(commandSender, getChain(root).stream().map(Node::getValue).collect(Collectors.toList()), popped); } /* @@ -177,10 +179,10 @@ public class CommandTree { public void verifyAndRegister() { // All top level commands are supposed to be registered in the command manager this.internalTree.children.stream().map(Node::getValue).forEach(commandComponent -> { - if (!(commandComponent instanceof StaticComponent)) { - throw new IllegalStateException("Top level command component cannot be a variable"); - } - // TODO: Register in the command handler + if (!(commandComponent instanceof StaticComponent)) { + throw new IllegalStateException("Top level command component cannot be a variable"); + } + // TODO: Register in the command handler }); this.checkAmbiguity(this.internalTree); // Verify that all leaf nodes have command registered @@ -243,13 +245,15 @@ public class CommandTree { return Collections.unmodifiableList(this.children); } - @Nonnull private Node addChild(@Nonnull final T child) { + @Nonnull + private Node addChild(@Nonnull final T child) { final Node node = new Node<>(child); this.children.add(node); return node; } - @Nullable private Node getChild(@Nonnull final T type) { + @Nullable + private Node getChild(@Nonnull final T type) { for (final Node child : this.children) { if (type.equals(child.getValue())) { return child; @@ -262,7 +266,8 @@ public class CommandTree { return this.children.isEmpty(); } - @Nullable public T getValue() { + @Nullable + public T getValue() { return this.value; } @@ -288,7 +293,8 @@ public class CommandTree { this.parent = parent; } - @Nullable public Node getParent() { + @Nullable + public Node getParent() { return this.parent; } diff --git a/src/main/java/com/intellectualsites/commands/exceptions/CommandParseException.java b/src/main/java/com/intellectualsites/commands/exceptions/CommandParseException.java new file mode 100644 index 00000000..36042c35 --- /dev/null +++ b/src/main/java/com/intellectualsites/commands/exceptions/CommandParseException.java @@ -0,0 +1,72 @@ +// +// MIT License +// +// Copyright (c) 2020 IntellectualSites +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package com.intellectualsites.commands.exceptions; + +import com.intellectualsites.commands.components.CommandComponent; +import com.intellectualsites.commands.sender.CommandSender; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.List; + +/** + * Exception thrown when parsing user input into a command + */ +public class CommandParseException extends IllegalArgumentException { + + private final CommandSender commandSender; + private final List> currentChain; + + /** + * Construct a new command parse exception + * + * @param commandSender Sender who executed the command + * @param currentChain Chain leading up to the exception + */ + protected CommandParseException(@Nonnull final CommandSender commandSender, @Nonnull final List> currentChain) { + this.commandSender = commandSender; + this.currentChain = currentChain; + } + + /** + * Get the command sender + * + * @return Command sender + */ + @Nonnull + public CommandSender getCommandSender() { + return this.commandSender; + } + + /** + * Get the command chain leading up to the exception + * + * @return Unmodifiable list of command components + */ + @Nonnull + public List> getCurrentChain() { + return Collections.unmodifiableList(this.currentChain); + } + +} diff --git a/src/main/java/com/intellectualsites/commands/exceptions/NoSuchCommandException.java b/src/main/java/com/intellectualsites/commands/exceptions/NoSuchCommandException.java new file mode 100644 index 00000000..07bc3b68 --- /dev/null +++ b/src/main/java/com/intellectualsites/commands/exceptions/NoSuchCommandException.java @@ -0,0 +1,62 @@ +// +// MIT License +// +// Copyright (c) 2020 IntellectualSites +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package com.intellectualsites.commands.exceptions; + +import com.intellectualsites.commands.components.CommandComponent; +import com.intellectualsites.commands.sender.CommandSender; + +import javax.annotation.Nonnull; +import java.util.List; + +/** + * Exception thrown when a command sender tries to execute + * a command that doesn't exist + */ +public class NoSuchCommandException extends CommandParseException { + + private final String suppliedCommand; + + /** + * Construct a no such command exception + * + * @param commandSender Sender who executed the command + * @param currentChain Chain leading up to the exception + * @param command Entered command (following the command chain) + */ + public NoSuchCommandException(@Nonnull final CommandSender commandSender, @Nonnull final List> currentChain, + @Nonnull final String command) { + super(commandSender, currentChain); + this.suppliedCommand = command; + } + + /** + * Get the supplied command + * + * @return Supplied command + */ + @Nonnull public String getSuppliedCommand() { + return this.suppliedCommand; + } + +}