summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main/java/org/bukkit/command/Command.java48
-rw-r--r--src/main/java/org/bukkit/command/CommandMap.java12
-rw-r--r--src/main/java/org/bukkit/command/MultipleCommandAlias.java2
-rw-r--r--src/main/java/org/bukkit/command/PluginCommand.java67
-rw-r--r--src/main/java/org/bukkit/command/SimpleCommandMap.java95
-rw-r--r--src/main/java/org/bukkit/command/TabCommandExecutor.java4
-rw-r--r--src/main/java/org/bukkit/command/TabCompleter.java20
-rw-r--r--src/main/java/org/bukkit/command/TabExecutor.java7
-rw-r--r--src/main/java/org/bukkit/command/defaults/BanCommand.java19
-rw-r--r--src/main/java/org/bukkit/command/defaults/BanIpCommand.java21
-rw-r--r--src/main/java/org/bukkit/command/defaults/BanListCommand.java19
-rw-r--r--src/main/java/org/bukkit/command/defaults/BukkitCommand.java6
-rw-r--r--src/main/java/org/bukkit/command/defaults/DefaultGameModeCommand.java22
-rw-r--r--src/main/java/org/bukkit/command/defaults/DeopCommand.java28
-rw-r--r--src/main/java/org/bukkit/command/defaults/ExpCommand.java17
-rw-r--r--src/main/java/org/bukkit/command/defaults/GameModeCommand.java27
-rw-r--r--src/main/java/org/bukkit/command/defaults/GiveCommand.java59
-rw-r--r--src/main/java/org/bukkit/command/defaults/HelpCommand.java31
-rw-r--r--src/main/java/org/bukkit/command/defaults/KickCommand.java17
-rw-r--r--src/main/java/org/bukkit/command/defaults/KillCommand.java14
-rw-r--r--src/main/java/org/bukkit/command/defaults/ListCommand.java14
-rw-r--r--src/main/java/org/bukkit/command/defaults/OpCommand.java44
-rw-r--r--src/main/java/org/bukkit/command/defaults/PardonCommand.java27
-rw-r--r--src/main/java/org/bukkit/command/defaults/PardonIpCommand.java19
-rw-r--r--src/main/java/org/bukkit/command/defaults/PluginsCommand.java3
-rw-r--r--src/main/java/org/bukkit/command/defaults/ReloadCommand.java3
-rw-r--r--src/main/java/org/bukkit/command/defaults/SaveCommand.java14
-rw-r--r--src/main/java/org/bukkit/command/defaults/SaveOffCommand.java14
-rw-r--r--src/main/java/org/bukkit/command/defaults/SaveOnCommand.java14
-rw-r--r--src/main/java/org/bukkit/command/defaults/SayCommand.java16
-rw-r--r--src/main/java/org/bukkit/command/defaults/SeedCommand.java14
-rw-r--r--src/main/java/org/bukkit/command/defaults/StopCommand.java14
-rw-r--r--src/main/java/org/bukkit/command/defaults/TeleportCommand.java17
-rw-r--r--src/main/java/org/bukkit/command/defaults/TimeCommand.java24
-rw-r--r--src/main/java/org/bukkit/command/defaults/TimingsCommand.java21
-rw-r--r--src/main/java/org/bukkit/command/defaults/ToggleDownfallCommand.java14
-rw-r--r--src/main/java/org/bukkit/command/defaults/VanillaCommand.java4
-rw-r--r--src/main/java/org/bukkit/command/defaults/VersionCommand.java26
-rw-r--r--src/main/java/org/bukkit/command/defaults/WhitelistCommand.java41
-rw-r--r--src/main/java/org/bukkit/plugin/Plugin.java4
-rw-r--r--src/main/java/org/bukkit/plugin/java/JavaPlugin.java7
-rw-r--r--src/main/java/org/bukkit/util/StringUtil.java49
-rw-r--r--src/test/java/org/bukkit/plugin/TestPlugin.java5
43 files changed, 898 insertions, 45 deletions
diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java
index ec502af5..b0b7f21f 100644
--- a/src/main/java/org/bukkit/command/Command.java
+++ b/src/main/java/org/bukkit/command/Command.java
@@ -1,12 +1,19 @@
package org.bukkit.command;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Server;
+import org.bukkit.entity.Player;
import org.bukkit.permissions.Permissible;
+import org.bukkit.util.StringUtil;
+
+import com.google.common.collect.ImmutableList;
/**
* Represents a Command, which executes various tasks upon user input
@@ -48,19 +55,46 @@ public abstract class Command {
public abstract boolean execute(CommandSender sender, String commandLabel, String[] args);
/**
+ * @deprecated This method is not supported and returns null
+ */
+ @Deprecated
+ public List<String> tabComplete(CommandSender sender, String[] args) {
+ return null;
+ }
+
+ /**
* Executed on tab completion for this command, returning a list of options
* the player can tab through.
- * <p />
- * By returning null, you tell Bukkit to generate a list of players to send
- * to the sender.
- * By returning an empty list, no options will be sent.
*
* @param sender Source object which is executing this command
+ * @param alias the alias being used
* @param args All arguments passed to the command, split via ' '
- * @return null to generate a Player list, otherwise a list of options
+ * @return a list of tab-completions for the specified arguments. This will never be null. List may be immutable.
+ * @throws IllegalArgumentException if sender, alias, or args is null
*/
- public List<String> tabComplete(CommandSender sender, String[] args) {
- return null;
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (!(sender instanceof Player) || args.length == 0) {
+ return ImmutableList.of();
+ }
+
+ String lastWord = args[args.length - 1];
+
+ Player senderPlayer = (Player) sender;
+
+ ArrayList<String> matchedPlayers = new ArrayList<String>();
+ for (Player player : sender.getServer().getOnlinePlayers()) {
+ String name = player.getName();
+ if (senderPlayer.canSee(player) && StringUtil.startsWithIgnoreCase(name, lastWord)) {
+ matchedPlayers.add(name);
+ }
+ }
+
+ Collections.sort(matchedPlayers, String.CASE_INSENSITIVE_ORDER);
+ return matchedPlayers;
}
/**
diff --git a/src/main/java/org/bukkit/command/CommandMap.java b/src/main/java/org/bukkit/command/CommandMap.java
index 5524da27..e7fad287 100644
--- a/src/main/java/org/bukkit/command/CommandMap.java
+++ b/src/main/java/org/bukkit/command/CommandMap.java
@@ -62,4 +62,16 @@ public interface CommandMap {
* @return Command with the specified name or null if a command with that label doesn't exist
*/
public Command getCommand(String name);
+
+
+ /**
+ * Looks for the requested command and executes an appropriate tab-completer if found. This method will also tab-complete partial commands.
+ *
+ * @param sender The command's sender.
+ * @param cmdLine The entire command string to tab-complete, excluding initial slash.
+ * @return a list of possible tab-completions. This list may be immutable. Will be null if no matching command of which sender has permission.
+ * @throws CommandException Thrown when the tab-completer for the given command fails with an unhandled exception
+ * @throws IllegalArgumentException if either sender or cmdLine are null
+ */
+ public List<String> tabComplete(CommandSender sender, String cmdLine) throws IllegalArgumentException;
}
diff --git a/src/main/java/org/bukkit/command/MultipleCommandAlias.java b/src/main/java/org/bukkit/command/MultipleCommandAlias.java
index b1b83b1f..3a666d16 100644
--- a/src/main/java/org/bukkit/command/MultipleCommandAlias.java
+++ b/src/main/java/org/bukkit/command/MultipleCommandAlias.java
@@ -10,7 +10,7 @@ public class MultipleCommandAlias extends Command {
super(name);
this.commands = commands;
}
-
+
public Command[] getCommands() {
return commands;
}
diff --git a/src/main/java/org/bukkit/command/PluginCommand.java b/src/main/java/org/bukkit/command/PluginCommand.java
index 05975c7f..f82e3ed3 100644
--- a/src/main/java/org/bukkit/command/PluginCommand.java
+++ b/src/main/java/org/bukkit/command/PluginCommand.java
@@ -1,5 +1,8 @@
package org.bukkit.command;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.plugin.Plugin;
/**
@@ -8,6 +11,7 @@ import org.bukkit.plugin.Plugin;
public final class PluginCommand extends Command implements PluginIdentifiableCommand {
private final Plugin owningPlugin;
private CommandExecutor executor;
+ private TabCompleter completer;
protected PluginCommand(String name, Plugin owner) {
super(name);
@@ -70,6 +74,26 @@ public final class PluginCommand extends Command implements PluginIdentifiableCo
}
/**
+ * Sets the {@link TabCompleter} to run when tab-completing this command.
+ * If no TabCompleter is specified, and the command's executor implements
+ * TabCompleter, then the executor will be used for tab completion.
+ *
+ * @param completer New tab completer
+ */
+ public void setTabCompleter(TabCompleter completer) {
+ this.completer = completer;
+ }
+
+ /**
+ * Gets the {@link TabCompleter} associated with this command.
+ *
+ * @return TabCompleter object linked to this command
+ */
+ public TabCompleter getTabCompleter() {
+ return completer;
+ }
+
+ /**
* Gets the owner of this PluginCommand
*
* @return Plugin that owns this command
@@ -77,4 +101,47 @@ public final class PluginCommand extends Command implements PluginIdentifiableCo
public Plugin getPlugin() {
return owningPlugin;
}
+
+ /**
+ * {@inheritDoc}<br>
+ * <br>
+ * Delegates to the tab completer if present.<br>
+ * If it is not present or returns null, will delegate to the current command
+ * executor if it implements {@link TabCompleter}. If a non-null list has not
+ * been found, will default to standard player name completion in
+ * {@link Command#tabComplete(CommandSender, String, String[])}.<br>
+ * <br>
+ * This method does not consider permissions.
+ * @throws CommandException if the completer or executor throw an exception during the process of tab-completing.
+ * @throws IllegalArgumentException if sender, alias, or args is null
+ */
+ @Override
+ public java.util.List<String> tabComplete(CommandSender sender, String alias, String[] args) throws CommandException, IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ List<String> completions = null;
+ try {
+ if (completer != null) {
+ completions = completer.onTabComplete(sender, this, alias, args);
+ }
+ if (completions == null && executor instanceof TabCompleter) {
+ completions = ((TabCompleter) executor).onTabComplete(sender, this, alias, args);
+ }
+ } catch (Throwable ex) {
+ StringBuilder message = new StringBuilder();
+ message.append("Unhandled exception during tab completion for command '/").append(alias).append(' ');
+ for (String arg : args) {
+ message.append(arg).append(' ');
+ }
+ message.deleteCharAt(message.length() - 1).append("' in plugin ").append(owningPlugin.getDescription().getFullName());
+ throw new CommandException(message.toString(), ex);
+ }
+
+ if (completions == null) {
+ return super.tabComplete(sender, alias, args);
+ }
+ return completions;
+ }
}
diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java
index 384a01ec..a44504ef 100644
--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java
+++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java
@@ -1,13 +1,25 @@
package org.bukkit.command;
-import org.bukkit.command.defaults.*;
-
-import java.util.*;
+import static org.bukkit.util.Java15Compat.Arrays_copyOfRange;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Server;
-import static org.bukkit.util.Java15Compat.Arrays_copyOfRange;
+import org.bukkit.command.defaults.*;
+import org.bukkit.util.StringUtil;
public class SimpleCommandMap implements CommandMap {
+ private static final Pattern PATTERN_ON_SPACE = Pattern.compile(" ", Pattern.LITERAL);
protected final Map<String, Command> knownCommands = new HashMap<String, Command>();
protected final Set<String> aliases = new HashSet<String>();
private final Server server;
@@ -81,7 +93,7 @@ public class SimpleCommandMap implements CommandMap {
Iterator<String> iterator = command.getAliases().iterator();
while (iterator.hasNext()) {
- if (!register((String) iterator.next(), fallbackPrefix, command, true)) {
+ if (!register(iterator.next(), fallbackPrefix, command, true)) {
iterator.remove();
}
}
@@ -150,7 +162,7 @@ public class SimpleCommandMap implements CommandMap {
* {@inheritDoc}
*/
public boolean dispatch(CommandSender sender, String commandLine) throws CommandException {
- String[] args = commandLine.split(" ");
+ String[] args = PATTERN_ON_SPACE.split(commandLine);
if (args.length == 0) {
return false;
@@ -186,13 +198,82 @@ public class SimpleCommandMap implements CommandMap {
}
public Command getCommand(String name) {
- Command target = knownCommands.get(name.toLowerCase());
+ Command target = knownCommands.get(name.toLowerCase());
if (target == null) {
target = getFallback(name);
}
return target;
}
+ public List<String> tabComplete(CommandSender sender, String cmdLine) {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(cmdLine, "Command line cannot null");
+
+ int spaceIndex = cmdLine.indexOf(' ');
+
+ if (spaceIndex == -1) {
+ ArrayList<String> completions = new ArrayList<String>();
+ Map<String, Command> knownCommands = this.knownCommands;
+
+ for (VanillaCommand command : fallbackCommands) {
+ String name = command.getName();
+
+ if (!command.testPermissionSilent(sender)) {
+ continue;
+ }
+ if (knownCommands.containsKey(name)) {
+ // Don't let a vanilla command override a command added below
+ // This has to do with the way aliases work
+ continue;
+ }
+ if (!StringUtil.startsWithIgnoreCase(name, cmdLine)) {
+ continue;
+ }
+
+ completions.add('/' + name);
+ }
+
+ for (Map.Entry<String, Command> commandEntry : knownCommands.entrySet()) {
+ Command command = commandEntry.getValue();
+
+ if (!command.testPermissionSilent(sender)) {
+ continue;
+ }
+
+ String name = commandEntry.getKey(); // Use the alias, not command name
+
+ if (StringUtil.startsWithIgnoreCase(name, cmdLine)) {
+ completions.add('/' + name);
+ }
+ }
+
+ Collections.sort(completions, String.CASE_INSENSITIVE_ORDER);
+ return completions;
+ }
+
+ String commandName = cmdLine.substring(0, spaceIndex);
+ Command target = getCommand(commandName);
+
+ if (target == null) {
+ return null;
+ }
+
+ if (!target.testPermissionSilent(sender)) {
+ return null;
+ }
+
+ String argLine = cmdLine.substring(spaceIndex + 1, cmdLine.length());
+ String[] args = PATTERN_ON_SPACE.split(argLine, -1);
+
+ try {
+ return target.tabComplete(sender, commandName, args);
+ } catch (CommandException ex) {
+ throw ex;
+ } catch (Throwable ex) {
+ throw new CommandException("Unhandled exception executing tab-completer for '" + cmdLine + "' in " + target, ex);
+ }
+ }
+
public Collection<Command> getCommands() {
return knownCommands.values();
}
diff --git a/src/main/java/org/bukkit/command/TabCommandExecutor.java b/src/main/java/org/bukkit/command/TabCommandExecutor.java
index b2ee58c5..95efbd40 100644
--- a/src/main/java/org/bukkit/command/TabCommandExecutor.java
+++ b/src/main/java/org/bukkit/command/TabCommandExecutor.java
@@ -4,7 +4,11 @@ import java.util.List;
/**
* Represents a class which can handle command tab completion and commands
+ * @deprecated Remains for plugins that would have implemented it even without functionality
+ * @see TabExecutor
*/
+@Deprecated
public interface TabCommandExecutor extends CommandExecutor {
public List<String> onTabComplete();
+
}
diff --git a/src/main/java/org/bukkit/command/TabCompleter.java b/src/main/java/org/bukkit/command/TabCompleter.java
new file mode 100644
index 00000000..3ba64fe8
--- /dev/null
+++ b/src/main/java/org/bukkit/command/TabCompleter.java
@@ -0,0 +1,20 @@
+package org.bukkit.command;
+
+import java.util.List;
+
+/**
+ * Represents a class which can suggest tab completions for commands.
+ */
+public interface TabCompleter {
+
+ /**
+ * Requests a list of possible completions for a command argument.
+ *
+ * @param sender Source of the command
+ * @param command Command which was executed
+ * @param alias The alias used
+ * @param args The arguments passed to the command, including final partial argument to be completed and command label
+ * @return A List of possible completions for the final argument, or null to default to the command executor
+ */
+ public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args);
+}
diff --git a/src/main/java/org/bukkit/command/TabExecutor.java b/src/main/java/org/bukkit/command/TabExecutor.java
new file mode 100644
index 00000000..67b3503d
--- /dev/null
+++ b/src/main/java/org/bukkit/command/TabExecutor.java
@@ -0,0 +1,7 @@
+package org.bukkit.command;
+
+/**
+ * This class is provided as a convenience to implement both TabCompleter and CommandExecutor.
+ */
+public interface TabExecutor extends TabCompleter, CommandExecutor {
+}
diff --git a/src/main/java/org/bukkit/command/defaults/BanCommand.java b/src/main/java/org/bukkit/command/defaults/BanCommand.java
index c4d3a54c..c4366524 100644
--- a/src/main/java/org/bukkit/command/defaults/BanCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/BanCommand.java
@@ -1,12 +1,16 @@
package org.bukkit.command.defaults;
import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import com.google.common.collect.ImmutableList;
+
public class BanCommand extends VanillaCommand {
public BanCommand() {
super("ban");
@@ -36,12 +40,19 @@ public class BanCommand extends VanillaCommand {
}
@Override
- public List<String> tabComplete(CommandSender sender, String[] args) {
- return args.length >= 1 ? null : EMPTY_LIST;
+ public boolean matches(String input) {
+ return input.equalsIgnoreCase("ban");
}
@Override
- public boolean matches(String input) {
- return input.equalsIgnoreCase("ban");
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length >= 1) {
+ return super.tabComplete(sender, alias, args);
+ }
+ return ImmutableList.of();
}
}
diff --git a/src/main/java/org/bukkit/command/defaults/BanIpCommand.java b/src/main/java/org/bukkit/command/defaults/BanIpCommand.java
index b1049739..8ea0c356 100644
--- a/src/main/java/org/bukkit/command/defaults/BanIpCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/BanIpCommand.java
@@ -2,12 +2,16 @@ package org.bukkit.command.defaults;
import java.util.List;
import java.util.regex.Pattern;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import com.google.common.collect.ImmutableList;
+
public class BanIpCommand extends VanillaCommand {
public static final Pattern ipValidity = Pattern.compile("^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
@@ -43,11 +47,6 @@ public class BanIpCommand extends VanillaCommand {
return true;
}
- @Override
- public List<String> tabComplete(CommandSender sender, String[] args) {
- return args.length >= 1 ? null : EMPTY_LIST;
- }
-
private void processIPBan(String ip, CommandSender sender) {
// TODO: Kick on ban
Bukkit.banIP(ip);
@@ -59,4 +58,16 @@ public class BanIpCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("ban-ip");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ return super.tabComplete(sender, alias, args);
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/BanListCommand.java b/src/main/java/org/bukkit/command/defaults/BanListCommand.java
index 668a4877..08c5be9a 100644
--- a/src/main/java/org/bukkit/command/defaults/BanListCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/BanListCommand.java
@@ -1,11 +1,19 @@
package org.bukkit.command.defaults;
+import java.util.ArrayList;
import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
+import org.bukkit.util.StringUtil;
+
+import com.google.common.collect.ImmutableList;
public class BanListCommand extends VanillaCommand {
+ private static final List<String> BANLIST_TYPES = ImmutableList.of("ips", "players");
+
public BanListCommand() {
super("banlist");
this.description = "View all players banned from this server";
@@ -38,8 +46,15 @@ public class BanListCommand extends VanillaCommand {
}
@Override
- public List<String> tabComplete(CommandSender sender, String[] args) {
- return args.length >= 1 ? null : EMPTY_LIST;
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ return StringUtil.copyPartialMatches(args[0], BANLIST_TYPES, new ArrayList<String>(BANLIST_TYPES.size()));
+ }
+ return ImmutableList.of();
}
@Override
diff --git a/src/main/java/org/bukkit/command/defaults/BukkitCommand.java b/src/main/java/org/bukkit/command/defaults/BukkitCommand.java
index d3de7c8b..23c85800 100644
--- a/src/main/java/org/bukkit/command/defaults/BukkitCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/BukkitCommand.java
@@ -1,10 +1,10 @@
package org.bukkit.command.defaults;
-import org.bukkit.command.Command;
-
import java.util.List;
-public abstract class BukkitCommand extends Command{
+import org.bukkit.command.Command;
+
+public abstract class BukkitCommand extends Command {
protected BukkitCommand(String name) {
super(name);
}
diff --git a/src/main/java/org/bukkit/command/defaults/DefaultGameModeCommand.java b/src/main/java/org/bukkit/command/defaults/DefaultGameModeCommand.java
index 63390b15..1611d413 100644
--- a/src/main/java/org/bukkit/command/defaults/DefaultGameModeCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/DefaultGameModeCommand.java
@@ -1,11 +1,20 @@
package org.bukkit.command.defaults;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
+import org.bukkit.util.StringUtil;
+
+import com.google.common.collect.ImmutableList;
public class DefaultGameModeCommand extends VanillaCommand {
+ private static final List<String> GAMEMODE_NAMES = ImmutableList.of("adventure", "creative", "survival");
+
public DefaultGameModeCommand() {
super("defaultgamemode");
this.description = "Set the default gamemode";
@@ -51,4 +60,17 @@ public class DefaultGameModeCommand extends VanillaCommand {
return true;
}
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ return StringUtil.copyPartialMatches(args[0], GAMEMODE_NAMES, new ArrayList<String>(GAMEMODE_NAMES.size()));
+ } else if (args.length == 2) {
+ return super.tabComplete(sender, alias, args);
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/DeopCommand.java b/src/main/java/org/bukkit/command/defaults/DeopCommand.java
index 291c0497..1ea6cadb 100644
--- a/src/main/java/org/bukkit/command/defaults/DeopCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/DeopCommand.java
@@ -1,11 +1,17 @@
package org.bukkit.command.defaults;
+import java.util.ArrayList;
import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import org.bukkit.util.StringUtil;
+
+import com.google.common.collect.ImmutableList;
public class DeopCommand extends VanillaCommand {
public DeopCommand() {
@@ -35,12 +41,26 @@ public class DeopCommand extends VanillaCommand {
}
@Override
- public List<String> tabComplete(CommandSender sender, String[] args) {
- return args.length >= 1 ? null : EMPTY_LIST;
+ public boolean matches(String input) {
+ return input.equalsIgnoreCase("deop");
}
@Override
- public boolean matches(String input) {
- return input.equalsIgnoreCase("deop");
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ List<String> completions = new ArrayList<String>();
+ for (OfflinePlayer player : Bukkit.getOfflinePlayers()) {
+ String playerName = player.getName();
+ if (player.isOp() && StringUtil.startsWithIgnoreCase(playerName, args[0])) {
+ completions.add(playerName);
+ }
+ }
+ return completions;
+ }
+ return ImmutableList.of();
}
}
diff --git a/src/main/java/org/bukkit/command/defaults/ExpCommand.java b/src/main/java/org/bukkit/command/defaults/ExpCommand.java
index 981cfb7b..791d2e14 100644
--- a/src/main/java/org/bukkit/command/defaults/ExpCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/ExpCommand.java
@@ -1,11 +1,16 @@
package org.bukkit.command.defaults;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import com.google.common.collect.ImmutableList;
+
public class ExpCommand extends VanillaCommand {
public ExpCommand() {
super("xp");
@@ -44,4 +49,16 @@ public class ExpCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("xp");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 2) {
+ return super.tabComplete(sender, alias, args);
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/GameModeCommand.java b/src/main/java/org/bukkit/command/defaults/GameModeCommand.java
index ad445160..8721e20b 100644
--- a/src/main/java/org/bukkit/command/defaults/GameModeCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/GameModeCommand.java
@@ -1,13 +1,22 @@
package org.bukkit.command.defaults;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
import org.bukkit.GameMode;
import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.util.StringUtil;
+
+import com.google.common.collect.ImmutableList;
public class GameModeCommand extends VanillaCommand {
+ private static final List<String> GAMEMODE_NAMES = ImmutableList.of("adventure", "creative", "survival");
+
public GameModeCommand() {
super("gamemode");
this.description = "Changes the player to a specific game mode";
@@ -77,4 +86,18 @@ public class GameModeCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("gamemode");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ return StringUtil.copyPartialMatches(args[0], GAMEMODE_NAMES, new ArrayList<String>(GAMEMODE_NAMES.size()));
+ } else if (args.length == 2) {
+ return super.tabComplete(sender, alias, args);
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/GiveCommand.java b/src/main/java/org/bukkit/command/defaults/GiveCommand.java
index eeac739a..6010ac86 100644
--- a/src/main/java/org/bukkit/command/defaults/GiveCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/GiveCommand.java
@@ -1,5 +1,10 @@
package org.bukkit.command.defaults;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
@@ -7,8 +12,21 @@ import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
+import org.bukkit.util.StringUtil;
+
+import com.google.common.collect.ImmutableList;
public class GiveCommand extends VanillaCommand {
+ private static List<String> materials;
+ static {
+ ArrayList<String> materialList = new ArrayList<String>();
+ for (Material material : Material.values()) {
+ materialList.add(material.name());
+ }
+ Collections.sort(materialList);
+ materials = ImmutableList.copyOf(materialList);
+ }
+
public GiveCommand() {
super("give");
this.description = "Gives the specified player a certain amount of items";
@@ -60,4 +78,45 @@ public class GiveCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("give");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ return super.tabComplete(sender, alias, args);
+ }
+ if (args.length == 2) {
+ final String arg = args[1];
+ final List<String> materials = GiveCommand.materials;
+ List<String> completion = null;
+
+ final int size = materials.size();
+ int i = Collections.binarySearch(materials, arg, String.CASE_INSENSITIVE_ORDER);
+
+ if (i < 0) {
+ // Insertion (start) index
+ i = -1 - i;
+ }
+
+ for ( ; i < size; i++) {
+ String material = materials.get(i);
+ if (StringUtil.startsWithIgnoreCase(material, arg)) {
+ if (completion == null) {
+ completion = new ArrayList<String>();
+ }
+ completion.add(material);
+ } else {
+ break;
+ }
+ }
+
+ if (completion != null) {
+ return completion;
+ }
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/HelpCommand.java b/src/main/java/org/bukkit/command/defaults/HelpCommand.java
index 4c002eb1..db3d92d0 100644
--- a/src/main/java/org/bukkit/command/defaults/HelpCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/HelpCommand.java
@@ -1,7 +1,15 @@
package org.bukkit.command.defaults;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.Validate;
import org.apache.commons.lang.math.NumberUtils;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@@ -13,7 +21,7 @@ import org.bukkit.help.HelpTopicComparator;
import org.bukkit.help.IndexHelpTopic;
import org.bukkit.util.ChatPaginator;
-import java.util.*;
+import com.google.common.collect.ImmutableList;
public class HelpCommand extends VanillaCommand {
public HelpCommand() {
@@ -106,6 +114,27 @@ public class HelpCommand extends VanillaCommand {
return input.equalsIgnoreCase("help") || input.equalsIgnoreCase("?");
}
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ List<String> matchedTopics = new ArrayList<String>();
+ String searchString = args[0];
+ for (HelpTopic topic : Bukkit.getServer().getHelpMap().getHelpTopics()) {
+ String trimmedTopic = topic.getName().startsWith("/") ? topic.getName().substring(1) : topic.getName();
+
+ if (trimmedTopic.startsWith(searchString)) {
+ matchedTopics.add(trimmedTopic);
+ }
+ }
+ return matchedTopics;
+ }
+ return ImmutableList.of();
+ }
+
protected HelpTopic findPossibleMatches(String searchString) {
int maxDistance = (searchString.length() / 5) + 3;
Set<HelpTopic> possibleMatches = new TreeSet<HelpTopic>(HelpTopicComparator.helpTopicComparatorInstance());
diff --git a/src/main/java/org/bukkit/command/defaults/KickCommand.java b/src/main/java/org/bukkit/command/defaults/KickCommand.java
index 1f747d8c..7b890b1a 100644
--- a/src/main/java/org/bukkit/command/defaults/KickCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/KickCommand.java
@@ -1,11 +1,16 @@
package org.bukkit.command.defaults;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import com.google.common.collect.ImmutableList;
+
public class KickCommand extends VanillaCommand {
public KickCommand() {
super("kick");
@@ -44,4 +49,16 @@ public class KickCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("kick");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length >= 1) {
+ return super.tabComplete(sender, alias, args);
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/KillCommand.java b/src/main/java/org/bukkit/command/defaults/KillCommand.java
index d3049f71..84f783f2 100644
--- a/src/main/java/org/bukkit/command/defaults/KillCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/KillCommand.java
@@ -1,10 +1,15 @@
package org.bukkit.command.defaults;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageEvent;
+import com.google.common.collect.ImmutableList;
+
public class KillCommand extends VanillaCommand {
public KillCommand() {
super("kill");
@@ -38,4 +43,13 @@ public class KillCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("kill");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/ListCommand.java b/src/main/java/org/bukkit/command/defaults/ListCommand.java
index 489edd28..e38ae806 100644
--- a/src/main/java/org/bukkit/command/defaults/ListCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/ListCommand.java
@@ -1,9 +1,14 @@
package org.bukkit.command.defaults;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import com.google.common.collect.ImmutableList;
+
public class ListCommand extends VanillaCommand {
public ListCommand() {
super("list");
@@ -41,4 +46,13 @@ public class ListCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("list");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/OpCommand.java b/src/main/java/org/bukkit/command/defaults/OpCommand.java
index 4774c7e3..d7874bcf 100644
--- a/src/main/java/org/bukkit/command/defaults/OpCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/OpCommand.java
@@ -1,10 +1,19 @@
package org.bukkit.command.defaults;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.util.StringUtil;
+
+import com.google.common.collect.ImmutableList;
public class OpCommand extends VanillaCommand {
public OpCommand() {
@@ -33,4 +42,39 @@ public class OpCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("op");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ if (!(sender instanceof Player)) {
+ return ImmutableList.of();
+ }
+
+ String lastWord = args[0];
+ if (lastWord.length() == 0) {
+ return ImmutableList.of();
+ }
+
+ Player senderPlayer = (Player) sender;
+
+ ArrayList<String> matchedPlayers = new ArrayList<String>();
+ for (Player player : sender.getServer().getOnlinePlayers()) {
+ String name = player.getName();
+ if (!senderPlayer.canSee(player) || player.isOp()) {
+ continue;
+ }
+ if (StringUtil.startsWithIgnoreCase(name, lastWord)) {
+ matchedPlayers.add(name);
+ }
+ }
+
+ Collections.sort(matchedPlayers, String.CASE_INSENSITIVE_ORDER);
+ return matchedPlayers;
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/PardonCommand.java b/src/main/java/org/bukkit/command/defaults/PardonCommand.java
index 29da200c..a737ff09 100644
--- a/src/main/java/org/bukkit/command/defaults/PardonCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/PardonCommand.java
@@ -1,9 +1,17 @@
package org.bukkit.command.defaults;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
+import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
+import org.bukkit.util.StringUtil;
+
+import com.google.common.collect.ImmutableList;
public class PardonCommand extends VanillaCommand {
public PardonCommand() {
@@ -30,4 +38,23 @@ public class PardonCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("pardon");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ List<String> completions = new ArrayList<String>();
+ for (OfflinePlayer player : Bukkit.getBannedPlayers()) {
+ String name = player.getName();
+ if (StringUtil.startsWithIgnoreCase(name, args[0])) {
+ completions.add(name);
+ }
+ }
+ return completions;
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/PardonIpCommand.java b/src/main/java/org/bukkit/command/defaults/PardonIpCommand.java
index d9742110..4571eeb9 100644
--- a/src/main/java/org/bukkit/command/defaults/PardonIpCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/PardonIpCommand.java
@@ -1,9 +1,16 @@
package org.bukkit.command.defaults;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
+import org.bukkit.util.StringUtil;
+
+import com.google.common.collect.ImmutableList;
public class PardonIpCommand extends VanillaCommand {
public PardonIpCommand() {
@@ -35,4 +42,16 @@ public class PardonIpCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("pardon-ip");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ return StringUtil.copyPartialMatches(args[0], Bukkit.getIPBans(), new ArrayList<String>());
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java
index 8cb45cce..b888da13 100644
--- a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java
@@ -1,8 +1,9 @@
package org.bukkit.command.defaults;
import java.util.Arrays;
-import org.bukkit.ChatColor;
+
import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
diff --git a/src/main/java/org/bukkit/command/defaults/ReloadCommand.java b/src/main/java/org/bukkit/command/defaults/ReloadCommand.java
index 9b090edc..7f820b3b 100644
--- a/src/main/java/org/bukkit/command/defaults/ReloadCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/ReloadCommand.java
@@ -1,8 +1,9 @@
package org.bukkit.command.defaults;
import java.util.Arrays;
-import org.bukkit.ChatColor;
+
import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
public class ReloadCommand extends BukkitCommand {
diff --git a/src/main/java/org/bukkit/command/defaults/SaveCommand.java b/src/main/java/org/bukkit/command/defaults/SaveCommand.java
index 08d8edf9..77839c1c 100644
--- a/src/main/java/org/bukkit/command/defaults/SaveCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/SaveCommand.java
@@ -1,10 +1,15 @@
package org.bukkit.command.defaults;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
+import com.google.common.collect.ImmutableList;
+
public class SaveCommand extends VanillaCommand {
public SaveCommand() {
super("save-all");
@@ -34,4 +39,13 @@ public class SaveCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("save-all");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/SaveOffCommand.java b/src/main/java/org/bukkit/command/defaults/SaveOffCommand.java
index d46cdd36..c081e5e1 100644
--- a/src/main/java/org/bukkit/command/defaults/SaveOffCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/SaveOffCommand.java
@@ -1,10 +1,15 @@
package org.bukkit.command.defaults;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
+import com.google.common.collect.ImmutableList;
+
public class SaveOffCommand extends VanillaCommand {
public SaveOffCommand() {
super("save-off");
@@ -29,4 +34,13 @@ public class SaveOffCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("save-off");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/SaveOnCommand.java b/src/main/java/org/bukkit/command/defaults/SaveOnCommand.java
index 4c1bfec6..d0561c36 100644
--- a/src/main/java/org/bukkit/command/defaults/SaveOnCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/SaveOnCommand.java
@@ -1,10 +1,15 @@
package org.bukkit.command.defaults;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
+import com.google.common.collect.ImmutableList;
+
public class SaveOnCommand extends VanillaCommand {
public SaveOnCommand() {
super("save-on");
@@ -29,4 +34,13 @@ public class SaveOnCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("save-on");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/SayCommand.java b/src/main/java/org/bukkit/command/defaults/SayCommand.java
index 44dc7ae0..651b60c0 100644
--- a/src/main/java/org/bukkit/command/defaults/SayCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/SayCommand.java
@@ -1,10 +1,15 @@
package org.bukkit.command.defaults;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import com.google.common.collect.ImmutableList;
+
public class SayCommand extends VanillaCommand {
public SayCommand() {
super("say");
@@ -43,4 +48,15 @@ public class SayCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("say");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+
+ if (args.length >= 1) {
+ return super.tabComplete(sender, alias, args);
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/SeedCommand.java b/src/main/java/org/bukkit/command/defaults/SeedCommand.java
index 4fac2678..b64fd405 100644
--- a/src/main/java/org/bukkit/command/defaults/SeedCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/SeedCommand.java
@@ -1,9 +1,14 @@
package org.bukkit.command.defaults;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import com.google.common.collect.ImmutableList;
+
public class SeedCommand extends VanillaCommand {
public SeedCommand() {
super("seed");
@@ -24,4 +29,13 @@ public class SeedCommand extends VanillaCommand {
sender.sendMessage("Seed: " + seed);
return true;
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/StopCommand.java b/src/main/java/org/bukkit/command/defaults/StopCommand.java
index 2b8ee082..c6a470b6 100644
--- a/src/main/java/org/bukkit/command/defaults/StopCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/StopCommand.java
@@ -1,9 +1,14 @@
package org.bukkit.command.defaults;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
+import com.google.common.collect.ImmutableList;
+
public class StopCommand extends VanillaCommand {
public StopCommand() {
super("stop");
@@ -26,4 +31,13 @@ public class StopCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("stop");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/TeleportCommand.java b/src/main/java/org/bukkit/command/defaults/TeleportCommand.java
index ad2a5527..55be9da3 100644
--- a/src/main/java/org/bukkit/command/defaults/TeleportCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/TeleportCommand.java
@@ -1,5 +1,8 @@
package org.bukkit.command.defaults;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
@@ -8,6 +11,8 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
+import com.google.common.collect.ImmutableList;
+
public class TeleportCommand extends VanillaCommand {
public TeleportCommand() {
super("tp");
@@ -66,4 +71,16 @@ public class TeleportCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("tp");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1 || args.length == 2) {
+ return super.tabComplete(sender, alias, args);
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/TimeCommand.java b/src/main/java/org/bukkit/command/defaults/TimeCommand.java
index 9866877d..011d32db 100644
--- a/src/main/java/org/bukkit/command/defaults/TimeCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/TimeCommand.java
@@ -1,12 +1,22 @@
package org.bukkit.command.defaults;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
+import org.bukkit.util.StringUtil;
+
+import com.google.common.collect.ImmutableList;
public class TimeCommand extends VanillaCommand {
+ private static final List<String> TABCOMPLETE_ADD_SET = ImmutableList.of("add", "set");
+ private static final List<String> TABCOMPLETE_DAY_NIGHT = ImmutableList.of("day", "night");
+
public TimeCommand() {
super("time");
this.description = "Changes the time on each world";
@@ -66,4 +76,18 @@ public class TimeCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("time");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ return StringUtil.copyPartialMatches(args[0], TABCOMPLETE_ADD_SET, new ArrayList<String>(TABCOMPLETE_ADD_SET.size()));
+ } else if (args.length == 2 && args[0].equalsIgnoreCase("set")) {
+ return StringUtil.copyPartialMatches(args[1], TABCOMPLETE_DAY_NIGHT, new ArrayList<String>(TABCOMPLETE_DAY_NIGHT.size()));
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java b/src/main/java/org/bukkit/command/defaults/TimingsCommand.java
index b9c8fc66..29ebbe05 100644
--- a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/TimingsCommand.java
@@ -3,18 +3,25 @@ package org.bukkit.command.defaults;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
-import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredListener;
import org.bukkit.plugin.TimedRegisteredListener;
+import org.bukkit.util.StringUtil;
+
+import com.google.common.collect.ImmutableList;
public class TimingsCommand extends BukkitCommand {
+ private static final List<String> TIMINGS_SUBCOMMANDS = ImmutableList.of("merged", "reset", "separate");
+
public TimingsCommand(String name) {
super(name);
this.description = "Records timings for all plugin events";
@@ -99,4 +106,16 @@ public class TimingsCommand extends BukkitCommand {
}
return true;
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ return StringUtil.copyPartialMatches(args[0], TIMINGS_SUBCOMMANDS, new ArrayList<String>(TIMINGS_SUBCOMMANDS.size()));
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/ToggleDownfallCommand.java b/src/main/java/org/bukkit/command/defaults/ToggleDownfallCommand.java
index e81710e1..08ed667f 100644
--- a/src/main/java/org/bukkit/command/defaults/ToggleDownfallCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/ToggleDownfallCommand.java
@@ -1,5 +1,8 @@
package org.bukkit.command.defaults;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.World;
@@ -7,6 +10,8 @@ import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import com.google.common.collect.ImmutableList;
+
public class ToggleDownfallCommand extends VanillaCommand {
public ToggleDownfallCommand() {
super("toggledownfall");
@@ -44,4 +49,13 @@ public class ToggleDownfallCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("toggledownfall");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/VanillaCommand.java b/src/main/java/org/bukkit/command/defaults/VanillaCommand.java
index bf6df750..1fdcc81e 100644
--- a/src/main/java/org/bukkit/command/defaults/VanillaCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/VanillaCommand.java
@@ -1,13 +1,11 @@
package org.bukkit.command.defaults;
-import java.util.ArrayList;
import java.util.List;
+
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
public abstract class VanillaCommand extends Command {
- static final List<String> EMPTY_LIST = new ArrayList(0);
-
protected VanillaCommand(String name) {
super(name);
}
diff --git a/src/main/java/org/bukkit/command/defaults/VersionCommand.java b/src/main/java/org/bukkit/command/defaults/VersionCommand.java
index 4d3ba15b..902f9d15 100644
--- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java
@@ -1,13 +1,18 @@
package org.bukkit.command.defaults;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import org.bukkit.ChatColor;
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
+import org.bukkit.util.StringUtil;
+
+import com.google.common.collect.ImmutableList;
public class VersionCommand extends BukkitCommand {
public VersionCommand(String name) {
@@ -102,4 +107,23 @@ public class VersionCommand extends BukkitCommand {
return result.toString();
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ List<String> completions = new ArrayList<String>();
+ String toComplete = args[0].toLowerCase();
+ for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
+ if (StringUtil.startsWithIgnoreCase(plugin.getName(), toComplete)) {
+ completions.add(plugin.getName());
+ }
+ }
+ return completions;
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java b/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java
index d0fd8578..70786d11 100644
--- a/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java
@@ -1,12 +1,21 @@
package org.bukkit.command.defaults;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
+import org.bukkit.util.StringUtil;
+
+import com.google.common.collect.ImmutableList;
public class WhitelistCommand extends VanillaCommand {
+ private static final List<String> WHITELIST_SUBCOMMANDS = ImmutableList.of("add", "remove", "on", "off", "list", "reload");
+
public WhitelistCommand() {
super("whitelist");
this.description = "Prevents the specified player from using this server";
@@ -88,4 +97,36 @@ public class WhitelistCommand extends VanillaCommand {
public boolean matches(String input) {
return input.equalsIgnoreCase("whitelist");
}
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ if (args.length == 1) {
+ return StringUtil.copyPartialMatches(args[0], WHITELIST_SUBCOMMANDS, new ArrayList<String>(WHITELIST_SUBCOMMANDS.size()));
+ } else if (args.length == 2) {
+ if (args[0].equalsIgnoreCase("add")) {
+ List<String> completions = new ArrayList<String>();
+ for (OfflinePlayer player : Bukkit.getOfflinePlayers()) {
+ String name = player.getName();
+ if (StringUtil.startsWithIgnoreCase(name, args[1]) && !player.isWhitelisted()) {
+ completions.add(name);
+ }
+ }
+ return completions;
+ } else if (args[0].equalsIgnoreCase("remove")) {
+ List<String> completions = new ArrayList<String>();
+ for (OfflinePlayer player : Bukkit.getWhitelistedPlayers()) {
+ String name = player.getName();
+ if (StringUtil.startsWithIgnoreCase(name, args[1])) {
+ completions.add(name);
+ }
+ }
+ return completions;
+ }
+ }
+ return ImmutableList.of();
+ }
}
diff --git a/src/main/java/org/bukkit/plugin/Plugin.java b/src/main/java/org/bukkit/plugin/Plugin.java
index 6b75c3e7..c266114c 100644
--- a/src/main/java/org/bukkit/plugin/Plugin.java
+++ b/src/main/java/org/bukkit/plugin/Plugin.java
@@ -5,7 +5,7 @@ import java.io.InputStream;
import java.util.logging.Logger;
import org.bukkit.Server;
-import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.TabExecutor;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.generator.ChunkGenerator;
@@ -16,7 +16,7 @@ import com.avaje.ebean.EbeanServer;
* <p />
* The use of {@link PluginBase} is recommended for actual Implementation
*/
-public interface Plugin extends CommandExecutor {
+public interface Plugin extends TabExecutor {
/**
* Returns the folder that the plugin data's files are located in. The
* folder may not yet exist.
diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
index cdc6e751..d4835547 100644
--- a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
+++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
@@ -299,6 +299,13 @@ public abstract class JavaPlugin extends PluginBase {
}
/**
+ * {@inheritDoc}
+ */
+ public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
+ return null;
+ }
+
+ /**
* Gets the command with the given name, specific to this plugin
*
* @param name Name or alias of the command
diff --git a/src/main/java/org/bukkit/util/StringUtil.java b/src/main/java/org/bukkit/util/StringUtil.java
new file mode 100644
index 00000000..12bc58d4
--- /dev/null
+++ b/src/main/java/org/bukkit/util/StringUtil.java
@@ -0,0 +1,49 @@
+package org.bukkit.util;
+
+import java.util.Collection;
+import org.apache.commons.lang.Validate;
+
+public class StringUtil {
+
+ /**
+ * Copies all elements from the iterable collection of originals to the collection provided.
+ *
+ * @param token String to search for
+ * @param originals An iterable collection of strings to filter.
+ * @param collection The collection to add matches to
+ * @return the collection provided that would have the elements copied into
+ * @throws UnsupportedOperationException if the collection is immutable and originals contains a string which starts with the specified search string.
+ * @throws IllegalArgumentException if any parameter is is null
+ * @throws IllegalArgumentException if originals contains a null element. <b>Note: the collection may be modified before this is thrown</b>
+ */
+ public static <T extends Collection<String>> T copyPartialMatches(final String token, final Iterable<String> originals, final T collection) throws UnsupportedOperationException, IllegalArgumentException {
+ Validate.notNull(token, "Search token cannot be null");
+ Validate.notNull(collection, "Collection cannot be null");
+ Validate.notNull(originals, "Originals cannot be null");
+
+ for (String string : originals) {
+ if (startsWithIgnoreCase(string, token)) {
+ collection.add(string);
+ }
+ }
+
+ return collection;
+ }
+
+ /**
+ * This method uses a substring to check case-insensitive equality. This means the internal array does not need to be copied like a toLowerCase() call would.
+ *
+ * @param string String to check
+ * @param prefix Prefix of string to compare
+ * @return true if provided string starts with, ignoring case, the prefix provided
+ * @throws NullPointerException if prefix is null
+ * @throws IllegalArgumentException if string is null
+ */
+ public static boolean startsWithIgnoreCase(final String string, final String prefix) throws IllegalArgumentException, NullPointerException {
+ Validate.notNull(string, "Cannot check a null string for a match");
+ if (string.length() < prefix.length()) {
+ return false;
+ }
+ return string.substring(0, prefix.length()).equalsIgnoreCase(prefix);
+ }
+}
diff --git a/src/test/java/org/bukkit/plugin/TestPlugin.java b/src/test/java/org/bukkit/plugin/TestPlugin.java
index a435771a..7e098925 100644
--- a/src/test/java/org/bukkit/plugin/TestPlugin.java
+++ b/src/test/java/org/bukkit/plugin/TestPlugin.java
@@ -2,6 +2,7 @@ package org.bukkit.plugin;
import java.io.File;
import java.io.InputStream;
+import java.util.List;
import org.bukkit.Server;
import org.bukkit.command.Command;
@@ -103,4 +104,8 @@ public class TestPlugin extends PluginBase {
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
throw new UnsupportedOperationException("Not supported.");
}
+
+ public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
}