diff --git a/Essentials/src/com/earth2me/essentials/Essentials.java b/Essentials/src/com/earth2me/essentials/Essentials.java index 69bb772d2..7987e4e3c 100644 --- a/Essentials/src/com/earth2me/essentials/Essentials.java +++ b/Essentials/src/com/earth2me/essentials/Essentials.java @@ -344,21 +344,79 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { @Override public List onTabComplete(CommandSender sender, Command command, String commandLabel, String[] args) { - // Allow plugins to override the command via onCommand + return onTabCompleteEssentials(sender, command, commandLabel, args, Essentials.class.getClassLoader(), + "com.earth2me.essentials.commands.Command", "essentials.", null); + } + + @Override + public List onTabCompleteEssentials(final CommandSender cSender, final Command command, final String commandLabel, final String[] args, + final ClassLoader classLoader, final String commandPath, final String permissionPrefix, + final IEssentialsModule module) { if (!getSettings().isCommandOverridden(command.getName()) && (!commandLabel.startsWith("e") || commandLabel.equalsIgnoreCase(command.getName()))) { final PluginCommand pc = alternativeCommandsHandler.getAlternative(commandLabel); if (pc != null) { try { TabCompleter completer = pc.getTabCompleter(); if (completer != null) { - return completer.onTabComplete(sender, command, commandLabel, args); + return completer.onTabComplete(cSender, command, commandLabel, args); } } catch (final Exception ex) { Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); } } } - return null; + + try { + // Note: The tab completer is always a player, even when tab-completing in a command block + User user = null; + if (cSender instanceof Player) { + user = getUser((Player) cSender); + } + + CommandSource sender = new CommandSource(cSender); + + // Check for disabled commands + if (getSettings().isCommandDisabled(commandLabel)) { + return Collections.emptyList(); + } + + IEssentialsCommand cmd; + try { + cmd = (IEssentialsCommand) classLoader.loadClass(commandPath + command.getName()).newInstance(); + cmd.setEssentials(this); + cmd.setEssentialsModule(module); + } catch (Exception ex) { + sender.sendMessage(tl("commandNotLoaded", commandLabel)); + LOGGER.log(Level.SEVERE, tl("commandNotLoaded", commandLabel), ex); + return Collections.emptyList(); + } + + // Check authorization + if (user != null && !user.isAuthorized(cmd, permissionPrefix)) { + return Collections.emptyList(); + } + + if (user != null && user.isJailed() && !user.isAuthorized(cmd, "essentials.jail.allow.")) { + return Collections.emptyList(); + } + + // Run the command + try { + if (user == null) { + return cmd.tabComplete(getServer(), sender, commandLabel, command, args); + } else { + return cmd.tabComplete(getServer(), user, commandLabel, command, args); + } + } catch (Exception ex) { + showError(sender, ex, commandLabel); + // Tab completion shouldn't fail + LOGGER.log(Level.SEVERE, tl("commandFailed", commandLabel), ex); + return Collections.emptyList(); + } + } catch (Throwable ex) { + LOGGER.log(Level.SEVERE, tl("commandFailed", commandLabel), ex); + return Collections.emptyList(); + } } @Override diff --git a/Essentials/src/com/earth2me/essentials/IEssentials.java b/Essentials/src/com/earth2me/essentials/IEssentials.java index 5da38fd50..f1ea0ca3a 100644 --- a/Essentials/src/com/earth2me/essentials/IEssentials.java +++ b/Essentials/src/com/earth2me/essentials/IEssentials.java @@ -25,6 +25,8 @@ public interface IEssentials extends Plugin { void reload(); + List onTabCompleteEssentials(CommandSender sender, Command command, String commandLabel, String[] args, ClassLoader classLoader, String commandPath, String permissionPrefix, IEssentialsModule module); + boolean onCommandEssentials(CommandSender sender, Command command, String commandLabel, String[] args, ClassLoader classLoader, String commandPath, String permissionPrefix, IEssentialsModule module); @Deprecated diff --git a/Essentials/src/com/earth2me/essentials/commands/EssentialsCommand.java b/Essentials/src/com/earth2me/essentials/commands/EssentialsCommand.java index 048c51a2f..d5338b861 100644 --- a/Essentials/src/com/earth2me/essentials/commands/EssentialsCommand.java +++ b/Essentials/src/com/earth2me/essentials/commands/EssentialsCommand.java @@ -5,11 +5,15 @@ import com.earth2me.essentials.IEssentialsModule; import com.earth2me.essentials.Trade; import com.earth2me.essentials.User; import com.earth2me.essentials.utils.FormatUtil; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; import net.ess3.api.IEssentials; import org.bukkit.Server; import org.bukkit.command.Command; import org.bukkit.entity.Player; +import org.bukkit.util.StringUtil; +import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.UUID; @@ -160,6 +164,43 @@ public abstract class EssentialsCommand implements IEssentialsCommand { throw new Exception(tl("onlyPlayers", commandLabel)); } + @Override + public final List tabComplete(final Server server, final User user, final String commandLabel, final Command cmd, final String[] args) { + if (args.length == 0) { + // Shouldn't happen, but bail out early if it does so that args[0] can always be used + return Collections.emptyList(); + } + List options = getTabCompleteOptions(server, user, commandLabel, args); + if (options == null) { + return null; + } + return StringUtil.copyPartialMatches(args[args.length - 1], options, Lists.newArrayList()); + } + + // Doesn't need to do any starts-with checks + protected List getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) { + return getTabCompleteOptions(server, user.getSource(), commandLabel, args); + } + + @Override + public final List tabComplete(final Server server, final CommandSource sender, final String commandLabel, final Command cmd, final String[] args) { + if (args.length == 0) { + // Shouldn't happen, but bail out early if it does so that args[0] can always be used + return Collections.emptyList(); + } + List options = getTabCompleteOptions(server, sender, commandLabel, args); + if (options == null) { + return null; + } + return StringUtil.copyPartialMatches(args[args.length - 1], options, Lists.newArrayList()); + } + + // Doesn't need to do any starts-with checks + protected List getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) { + // No tab completion results + return Collections.emptyList(); + } + public static String getFinalArg(final String[] args, final int start) { final StringBuilder bldr = new StringBuilder(); for (int i = start; i < args.length; i++) { @@ -194,4 +235,41 @@ public abstract class EssentialsCommand implements IEssentialsCommand { return interactor.getBase().canSee(interactee.getBase()); } + + /** + * Gets a list of all player names that can be seen with by the given CommandSource, + * for tab completion. + */ + protected List getPlayers(final Server server, final CommandSource interactor) { + List players = Lists.newArrayList(); + for (User user : ess.getOnlineUsers()) { + if (canInteractWith(interactor, user)) { + players.add(user.getName()); + } + } + return players; + } + + /** + * Gets a list of all player names that can be seen with by the given User, + * for tab completion. + */ + protected List getPlayers(final Server server, final User interactor) { + List players = Lists.newArrayList(); + for (User user : ess.getOnlineUsers()) { + if (canInteractWith(interactor, user)) { + players.add(user.getName()); + } + } + return players; + } + + /** + * Common time durations (in seconds), for use in tab completion. + */ + protected static final List COMMON_DURATIONS = ImmutableList.of("1", "60", "600", "3600", "86400"); + /** + * Common date diffs, for use in tab completion + */ + protected static final List COMMON_DATE_DIFFS = ImmutableList.of("1m", "15m", "1h", "3h", "12h", "1d", "1w", "1mo", "1y"); } diff --git a/Essentials/src/com/earth2me/essentials/commands/EssentialsLoopCommand.java b/Essentials/src/com/earth2me/essentials/commands/EssentialsLoopCommand.java index ed3444149..fffe3b86e 100644 --- a/Essentials/src/com/earth2me/essentials/commands/EssentialsLoopCommand.java +++ b/Essentials/src/com/earth2me/essentials/commands/EssentialsLoopCommand.java @@ -108,4 +108,20 @@ public abstract class EssentialsLoopCommand extends EssentialsCommand { } protected abstract void updatePlayer(Server server, CommandSource sender, User user, String[] args) throws NotEnoughArgumentsException, PlayerExemptException, ChargeException, MaxMoneyException; + + @Override + protected List getPlayers(final Server server, final CommandSource interactor) { + List players = super.getPlayers(server, interactor); + players.add("**"); + players.add("*"); + return players; + } + + @Override + protected List getPlayers(final Server server, final User interactor) { + List players = super.getPlayers(server, interactor); + players.add("**"); + players.add("*"); + return players; + } } diff --git a/Essentials/src/com/earth2me/essentials/commands/EssentialsToggleCommand.java b/Essentials/src/com/earth2me/essentials/commands/EssentialsToggleCommand.java index 22b6ee95e..c0486ac3e 100644 --- a/Essentials/src/com/earth2me/essentials/commands/EssentialsToggleCommand.java +++ b/Essentials/src/com/earth2me/essentials/commands/EssentialsToggleCommand.java @@ -2,9 +2,11 @@ package com.earth2me.essentials.commands; import com.earth2me.essentials.CommandSource; import com.earth2me.essentials.User; +import com.google.common.collect.Lists; import org.bukkit.Server; import org.bukkit.entity.Player; +import java.util.Collections; import java.util.List; @@ -72,4 +74,30 @@ public abstract class EssentialsToggleCommand extends EssentialsCommand { // Make sure when implementing this method that all 3 Boolean states are handled, 'null' should toggle the existing state. abstract void togglePlayer(CommandSource sender, User user, Boolean enabled) throws NotEnoughArgumentsException; + + @Override + protected List getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) { + if (args.length == 1) { + if (user.isAuthorized(othersPermission)) { + return getPlayers(server, user); + } else { + return Lists.newArrayList("enable", "disable"); + } + } else if (args.length == 2 && user.isAuthorized(othersPermission)) { + return Lists.newArrayList("enable", "disable"); + } else { + return Collections.emptyList(); + } + } + + @Override + protected List getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) { + if (args.length == 1) { + return getPlayers(server, sender); + } else if (args.length == 2) { + return Lists.newArrayList("enable", "disable"); + } else { + return Collections.emptyList(); + } + } } diff --git a/Essentials/src/com/earth2me/essentials/commands/IEssentialsCommand.java b/Essentials/src/com/earth2me/essentials/commands/IEssentialsCommand.java index 247adf6da..07cb08abe 100644 --- a/Essentials/src/com/earth2me/essentials/commands/IEssentialsCommand.java +++ b/Essentials/src/com/earth2me/essentials/commands/IEssentialsCommand.java @@ -6,6 +6,7 @@ import com.earth2me.essentials.User; import net.ess3.api.IEssentials; import org.bukkit.Server; import org.bukkit.command.Command; +import java.util.List; public interface IEssentialsCommand { @@ -15,6 +16,10 @@ public interface IEssentialsCommand { void run(Server server, CommandSource sender, String commandLabel, Command cmd, String[] args) throws Exception; + List tabComplete(Server server, User user, String commandLabel, Command cmd, String[] args); + + List tabComplete(Server server, CommandSource sender, String commandLabel, Command cmd, String[] args); + void setEssentials(IEssentials ess); void setEssentialsModule(IEssentialsModule module);