From 33e1e0b1f13cb2795cb716407d61939218c60f55 Mon Sep 17 00:00:00 2001
From: sk89q
Date: Sat, 28 Jun 2014 16:30:02 -0700
Subject: [PATCH] Overhauled command handling and suggestion support.
---
.../sk89q/bukkit/util/CommandInspector.java | 32 +++++++
.../bukkit/util/DynamicPluginCommand.java | 17 +++-
.../util/DynamicPluginCommandHelpTopic.java | 89 +++++++++---------
.../bukkit/BukkitCommandInspector.java | 83 +++++++++++++++++
.../bukkit/BukkitServerInterface.java | 5 +-
.../worldedit/bukkit/WorldEditListener.java | 13 +--
.../worldedit/bukkit/WorldEditPlugin.java | 26 +++++-
.../sk89q/worldedit/forge/ForgeWorldEdit.java | 7 +-
.../java/com/sk89q/worldedit/WorldEdit.java | 17 ----
.../worldedit/command/UtilityCommands.java | 4 +-
.../event/platform/CommandEvent.java | 14 +--
.../platform/CommandSuggestionEvent.java | 90 +++++++++++++++++++
.../extension/platform/CommandManager.java | 39 ++++----
...sionsHandler.java => ActorAuthorizer.java} | 17 ++--
.../sk89q/worldedit/util/auth/Authorizer.java | 38 ++++++++
.../worldedit/util/auth/NullAuthorizer.java | 35 ++++++++
.../util/command/CommandCallable.java | 19 +++-
.../worldedit/util/command/Description.java | 2 +-
.../util/command/SimpleDescription.java | 4 +-
.../util/command/SimpleDispatcher.java | 40 ++++++---
.../util/command/fluent/DispatcherNode.java | 4 +-
.../command/parametric/ParametricBuilder.java | 31 ++++++-
.../parametric/ParametricCallable.java | 67 ++++++++------
.../parametric/PermissionsHandler.java | 67 --------------
24 files changed, 536 insertions(+), 224 deletions(-)
create mode 100644 src/bukkit/java/com/sk89q/bukkit/util/CommandInspector.java
create mode 100644 src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java
create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/CommandSuggestionEvent.java
rename src/main/java/com/sk89q/worldedit/internal/command/{CommandPermissionsHandler.java => ActorAuthorizer.java} (75%)
create mode 100644 src/main/java/com/sk89q/worldedit/util/auth/Authorizer.java
create mode 100644 src/main/java/com/sk89q/worldedit/util/auth/NullAuthorizer.java
delete mode 100644 src/main/java/com/sk89q/worldedit/util/command/parametric/PermissionsHandler.java
diff --git a/src/bukkit/java/com/sk89q/bukkit/util/CommandInspector.java b/src/bukkit/java/com/sk89q/bukkit/util/CommandInspector.java
new file mode 100644
index 000000000..a7d213944
--- /dev/null
+++ b/src/bukkit/java/com/sk89q/bukkit/util/CommandInspector.java
@@ -0,0 +1,32 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.bukkit.util;
+
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+public interface CommandInspector {
+
+ String getShortText(Command command);
+
+ String getFullText(Command command);
+
+ boolean testPermission(CommandSender sender, Command command);
+}
diff --git a/src/bukkit/java/com/sk89q/bukkit/util/DynamicPluginCommand.java b/src/bukkit/java/com/sk89q/bukkit/util/DynamicPluginCommand.java
index 1660d987f..c48df659c 100644
--- a/src/bukkit/java/com/sk89q/bukkit/util/DynamicPluginCommand.java
+++ b/src/bukkit/java/com/sk89q/bukkit/util/DynamicPluginCommand.java
@@ -26,9 +26,12 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginIdentifiableCommand;
+import org.bukkit.command.TabCompleter;
import org.bukkit.plugin.Plugin;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
/**
* An implementation of a dynamically registered {@link org.bukkit.command.Command} attached to a plugin
@@ -76,6 +79,15 @@ public class DynamicPluginCommand extends org.bukkit.command.Command implements
return owningPlugin;
}
+ @Override
+ public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ if (owner instanceof TabCompleter) {
+ return ((TabCompleter) owner).onTabComplete(sender, this, alias, args);
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
@SuppressWarnings("unchecked")
@Override
public boolean testPermissionSilent(CommandSender sender) {
@@ -83,7 +95,10 @@ public class DynamicPluginCommand extends org.bukkit.command.Command implements
return true;
}
- if (registeredWith instanceof CommandsManager>) {
+ if (registeredWith instanceof CommandInspector) {
+ CommandInspector resolver = (CommandInspector) registeredWith;
+ return resolver.testPermission(sender, this);
+ } else if (registeredWith instanceof CommandsManager>) {
try {
for (String permission : permissions) {
if (((CommandsManager) registeredWith).hasPermission(sender, permission)) {
diff --git a/src/bukkit/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java b/src/bukkit/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java
index 6d0b4f690..fda92fc40 100644
--- a/src/bukkit/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java
+++ b/src/bukkit/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java
@@ -40,55 +40,64 @@ public class DynamicPluginCommandHelpTopic extends HelpTopic {
this.cmd = cmd;
this.name = "/" + cmd.getName();
- String fullTextTemp = null;
- StringBuilder fullText = new StringBuilder();
-
- if (cmd.getRegisteredWith() instanceof CommandsManager) {
- Map helpText = ((CommandsManager>) cmd.getRegisteredWith()).getHelpMessages();
- final String lookupName = cmd.getName().replaceAll("/", "");
- if (helpText.containsKey(lookupName)) { // We have full help text for this command
- fullTextTemp = helpText.get(lookupName);
- }
- // No full help text, assemble help text from info
- helpText = ((CommandsManager>) cmd.getRegisteredWith()).getCommands();
- if (helpText.containsKey(cmd.getName())) {
- final String shortText = helpText.get(cmd.getName());
- if (fullTextTemp == null) {
- fullTextTemp = this.name + " " + shortText;
- }
- this.shortText = shortText;
- }
+ if (cmd.getRegisteredWith() instanceof CommandInspector) {
+ CommandInspector resolver = (CommandInspector) cmd.getRegisteredWith();
+ this.shortText = resolver.getShortText(cmd);
+ this.fullText = resolver.getFullText(cmd);
} else {
- this.shortText = cmd.getDescription();
- }
+ String fullTextTemp = null;
+ StringBuilder fullText = new StringBuilder();
- // Put the usage in the format: Usage string (newline) Aliases (newline) Help text
- String[] split = fullTextTemp == null ? new String[2] : fullTextTemp.split("\n", 2);
- fullText.append(ChatColor.BOLD).append(ChatColor.GOLD).append("Usage: ").append(ChatColor.WHITE);
- fullText.append(split[0]).append("\n");
-
- if (cmd.getAliases().size() > 0) {
- fullText.append(ChatColor.BOLD).append(ChatColor.GOLD).append("Aliases: ").append(ChatColor.WHITE);
- boolean first = true;
- for (String alias : cmd.getAliases()) {
- if (!first) {
- fullText.append(", ");
+ if (cmd.getRegisteredWith() instanceof CommandsManager) {
+ Map helpText = ((CommandsManager>) cmd.getRegisteredWith()).getHelpMessages();
+ final String lookupName = cmd.getName().replaceAll("/", "");
+ if (helpText.containsKey(lookupName)) { // We have full help text for this command
+ fullTextTemp = helpText.get(lookupName);
}
- fullText.append(alias);
- first = false;
+ // No full help text, assemble help text from info
+ helpText = ((CommandsManager>) cmd.getRegisteredWith()).getCommands();
+ if (helpText.containsKey(cmd.getName())) {
+ final String shortText = helpText.get(cmd.getName());
+ if (fullTextTemp == null) {
+ fullTextTemp = this.name + " " + shortText;
+ }
+ this.shortText = shortText;
+ }
+ } else {
+ this.shortText = cmd.getDescription();
}
- fullText.append("\n");
+
+ // Put the usage in the format: Usage string (newline) Aliases (newline) Help text
+ String[] split = fullTextTemp == null ? new String[2] : fullTextTemp.split("\n", 2);
+ fullText.append(ChatColor.BOLD).append(ChatColor.GOLD).append("Usage: ").append(ChatColor.WHITE);
+ fullText.append(split[0]).append("\n");
+
+ if (!cmd.getAliases().isEmpty()) {
+ fullText.append(ChatColor.BOLD).append(ChatColor.GOLD).append("Aliases: ").append(ChatColor.WHITE);
+ boolean first = true;
+ for (String alias : cmd.getAliases()) {
+ if (!first) {
+ fullText.append(", ");
+ }
+ fullText.append(alias);
+ first = false;
+ }
+ fullText.append("\n");
+ }
+ if (split.length > 1) {
+ fullText.append(split[1]);
+ }
+ this.fullText = fullText.toString();
}
- if (split.length > 1) {
- fullText.append(split[1]);
- }
- this.fullText = fullText.toString();
}
@Override
@SuppressWarnings("unchecked")
public boolean canSee(CommandSender player) {
- if (cmd.getPermissions() != null && cmd.getPermissions().length > 0) {
+ if (cmd.getRegisteredWith() instanceof CommandInspector) {
+ CommandInspector resolver = (CommandInspector) cmd.getRegisteredWith();
+ return resolver.testPermission(player, cmd);
+ } else if (cmd.getPermissions() != null && cmd.getPermissions().length > 0) {
if (cmd.getRegisteredWith() instanceof CommandsManager) {
try {
for (String perm : cmd.getPermissions()) {
@@ -123,7 +132,7 @@ public class DynamicPluginCommandHelpTopic extends HelpTopic {
@Override
public String getFullText(CommandSender forWho) {
- if (this.fullText == null || this.fullText.length() == 0) {
+ if (this.fullText == null || this.fullText.isEmpty()) {
return getShortText();
} else {
return this.fullText;
diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java
new file mode 100644
index 000000000..9c11224c6
--- /dev/null
+++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java
@@ -0,0 +1,83 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.bukkit;
+
+import com.sk89q.bukkit.util.CommandInspector;
+import com.sk89q.minecraft.util.commands.CommandLocals;
+import com.sk89q.worldedit.extension.platform.Actor;
+import com.sk89q.worldedit.util.command.CommandMapping;
+import com.sk89q.worldedit.util.command.Description;
+import com.sk89q.worldedit.util.command.Dispatcher;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+import java.util.logging.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+class BukkitCommandInspector implements CommandInspector {
+
+ private static final Logger logger = Logger.getLogger(BukkitCommandInspector.class.getCanonicalName());
+ private final WorldEditPlugin plugin;
+ private final Dispatcher dispatcher;
+
+ BukkitCommandInspector(WorldEditPlugin plugin, Dispatcher dispatcher) {
+ checkNotNull(plugin);
+ checkNotNull(dispatcher);
+ this.plugin = plugin;
+ this.dispatcher = dispatcher;
+ }
+
+ @Override
+ public String getShortText(Command command) {
+ CommandMapping mapping = dispatcher.get(command.getName());
+ if (mapping != null) {
+ return mapping.getDescription().getShortDescription();
+ } else {
+ logger.warning("BukkitCommandInspector doesn't know how about the command '" + command + "'");
+ return "Help text not available";
+ }
+ }
+
+ @Override
+ public String getFullText(Command command) {
+ CommandMapping mapping = dispatcher.get(command.getName());
+ if (mapping != null) {
+ Description description = mapping.getDescription();
+ return "Usage: " + description.getUsage() + (description.getHelp() != null ? "\n" + description.getHelp() : "");
+ } else {
+ logger.warning("BukkitCommandInspector doesn't know how about the command '" + command + "'");
+ return "Help text not available";
+ }
+ }
+
+ @Override
+ public boolean testPermission(CommandSender sender, Command command) {
+ CommandMapping mapping = dispatcher.get(command.getName());
+ if (mapping != null) {
+ CommandLocals locals = new CommandLocals();
+ locals.put(Actor.class, plugin.wrapCommandSender(sender));
+ return mapping.getCallable().testPermission(locals);
+ } else {
+ logger.warning("BukkitCommandInspector doesn't know how about the command '" + command + "'");
+ return false;
+ }
+ }
+}
diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java
index d86affe9d..8bf7f874b 100644
--- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java
+++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java
@@ -125,15 +125,14 @@ public class BukkitServerInterface extends ServerInterface {
@Override
public void registerCommands(Dispatcher dispatcher) {
List toRegister = new ArrayList();
+ BukkitCommandInspector inspector = new BukkitCommandInspector(plugin, dispatcher);
for (CommandMapping command : dispatcher.getCommands()) {
Description description = command.getDescription();
List permissions = description.getPermissions();
String[] permissionsArray = new String[permissions.size()];
permissions.toArray(permissionsArray);
- toRegister.add(new CommandInfo(
- description.getUsage(), description.getDescription(),
- command.getAllAliases(), dispatcher, permissionsArray));
+ toRegister.add(new CommandInfo(description.getUsage(), description.getShortDescription(), command.getAllAliases(), inspector, permissionsArray));
}
dynamicCommands.register(toRegister);
diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditListener.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditListener.java
index 4a60658a3..91a7adcda 100644
--- a/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditListener.java
+++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditListener.java
@@ -96,20 +96,21 @@ public class WorldEditListener implements Listener {
String[] split = event.getMessage().split(" ");
if (split.length > 0) {
- split = plugin.getWorldEdit().commandDetection(split);
- split[0] = "/" + split[0];
+ split[0] = split[0].substring(1);
+ split = plugin.getWorldEdit().getPlatformManager().getCommandManager().commandDetection(split);
}
- final String newMessage = StringUtil.joinString(split, " ");
+ final String newMessage = "/" + StringUtil.joinString(split, " ");
if (!newMessage.equals(event.getMessage())) {
event.setMessage(newMessage);
plugin.getServer().getPluginManager().callEvent(event);
+
if (!event.isCancelled()) {
- if (event.getMessage().length() > 0) {
- plugin.getServer().dispatchCommand(event.getPlayer(),
- event.getMessage().substring(1));
+ if (!event.getMessage().isEmpty()) {
+ plugin.getServer().dispatchCommand(event.getPlayer(), event.getMessage().substring(1));
}
+
event.setCancelled(true);
}
}
diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java
index b66ee0e94..9f0beff64 100644
--- a/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java
+++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java
@@ -19,6 +19,7 @@
package com.sk89q.worldedit.bukkit;
+import com.google.common.base.Joiner;
import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.wepif.PermissionsResolverManager;
import com.sk89q.worldedit.*;
@@ -27,17 +28,21 @@ import com.sk89q.worldedit.bukkit.selections.CylinderSelection;
import com.sk89q.worldedit.bukkit.selections.Polygonal2DSelection;
import com.sk89q.worldedit.bukkit.selections.Selection;
import com.sk89q.worldedit.event.platform.CommandEvent;
+import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.regions.*;
import org.bukkit.World;
+import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.*;
import java.util.Enumeration;
+import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
@@ -47,7 +52,7 @@ import java.util.zip.ZipEntry;
*
* @author sk89q
*/
-public class WorldEditPlugin extends JavaPlugin {
+public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
/**
* The name of the CUI's plugin channel registration
@@ -217,19 +222,32 @@ public class WorldEditPlugin extends JavaPlugin {
}
@Override
- public boolean onCommand(CommandSender sender, org.bukkit.command.Command cmd, String commandLabel, String[] args) {
+ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
// Add the command to the array because the underlying command handling
// code of WorldEdit expects it
String[] split = new String[args.length + 1];
System.arraycopy(args, 0, split, 1, args.length);
- split[0] = "/" + cmd.getName();
+ split[0] = cmd.getName();
- CommandEvent event = new CommandEvent(wrapCommandSender(sender), split);
+ CommandEvent event = new CommandEvent(wrapCommandSender(sender), Joiner.on(" ").join(split));
getWorldEdit().getEventBus().post(event);
return true;
}
+ @Override
+ public List onTabComplete(CommandSender sender, Command cmd, String commandLabel, String[] args) {
+ // Add the command to the array because the underlying command handling
+ // code of WorldEdit expects it
+ String[] split = new String[args.length + 1];
+ System.arraycopy(args, 0, split, 1, args.length);
+ split[0] = cmd.getName();
+
+ CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), Joiner.on(" ").join(split));
+ getWorldEdit().getEventBus().post(event);
+ return event.getSuggestions();
+ }
+
/**
* Gets the session for the player.
*
diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java
index 1df421583..dbc53eb1d 100644
--- a/src/forge/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java
+++ b/src/forge/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java
@@ -19,6 +19,7 @@
package com.sk89q.worldedit.forge;
+import com.google.common.base.Joiner;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closer;
import com.sk89q.worldedit.LocalSession;
@@ -123,8 +124,10 @@ public class ForgeWorldEdit {
if (((EntityPlayerMP) event.sender).worldObj.isRemote) return;
String[] split = new String[event.parameters.length + 1];
System.arraycopy(event.parameters, 0, split, 1, event.parameters.length);
- split[0] = ("/" + event.command.getCommandName());
- WorldEdit.getInstance().handleCommand(wrap((EntityPlayerMP) event.sender), split);
+ split[0] = event.command.getCommandName();
+ com.sk89q.worldedit.event.platform.CommandEvent weEvent =
+ new com.sk89q.worldedit.event.platform.CommandEvent(wrap((EntityPlayerMP) event.sender), Joiner.on(" ").join(split));
+ WorldEdit.getInstance().getEventBus().post(weEvent);
}
}
diff --git a/src/main/java/com/sk89q/worldedit/WorldEdit.java b/src/main/java/com/sk89q/worldedit/WorldEdit.java
index a34019da5..1a0d25a5e 100644
--- a/src/main/java/com/sk89q/worldedit/WorldEdit.java
+++ b/src/main/java/com/sk89q/worldedit/WorldEdit.java
@@ -25,7 +25,6 @@ import com.sk89q.worldedit.blocks.BlockType;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.event.platform.BlockInteractEvent;
-import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.event.platform.InputType;
import com.sk89q.worldedit.event.platform.PlayerInputEvent;
import com.sk89q.worldedit.extension.input.ParserContext;
@@ -740,22 +739,6 @@ public class WorldEdit {
return event.isCancelled();
}
- /**
- *
- * @param player
- * @param split
- * @return whether the command was processed
- */
- public boolean handleCommand(Player player, String[] split) {
- CommandEvent event = new CommandEvent(player, split);
- getEventBus().post(event);
- return event.isCancelled();
- }
-
- public String[] commandDetection(String[] split) {
- return getPlatformManager().getCommandManager().commandDetection(split);
- }
-
/**
* Executes a WorldEdit script.
*
diff --git a/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java
index 8b4999e67..f10d74e91 100644
--- a/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java
+++ b/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java
@@ -546,8 +546,8 @@ public class UtilityCommands {
if (description.getHelp() != null) {
actor.print(description.getHelp());
- } else if (description.getDescription() != null) {
- actor.print(description.getDescription());
+ } else if (description.getShortDescription() != null) {
+ actor.print(description.getShortDescription());
} else {
actor.print("No further help is available.");
}
diff --git a/src/main/java/com/sk89q/worldedit/event/platform/CommandEvent.java b/src/main/java/com/sk89q/worldedit/event/platform/CommandEvent.java
index a6b7ebdf1..0790787f4 100644
--- a/src/main/java/com/sk89q/worldedit/event/platform/CommandEvent.java
+++ b/src/main/java/com/sk89q/worldedit/event/platform/CommandEvent.java
@@ -30,20 +30,20 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class CommandEvent extends AbstractCancellable {
private final Actor actor;
- private final String[] args;
+ private final String arguments;
/**
* Create a new instance.
*
* @param actor the player
- * @param args the arguments
+ * @param arguments the arguments
*/
- public CommandEvent(Actor actor, String[] args) {
+ public CommandEvent(Actor actor, String arguments) {
checkNotNull(actor);
- checkNotNull(args);
+ checkNotNull(arguments);
this.actor = actor;
- this.args = args;
+ this.arguments = arguments;
}
/**
@@ -60,8 +60,8 @@ public class CommandEvent extends AbstractCancellable {
*
* @return the arguments
*/
- public String[] getArguments() {
- return args;
+ public String getArguments() {
+ return arguments;
}
}
diff --git a/src/main/java/com/sk89q/worldedit/event/platform/CommandSuggestionEvent.java b/src/main/java/com/sk89q/worldedit/event/platform/CommandSuggestionEvent.java
new file mode 100644
index 000000000..8fa39c0ff
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/event/platform/CommandSuggestionEvent.java
@@ -0,0 +1,90 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.event.platform;
+
+import com.sk89q.worldedit.event.Event;
+import com.sk89q.worldedit.extension.platform.Actor;
+
+import java.util.Collections;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Posted when suggestions for auto-completion are requested for command input.
+ */
+public class CommandSuggestionEvent extends Event {
+
+ private final Actor actor;
+ private final String arguments;
+ private List suggestions = Collections.emptyList();
+
+ /**
+ * Create a new instance.
+ *
+ * @param actor the player
+ * @param arguments the arguments
+ */
+ public CommandSuggestionEvent(Actor actor, String arguments) {
+ checkNotNull(actor);
+ checkNotNull(arguments);
+
+ this.actor = actor;
+ this.arguments = arguments;
+ }
+
+ /**
+ * Get the actor that issued the command.
+ *
+ * @return the actor that issued the command
+ */
+ public Actor getActor() {
+ return actor;
+ }
+
+ /**
+ * Get the arguments.
+ *
+ * @return the arguments
+ */
+ public String getArguments() {
+ return arguments;
+ }
+
+ /**
+ * Get the list of suggestions that are to be presented.
+ *
+ * @return the list of suggestions
+ */
+ public List getSuggestions() {
+ return suggestions;
+ }
+
+ /**
+ * Set the list of suggestions that are to be presented.
+ *
+ * @param suggestions the list of suggestions
+ */
+ public void setSuggestions(List suggestions) {
+ checkNotNull(suggestions);
+ this.suggestions = suggestions;
+ }
+
+}
diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java
index a3e506bdb..a8e5b7043 100644
--- a/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java
+++ b/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java
@@ -30,8 +30,9 @@ import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.*;
import com.sk89q.worldedit.event.platform.CommandEvent;
+import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
+import com.sk89q.worldedit.internal.command.ActorAuthorizer;
import com.sk89q.worldedit.internal.command.CommandLoggingHandler;
-import com.sk89q.worldedit.internal.command.CommandPermissionsHandler;
import com.sk89q.worldedit.internal.command.WorldEditBinding;
import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter;
import com.sk89q.worldedit.session.request.Request;
@@ -87,11 +88,11 @@ public final class CommandManager {
// Set up the commands manager
ParametricBuilder builder = new ParametricBuilder();
+ builder.setAuthorizer(new ActorAuthorizer());
builder.addBinding(new WorldEditBinding(worldEdit));
- builder.attach(new CommandPermissionsHandler());
- builder.attach(new WorldEditExceptionConverter(worldEdit));
- builder.attach(new LegacyCommandsHandler());
- builder.attach(new CommandLoggingHandler(worldEdit, logger));
+ builder.addExceptionConverter(new WorldEditExceptionConverter(worldEdit));
+ builder.addInvokeListener(new LegacyCommandsHandler());
+ builder.addInvokeListener(new CommandLoggingHandler(worldEdit, logger));
dispatcher = new CommandGraph()
.builder(builder)
@@ -171,8 +172,6 @@ public final class CommandManager {
}
public String[] commandDetection(String[] split) {
- split[0] = split[0].substring(1);
-
// Quick script shortcut
if (split[0].matches("^[^/].*\\.js$")) {
String[] newSplit = new String[split.length + 1];
@@ -185,13 +184,14 @@ public final class CommandManager {
String searchCmd = split[0].toLowerCase();
// Try to detect the command
- if (dispatcher.contains(searchCmd)) {
- } else if (worldEdit.getConfiguration().noDoubleSlash && dispatcher.contains("/" + searchCmd)) {
- split[0] = "/" + split[0];
- } else if (split[0].length() >= 2 && split[0].charAt(0) == '/'
- && dispatcher.contains(searchCmd.substring(1))) {
- split[0] = split[0].substring(1);
+ if (!dispatcher.contains(searchCmd)) {
+ if (worldEdit.getConfiguration().noDoubleSlash && dispatcher.contains("/" + searchCmd)) {
+ split[0] = "/" + split[0];
+ } else if (searchCmd.length() >= 2 && searchCmd.charAt(0) == '/' && dispatcher.contains(searchCmd.substring(1))) {
+ split[0] = split[0].substring(1);
+ }
}
+
return split;
}
@@ -200,7 +200,7 @@ public final class CommandManager {
Request.reset();
Actor actor = platformManager.createProxyActor(event.getActor());
- String split[] = commandDetection(event.getArguments());
+ String split[] = commandDetection(event.getArguments().split(" "));
// No command found!
if (!dispatcher.contains(split[0])) {
@@ -216,7 +216,7 @@ public final class CommandManager {
long start = System.currentTimeMillis();
try {
- dispatcher.call(Joiner.on(" ").join(split), locals);
+ dispatcher.call(null, Joiner.on(" ").join(split), locals);
} catch (CommandPermissionsException e) {
actor.printError("You don't have permission to do this.");
} catch (InvalidUsageException e) {
@@ -255,6 +255,15 @@ public final class CommandManager {
event.setCancelled(true);
}
+ @Subscribe
+ public void handleCommandSuggestion(CommandSuggestionEvent event) {
+ try {
+ event.setSuggestions(dispatcher.getSuggestions(event.getArguments()));
+ } catch (CommandException e) {
+ event.getActor().printError(e.getMessage());
+ }
+ }
+
/**
* Get the command dispatcher instance.
*
diff --git a/src/main/java/com/sk89q/worldedit/internal/command/CommandPermissionsHandler.java b/src/main/java/com/sk89q/worldedit/internal/command/ActorAuthorizer.java
similarity index 75%
rename from src/main/java/com/sk89q/worldedit/internal/command/CommandPermissionsHandler.java
rename to src/main/java/com/sk89q/worldedit/internal/command/ActorAuthorizer.java
index cbf5eb7c5..f2f301ca2 100644
--- a/src/main/java/com/sk89q/worldedit/internal/command/CommandPermissionsHandler.java
+++ b/src/main/java/com/sk89q/worldedit/internal/command/ActorAuthorizer.java
@@ -19,23 +19,22 @@
package com.sk89q.worldedit.internal.command;
-import com.sk89q.minecraft.util.commands.CommandContext;
+import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.extension.platform.Actor;
-import com.sk89q.worldedit.util.command.parametric.PermissionsHandler;
+import com.sk89q.worldedit.util.auth.Authorizer;
-public class CommandPermissionsHandler extends PermissionsHandler {
-
- public CommandPermissionsHandler() {
- }
+/**
+ * Implementation of an authorizer that uses {@link Actor#hasPermission(String)}.
+ */
+public class ActorAuthorizer implements Authorizer {
@Override
- protected boolean hasPermission(CommandContext context, String permission) {
- Actor sender = context.getLocals().get(Actor.class);
+ public boolean testPermission(CommandLocals locals, String permission) {
+ Actor sender = locals.get(Actor.class);
if (sender == null) {
throw new RuntimeException("Uh oh! No 'Actor' specified so that we can check permissions");
} else {
return sender.hasPermission(permission);
}
}
-
}
diff --git a/src/main/java/com/sk89q/worldedit/util/auth/Authorizer.java b/src/main/java/com/sk89q/worldedit/util/auth/Authorizer.java
new file mode 100644
index 000000000..adbeafc7c
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/util/auth/Authorizer.java
@@ -0,0 +1,38 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.util.auth;
+
+import com.sk89q.minecraft.util.commands.CommandLocals;
+
+/**
+ * Tests whether permission is granted.
+ */
+public interface Authorizer {
+
+ /**
+ * Tests whether permission is granted for the given context.
+ *
+ * @param locals locals
+ * @param permission the permission string
+ * @return true if permitted
+ */
+ boolean testPermission(CommandLocals locals, String permission);
+
+}
diff --git a/src/main/java/com/sk89q/worldedit/util/auth/NullAuthorizer.java b/src/main/java/com/sk89q/worldedit/util/auth/NullAuthorizer.java
new file mode 100644
index 000000000..346e6b794
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/util/auth/NullAuthorizer.java
@@ -0,0 +1,35 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.util.auth;
+
+import com.sk89q.minecraft.util.commands.CommandLocals;
+
+/**
+ * An implementation of {@link Authorizer} that always returns false for
+ * tests of permissions.
+ */
+public class NullAuthorizer implements Authorizer {
+
+ @Override
+ public boolean testPermission(CommandLocals locals, String permission) {
+ return false;
+ }
+
+}
diff --git a/src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java b/src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java
index 0fd96670d..1120dffc8 100644
--- a/src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java
+++ b/src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java
@@ -22,7 +22,8 @@ package com.sk89q.worldedit.util.command;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
-import java.util.Collection;
+import javax.annotation.Nullable;
+import java.util.List;
import java.util.Set;
/**
@@ -39,13 +40,17 @@ public interface CommandCallable {
/**
* Execute the correct command based on the input.
+ *
+ * The implementing class must perform the necessary permission checks.
*
+ * @param alias the alias that was used to invoke this command,
+ * which may be null if this is a "root" command
* @param arguments the arguments
* @param locals the locals
* @return the called command, or null if there was no command found
* @throws CommandException thrown on a command error
*/
- boolean call(String arguments, CommandLocals locals) throws CommandException;
+ boolean call(@Nullable String alias, String arguments, CommandLocals locals) throws CommandException;
/**
* Get a list of suggestions based on input.
@@ -54,7 +59,7 @@ public interface CommandCallable {
* @return a list of suggestions
* @throws CommandException thrown if there was a parsing error
*/
- Collection getSuggestions(String arguments) throws CommandException;
+ List getSuggestions(String arguments) throws CommandException;
/**
* Get an object describing this command.
@@ -63,4 +68,12 @@ public interface CommandCallable {
*/
Description getDescription();
+ /**
+ * Test whether this command can be executed with the given context.
+ *
+ * @param locals the locals
+ * @return true if execution is permitted
+ */
+ boolean testPermission(CommandLocals locals);
+
}
diff --git a/src/main/java/com/sk89q/worldedit/util/command/Description.java b/src/main/java/com/sk89q/worldedit/util/command/Description.java
index e45885ed1..72e9fd5f0 100644
--- a/src/main/java/com/sk89q/worldedit/util/command/Description.java
+++ b/src/main/java/com/sk89q/worldedit/util/command/Description.java
@@ -38,7 +38,7 @@ public interface Description {
*
* @return a description, or null if no description is available
*/
- String getDescription();
+ String getShortDescription();
/**
* Get a longer help text about this command.
diff --git a/src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java b/src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java
index 38ab1b799..111ee68e5 100644
--- a/src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java
+++ b/src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java
@@ -49,7 +49,7 @@ public class SimpleDescription implements Description {
}
@Override
- public String getDescription() {
+ public String getShortDescription() {
return description;
}
@@ -57,7 +57,7 @@ public class SimpleDescription implements Description {
* Set the description of the command.
*
* @param description the description
- * @see #getDescription()
+ * @see #getShortDescription()
*/
public void setDescription(String description) {
this.description = description;
diff --git a/src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java b/src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java
index 888445017..0d498668b 100644
--- a/src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java
+++ b/src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java
@@ -25,6 +25,7 @@ import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.minecraft.util.commands.WrappedCommandException;
+import javax.annotation.Nullable;
import java.util.*;
/**
@@ -89,20 +90,20 @@ public class SimpleDispatcher implements Dispatcher {
}
@Override
- public boolean call(String arguments, CommandLocals locals) throws CommandException {
+ public boolean call(@Nullable String alias, String arguments, CommandLocals locals) throws CommandException {
String[] split = CommandContext.split(arguments);
Set aliases = getPrimaryAliases();
if (aliases.isEmpty()) {
throw new InvalidUsageException("This command has no sub-commands.", getDescription());
- } else if (split.length != 0) {
+ } else if (split.length > 0) {
String subCommand = split[0];
+ String subArguments = Joiner.on(" ").join(Arrays.copyOfRange(split, 1, split.length));
CommandMapping mapping = get(subCommand);
- String passedArguments = Joiner.on(" ").join(Arrays.copyOfRange(split, 1, split.length));
if (mapping != null) {
try {
- mapping.getCallable().call(passedArguments, locals);
+ mapping.getCallable().call(subCommand, subArguments, locals);
} catch (CommandException e) {
e.prependStack(subCommand);
throw e;
@@ -119,22 +120,26 @@ public class SimpleDispatcher implements Dispatcher {
}
@Override
- public Collection getSuggestions(String arguments) throws CommandException {
+ public List getSuggestions(String arguments) throws CommandException {
String[] split = CommandContext.split(arguments);
if (split.length == 0) {
- return getAllAliases();
+ return new ArrayList(getAllAliases());
} else if (split.length == 1) {
String prefix = split[0];
- List suggestions = new ArrayList();
+ if (!prefix.isEmpty()) {
+ List suggestions = new ArrayList();
- for (String alias : getAllAliases()) {
- if (alias.startsWith(prefix)) {
- suggestions.add(alias);
+ for (String alias : getAllAliases()) {
+ if (alias.startsWith(prefix)) {
+ suggestions.add(alias);
+ }
}
- }
- return suggestions;
+ return suggestions;
+ } else {
+ return new ArrayList(getAllAliases());
+ }
} else {
String subCommand = split[0];
CommandMapping mapping = get(subCommand);
@@ -153,6 +158,17 @@ public class SimpleDispatcher implements Dispatcher {
return description;
}
+ @Override
+ public boolean testPermission(CommandLocals locals) {
+ for (CommandMapping mapping : getCommands()) {
+ if (mapping.getCallable().testPermission(locals)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
/**
* Get a list of subcommands for display.
*
diff --git a/src/main/java/com/sk89q/worldedit/util/command/fluent/DispatcherNode.java b/src/main/java/com/sk89q/worldedit/util/command/fluent/DispatcherNode.java
index 8a4f71b6c..49b53d8b9 100644
--- a/src/main/java/com/sk89q/worldedit/util/command/fluent/DispatcherNode.java
+++ b/src/main/java/com/sk89q/worldedit/util/command/fluent/DispatcherNode.java
@@ -79,14 +79,14 @@ public class DispatcherNode {
*
* @param object the object provided to the {@link ParametricBuilder}
* @return this object
- * @see ParametricBuilder#register(com.sk89q.worldedit.util.command.Dispatcher, Object)
+ * @see ParametricBuilder#registerMethodsAsCommands(com.sk89q.worldedit.util.command.Dispatcher, Object)
*/
public DispatcherNode build(Object object) {
ParametricBuilder builder = graph.getBuilder();
if (builder == null) {
throw new RuntimeException("No ParametricBuilder set");
}
- builder.register(getDispatcher(), object);
+ builder.registerMethodsAsCommands(getDispatcher(), object);
return this;
}
diff --git a/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricBuilder.java b/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricBuilder.java
index be7bc2c1e..f788a695f 100644
--- a/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricBuilder.java
+++ b/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricBuilder.java
@@ -24,6 +24,8 @@ import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
+import com.sk89q.worldedit.util.auth.Authorizer;
+import com.sk89q.worldedit.util.auth.NullAuthorizer;
import com.sk89q.worldedit.util.command.CommandCallable;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.util.command.binding.PrimitiveBindings;
@@ -39,6 +41,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import static com.google.common.base.Preconditions.checkNotNull;
+
/**
* Creates commands using annotations placed on methods and individual parameters of
* such methods.
@@ -52,6 +56,7 @@ public class ParametricBuilder {
private final Paranamer paranamer = new CachingParanamer();
private final List invokeListeners = new ArrayList();
private final List exceptionConverters = new ArrayList();
+ private Authorizer authorizer = new NullAuthorizer();
/**
* Create a new builder.
@@ -115,7 +120,7 @@ public class ParametricBuilder {
* @param listener the listener
* @see InvokeHandler the handler
*/
- public void attach(InvokeListener listener) {
+ public void addInvokeListener(InvokeListener listener) {
invokeListeners.add(listener);
}
@@ -128,7 +133,7 @@ public class ParametricBuilder {
* @param converter the converter
* @see ExceptionConverter for an explanation
*/
- public void attach(ExceptionConverter converter) {
+ public void addExceptionConverter(ExceptionConverter converter) {
exceptionConverters.add(converter);
}
@@ -141,7 +146,7 @@ public class ParametricBuilder {
* @param object the object contain the methods
* @throws ParametricException thrown if the commands cannot be registered
*/
- public void register(Dispatcher dispatcher, Object object) throws ParametricException {
+ public void registerMethodsAsCommands(Dispatcher dispatcher, Object object) throws ParametricException {
for (Method method : object.getClass().getDeclaredMethods()) {
Command definition = method.getAnnotation(Command.class);
if (definition != null) {
@@ -201,5 +206,23 @@ public class ParametricBuilder {
List getExceptionConverters() {
return exceptionConverters;
}
-
+
+ /**
+ * Get the authorizer.
+ *
+ * @return the authorizer
+ */
+ public Authorizer getAuthorizer() {
+ return authorizer;
+ }
+
+ /**
+ * Set the authorizer.
+ *
+ * @param authorizer the authorizer
+ */
+ public void setAuthorizer(Authorizer authorizer) {
+ checkNotNull(authorizer);
+ this.authorizer = authorizer;
+ }
}
diff --git a/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java b/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java
index 23e2d1b22..bada21862 100644
--- a/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java
+++ b/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java
@@ -23,6 +23,7 @@ import com.sk89q.minecraft.util.commands.*;
import com.sk89q.worldedit.util.command.*;
import com.sk89q.worldedit.util.command.binding.Switch;
+import javax.annotation.Nullable;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -40,6 +41,7 @@ class ParametricCallable implements CommandCallable {
private final ParameterData[] parameters;
private final Set valueFlags = new HashSet();
private final SimpleDescription description = new SimpleDescription();
+ private final CommandPermissions commandPermissions;
/**
* Create a new instance.
@@ -50,11 +52,7 @@ class ParametricCallable implements CommandCallable {
* @param definition the command definition annotation
* @throws ParametricException thrown on an error
*/
- ParametricCallable(
- ParametricBuilder builder,
- Object object, Method method,
- Command definition) throws ParametricException {
-
+ ParametricCallable(ParametricBuilder builder, Object object, Method method, Command definition) throws ParametricException {
this.builder = builder;
this.object = object;
this.method = method;
@@ -101,8 +99,7 @@ class ParametricCallable implements CommandCallable {
}
}
- parameter.setName(names.length > 0 ?
- names[i] : generateName(type, parameter.getClassifier(), i));
+ parameter.setName(names.length > 0 ? names[i] : generateName(type, parameter.getClassifier(), i));
// Track all value flags
if (parameter.isValueFlag()) {
@@ -115,9 +112,7 @@ class ParametricCallable implements CommandCallable {
// Don't know how to parse for this type of value
if (parameter.getBinding() == null) {
- throw new ParametricException(
- "Don't know how to handle the parameter type '" + type + "' in\n" +
- method.toGenericString());
+ throw new ParametricException("Don't know how to handle the parameter type '" + type + "' in\n" + method.toGenericString());
}
}
@@ -159,11 +154,19 @@ class ParametricCallable implements CommandCallable {
// Set parameters
description.setParameters(userParameters);
+
+ // Get permissions annotation
+ commandPermissions = method.getAnnotation(CommandPermissions.class);
}
@Override
- public boolean call(String stringArguments, CommandLocals locals) throws CommandException {
- String[] split = CommandContext.split(stringArguments);
+ public boolean call(@Nullable String alias, String stringArguments, CommandLocals locals) throws CommandException {
+ // Test permission
+ if (!testPermission(locals)) {
+ throw new CommandPermissionsException();
+ }
+
+ String[] split = CommandContext.split(alias + " " + stringArguments);
CommandContext context = new CommandContext(split, getValueFlags(), false, locals);
Object[] args = new Object[parameters.length];
@@ -218,12 +221,9 @@ class ParametricCallable implements CommandCallable {
handler.postInvoke(handler, method, parameters, args, context);
}
} catch (MissingParameterException e) {
- throw new InvalidUsageException(
- "Too few parameters!", getDescription());
+ throw new InvalidUsageException("Too few parameters!", getDescription());
} catch (UnconsumedParameterException e) {
- throw new InvalidUsageException(
- "Too many parameters! Unused parameters: "
- + e.getUnconsumed(), getDescription());
+ throw new InvalidUsageException("Too many parameters! Unused parameters: " + e.getUnconsumed(), getDescription());
} catch (ParameterException e) {
if (e.getCause() != null) {
for (ExceptionConverter converter : builder.getExceptionConverters()) {
@@ -231,10 +231,10 @@ class ParametricCallable implements CommandCallable {
}
}
+ assert parameter != null;
String name = parameter.getName();
- throw new InvalidUsageException("For parameter '" + name + "': "
- + e.getMessage(), getDescription());
+ throw new InvalidUsageException("For parameter '" + name + "': " + e.getMessage(), getDescription());
} catch (InvocationTargetException e) {
for (ExceptionConverter converter : builder.getExceptionConverters()) {
converter.convert(e.getCause());
@@ -252,7 +252,7 @@ class ParametricCallable implements CommandCallable {
}
@Override
- public Collection getSuggestions(String stringArguments) throws CommandException {
+ public List getSuggestions(String stringArguments) throws CommandException {
String[] split = CommandContext.split(stringArguments);
CommandContext context = new CommandContext(split, getValueFlags());
@@ -281,13 +281,11 @@ class ParametricCallable implements CommandCallable {
ParameterData lastConsumer = null;
String lastConsumed = null;
- for (int i = 0; i < parameters.length; i++) {
- ParameterData parameter = parameters[i];
-
+ for (ParameterData parameter : parameters) {
if (parameter.getFlag() != null) {
continue; // We already handled flags
}
-
+
try {
scoped.mark();
parameter.getBinding().bind(parameter, scoped, true);
@@ -306,8 +304,8 @@ class ParametricCallable implements CommandCallable {
if (lastConsumer != null) {
return lastConsumer.getBinding()
.getSuggestions(lastConsumer, lastConsumed);
- // For /command| value1 value2
- // This should never occur
+ // For /command| value1 value2
+ // This should never occur
} else {
throw new RuntimeException("Invalid suggestion context");
}
@@ -352,7 +350,22 @@ class ParametricCallable implements CommandCallable {
public SimpleDescription getDescription() {
return description;
}
-
+
+ @Override
+ public boolean testPermission(CommandLocals locals) {
+ if (commandPermissions != null) {
+ for (String perm : commandPermissions.value()) {
+ if (builder.getAuthorizer().testPermission(locals, perm)) {
+ return true;
+ }
+ }
+
+ return false;
+ } else {
+ return true;
+ }
+ }
+
/**
* Get the right {@link ArgumentStack}.
*
diff --git a/src/main/java/com/sk89q/worldedit/util/command/parametric/PermissionsHandler.java b/src/main/java/com/sk89q/worldedit/util/command/parametric/PermissionsHandler.java
deleted file mode 100644
index ed11942ba..000000000
--- a/src/main/java/com/sk89q/worldedit/util/command/parametric/PermissionsHandler.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * WorldEdit, a Minecraft world manipulation toolkit
- * Copyright (C) sk89q
- * Copyright (C) WorldEdit team and contributors
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by the
- * Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.sk89q.worldedit.util.command.parametric;
-
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandException;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
-import com.sk89q.minecraft.util.commands.CommandPermissionsException;
-
-import java.lang.reflect.Method;
-
-/**
- * A handler for the {@link CommandPermissions} annotation.
- */
-public abstract class PermissionsHandler extends AbstractInvokeListener implements InvokeHandler {
-
- @Override
- public InvokeHandler createInvokeHandler() {
- return this;
- }
-
- @Override
- public void preProcess(Object object, Method method,
- ParameterData[] parameters, CommandContext context)
- throws CommandException, ParameterException {
- CommandPermissions annotation = method.getAnnotation(CommandPermissions.class);
- if (annotation != null) {
- for (String perm : annotation.value()) {
- if (hasPermission(context, perm)) {
- return;
- }
- }
-
- throw new CommandPermissionsException();
- }
- }
-
- @Override
- public void preInvoke(Object object, Method method, ParameterData[] parameters,
- Object[] args, CommandContext context) throws CommandException {
- }
-
- @Override
- public void postInvoke(Object object, Method method, ParameterData[] parameters,
- Object[] args, CommandContext context) throws CommandException {
- }
-
- protected abstract boolean hasPermission(CommandContext context, String permission);
-
-}