diff --git a/docs/acf-bukkit/co/aikar/commands/BukkitCommandCompletions.html b/docs/acf-bukkit/co/aikar/commands/BukkitCommandCompletions.html index 3df24455..870e2f33 100644 --- a/docs/acf-bukkit/co/aikar/commands/BukkitCommandCompletions.html +++ b/docs/acf-bukkit/co/aikar/commands/BukkitCommandCompletions.html @@ -107,7 +107,7 @@


  • -
    public class BukkitCommandCompletions
    +
    public class BukkitCommandCompletions
     extends co.aikar.commands.CommandCompletions<BukkitCommandCompletionContext>
  • @@ -158,7 +158,7 @@ extends co.aikar.commands.CommandCompletions<
  • @@ -187,7 +187,7 @@ extends co.aikar.commands.CommandCompletions<
  • BukkitCommandCompletions

    -
    public BukkitCommandCompletions(BukkitCommandManager manager)
    +
    public BukkitCommandCompletions(BukkitCommandManager manager)
  • diff --git a/docs/acf-bukkit/co/aikar/commands/BukkitCommandExecutionContext.html b/docs/acf-bukkit/co/aikar/commands/BukkitCommandExecutionContext.html index cea2f056..3da476ff 100644 --- a/docs/acf-bukkit/co/aikar/commands/BukkitCommandExecutionContext.html +++ b/docs/acf-bukkit/co/aikar/commands/BukkitCommandExecutionContext.html @@ -164,7 +164,7 @@ extends co.aikar.commands.CommandExecutionContext<
  • diff --git a/docs/acf-bukkit/co/aikar/commands/BukkitCommandManager.html b/docs/acf-bukkit/co/aikar/commands/BukkitCommandManager.html index dbec6102..fdd547d1 100644 --- a/docs/acf-bukkit/co/aikar/commands/BukkitCommandManager.html +++ b/docs/acf-bukkit/co/aikar/commands/BukkitCommandManager.html @@ -113,7 +113,7 @@ var activeTableTab = "activeTableTab";


  • -
    public class BukkitCommandManager
    +
    public class BukkitCommandManager
     extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,BukkitCommandIssuer,org.bukkit.ChatColor,BukkitMessageFormatter,BukkitCommandExecutionContext,BukkitConditionContext>
  • @@ -336,7 +336,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,

    Methods inherited from class co.aikar.commands.CommandManager

    -addSupportedLanguage, enableUnstableAPI, formatMessage, generateCommandHelp, generateCommandHelp, generateCommandHelp, generateCommandHelp, getCommandConditions, getCommandReplacements, getCurrentCommandIssuer, getCurrentCommandManager, getCurrentCommandOperationContext, getDefaultExceptionHandler, getDefaultFormatter, getDefaultHelpPerPage, getFormat, getHelpFormatter, getIssuerLocale, getRootCommand, getSupportedLanguages, hasPermission, isLoggingUnhandledExceptions, log, notifyLocaleChange, obtainRootCommand, onLocaleChange, registerDependency, registerDependency, sendMessage, sendMessage, setDefaultExceptionHandler, setDefaultExceptionHandler, setDefaultFormatter, setDefaultHelpPerPage, setFormat, setFormat, setFormat, setHelpFormatter, setIssuerLocale, usePerIssuerLocale, usingPerIssuerLocale +addSupportedLanguage, enableUnstableAPI, formatMessage, generateCommandHelp, generateCommandHelp, generateCommandHelp, generateCommandHelp, getCommandConditions, getCommandReplacements, getCurrentCommandIssuer, getCurrentCommandManager, getCurrentCommandOperationContext, getDefaultExceptionHandler, getDefaultFormatter, getDefaultHelpPerPage, getFormat, getHelpFormatter, getIssuerLocale, getRootCommand, getSupportedLanguages, hasPermission, hasPermission, isLoggingUnhandledExceptions, log, notifyLocaleChange, obtainRootCommand, onLocaleChange, registerDependency, registerDependency, sendMessage, sendMessage, setDefaultExceptionHandler, setDefaultExceptionHandler, setDefaultFormatter, setDefaultHelpPerPage, setFormat, setFormat, setFormat, setHelpFormatter, setIssuerLocale, usePerIssuerLocale, usingPerIssuerLocale @@ -374,7 +374,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • mcMinorVersion

    -
    public final Integer mcMinorVersion
    +
    public final Integer mcMinorVersion
  • @@ -383,7 +383,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • mcPatchVersion

    -
    public final Integer mcPatchVersion
    +
    public final Integer mcPatchVersion
  • @@ -392,7 +392,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • knownCommands

    -
    protected Map<String,org.bukkit.command.Command> knownCommands
    +
    protected Map<String,org.bukkit.command.Command> knownCommands
  • @@ -401,7 +401,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • registeredCommands

    -
    protected Map<String,BukkitRootCommand> registeredCommands
    +
    protected Map<String,BukkitRootCommand> registeredCommands
  • @@ -410,7 +410,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • contexts

    -
    protected BukkitCommandContexts contexts
    +
    protected BukkitCommandContexts contexts
  • @@ -419,7 +419,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • completions

    -
    protected BukkitCommandCompletions completions
    +
    protected BukkitCommandCompletions completions
  • @@ -428,7 +428,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • locales

    -
    protected BukkitLocales locales
    +
    protected BukkitLocales locales
  • @@ -437,7 +437,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • autoDetectFromClient

    -
    protected boolean autoDetectFromClient
    +
    protected boolean autoDetectFromClient
  • @@ -454,7 +454,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • BukkitCommandManager

    -
    public BukkitCommandManager(org.bukkit.plugin.Plugin plugin)
    +
    public BukkitCommandManager(org.bukkit.plugin.Plugin plugin)
  • @@ -471,7 +471,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • getPlugin

    -
    public org.bukkit.plugin.Plugin getPlugin()
    +
    public org.bukkit.plugin.Plugin getPlugin()
  • @@ -480,7 +480,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • isCommandIssuer

    -
    public boolean isCommandIssuer(Class<?> type)
    +
    public boolean isCommandIssuer(Class<?> type)
    Specified by:
    isCommandIssuer in class co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,BukkitCommandIssuer,org.bukkit.ChatColor,BukkitMessageFormatter,BukkitCommandExecutionContext,BukkitConditionContext>
    @@ -493,7 +493,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • getCommandContexts

    -
    public co.aikar.commands.CommandContexts<BukkitCommandExecutionContextgetCommandContexts()
    +
    public co.aikar.commands.CommandContexts<BukkitCommandExecutionContextgetCommandContexts()
    Specified by:
    getCommandContexts in class co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,BukkitCommandIssuer,org.bukkit.ChatColor,BukkitMessageFormatter,BukkitCommandExecutionContext,BukkitConditionContext>
    @@ -506,7 +506,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • getCommandCompletions

    -
    public co.aikar.commands.CommandCompletions<BukkitCommandCompletionContextgetCommandCompletions()
    +
    public co.aikar.commands.CommandCompletions<BukkitCommandCompletionContextgetCommandCompletions()
    Specified by:
    getCommandCompletions in class co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,BukkitCommandIssuer,org.bukkit.ChatColor,BukkitMessageFormatter,BukkitCommandExecutionContext,BukkitConditionContext>
    @@ -519,7 +519,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • getLocales

    -
    public BukkitLocales getLocales()
    +
    public BukkitLocales getLocales()
    Specified by:
    getLocales in class co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,BukkitCommandIssuer,org.bukkit.ChatColor,BukkitMessageFormatter,BukkitCommandExecutionContext,BukkitConditionContext>
    @@ -532,7 +532,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • hasRegisteredCommands

    -
    public boolean hasRegisteredCommands()
    +
    public boolean hasRegisteredCommands()
    Specified by:
    hasRegisteredCommands in class co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,BukkitCommandIssuer,org.bukkit.ChatColor,BukkitMessageFormatter,BukkitCommandExecutionContext,BukkitConditionContext>
    @@ -545,7 +545,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • registerCommand

    -
    public void registerCommand(co.aikar.commands.BaseCommand command,
    +
    public void registerCommand(co.aikar.commands.BaseCommand command,
                                 boolean force)
  • @@ -555,7 +555,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • registerCommand

    -
    public void registerCommand(co.aikar.commands.BaseCommand command)
    +
    public void registerCommand(co.aikar.commands.BaseCommand command)
    Specified by:
    registerCommand in class co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,BukkitCommandIssuer,org.bukkit.ChatColor,BukkitMessageFormatter,BukkitCommandExecutionContext,BukkitConditionContext>
    @@ -568,7 +568,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,
  • unregisterCommand

    -
    public void unregisterCommand(co.aikar.commands.BaseCommand command)
    +
    public void unregisterCommand(co.aikar.commands.BaseCommand command)
  • @@ -578,7 +578,7 @@ extends co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,

    unregisterCommand

    @Deprecated
    -public void unregisterCommand(BukkitRootCommand command)
    +public void unregisterCommand(BukkitRootCommand command)
    Deprecated. Use unregisterCommand(BaseCommand) - this will be visibility reduced later.
    Parameters:
    @@ -592,7 +592,7 @@ public void 
  • unregisterCommands

    -
    public void unregisterCommands()
    +
    public void unregisterCommands()
  • @@ -601,7 +601,7 @@ public void 
  • setPlayerLocale

    -
    public Locale setPlayerLocale(org.bukkit.entity.Player player,
    +
    public Locale setPlayerLocale(org.bukkit.entity.Player player,
                                   Locale locale)
  • @@ -611,7 +611,7 @@ public void 
  • getTimings

    -
    public co.aikar.timings.lib.TimingManager getTimings()
    +
    public co.aikar.timings.lib.TimingManager getTimings()
  • @@ -620,7 +620,7 @@ public void 
  • createRootCommand

    -
    public co.aikar.commands.RootCommand createRootCommand(String cmd)
    +
    public co.aikar.commands.RootCommand createRootCommand(String cmd)
    Specified by:
    createRootCommand in class co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,BukkitCommandIssuer,org.bukkit.ChatColor,BukkitMessageFormatter,BukkitCommandExecutionContext,BukkitConditionContext>
    @@ -633,7 +633,7 @@ public void 
  • getRegisteredRootCommands

    -
    public Collection<co.aikar.commands.RootCommand> getRegisteredRootCommands()
    +
    public Collection<co.aikar.commands.RootCommand> getRegisteredRootCommands()
    Specified by:
    getRegisteredRootCommands in class co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,BukkitCommandIssuer,org.bukkit.ChatColor,BukkitMessageFormatter,BukkitCommandExecutionContext,BukkitConditionContext>
    @@ -646,7 +646,7 @@ public void 
  • getCommandIssuer

    -
    public BukkitCommandIssuer getCommandIssuer(Object issuer)
    +
    public BukkitCommandIssuer getCommandIssuer(Object issuer)
    Specified by:
    getCommandIssuer in class co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,BukkitCommandIssuer,org.bukkit.ChatColor,BukkitMessageFormatter,BukkitCommandExecutionContext,BukkitConditionContext>
    @@ -659,7 +659,7 @@ public void 
  • createCommandContext

    -
    public BukkitCommandExecutionContext createCommandContext(co.aikar.commands.RegisteredCommand command,
    +
    public BukkitCommandExecutionContext createCommandContext(co.aikar.commands.RegisteredCommand command,
                                                               co.aikar.commands.CommandParameter parameter,
                                                               co.aikar.commands.CommandIssuer sender,
                                                               List<String> args,
    @@ -677,7 +677,7 @@ public void 
     
  • createCompletionContext

    -
    public BukkitCommandCompletionContext createCompletionContext(co.aikar.commands.RegisteredCommand command,
    +
    public BukkitCommandCompletionContext createCompletionContext(co.aikar.commands.RegisteredCommand command,
                                                                   co.aikar.commands.CommandIssuer sender,
                                                                   String input,
                                                                   String config,
    @@ -694,7 +694,7 @@ public void 
     
  • createRegisteredCommand

    -
    public co.aikar.commands.RegisteredCommand createRegisteredCommand(co.aikar.commands.BaseCommand command,
    +
    public co.aikar.commands.RegisteredCommand createRegisteredCommand(co.aikar.commands.BaseCommand command,
                                                                        String cmdName,
                                                                        Method method,
                                                                        String prefSubCommand)
    @@ -710,7 +710,7 @@ public void 
  • createConditionContext

    -
    public BukkitConditionContext createConditionContext(co.aikar.commands.CommandIssuer issuer,
    +
    public BukkitConditionContext createConditionContext(co.aikar.commands.CommandIssuer issuer,
                                                          String config)
    Overrides:
    @@ -724,7 +724,7 @@ public void 
  • log

    -
    public void log(co.aikar.commands.LogLevel level,
    +
    public void log(co.aikar.commands.LogLevel level,
                     String message,
                     Throwable throwable)
    @@ -739,7 +739,7 @@ public void 
  • usePerIssuerLocale

    -
    public boolean usePerIssuerLocale(boolean usePerIssuerLocale,
    +
    public boolean usePerIssuerLocale(boolean usePerIssuerLocale,
                                       boolean autoDetectFromClient)
  • @@ -749,7 +749,7 @@ public void 
  • getCommandPrefix

    -
    public String getCommandPrefix(co.aikar.commands.CommandIssuer issuer)
    +
    public String getCommandPrefix(co.aikar.commands.CommandIssuer issuer)
    Overrides:
    getCommandPrefix in class co.aikar.commands.CommandManager<org.bukkit.command.CommandSender,BukkitCommandIssuer,org.bukkit.ChatColor,BukkitMessageFormatter,BukkitCommandExecutionContext,BukkitConditionContext>
    @@ -762,7 +762,7 @@ public void 
  • handleUncaughtException

    -
    protected boolean handleUncaughtException(co.aikar.commands.BaseCommand scope,
    +
    protected boolean handleUncaughtException(co.aikar.commands.BaseCommand scope,
                                               co.aikar.commands.RegisteredCommand registeredCommand,
                                               co.aikar.commands.CommandIssuer sender,
                                               List<String> args,
    diff --git a/docs/acf-bukkit/src-html/co/aikar/commands/BukkitCommandCompletions.html b/docs/acf-bukkit/src-html/co/aikar/commands/BukkitCommandCompletions.html
    index 53f4f463..d927f0e7 100644
    --- a/docs/acf-bukkit/src-html/co/aikar/commands/BukkitCommandCompletions.html
    +++ b/docs/acf-bukkit/src-html/co/aikar/commands/BukkitCommandCompletions.html
    @@ -31,72 +31,76 @@
     023
     024package co.aikar.commands;
     025
    -026import org.apache.commons.lang.Validate;
    -027import org.bukkit.Bukkit;
    -028import org.bukkit.ChatColor;
    -029import org.bukkit.DyeColor;
    -030import org.bukkit.World;
    -031import org.bukkit.command.CommandSender;
    -032import org.bukkit.entity.EntityType;
    -033import org.bukkit.entity.Player;
    -034import org.bukkit.util.StringUtil;
    -035
    -036import java.util.ArrayList;
    -037import java.util.Arrays;
    -038import java.util.Set;
    -039import java.util.stream.Collectors;
    -040import java.util.stream.Stream;
    -041
    -042@SuppressWarnings("WeakerAccess")
    -043public class BukkitCommandCompletions extends CommandCompletions<BukkitCommandCompletionContext> {
    -044    public BukkitCommandCompletions(BukkitCommandManager manager) {
    -045        super(manager);
    -046        registerAsyncCompletion("mobs", c -> {
    -047            final Stream<String> normal = Stream.of(EntityType.values())
    -048                    .map(entityType -> ACFUtil.simplifyString(entityType.getName()));
    -049            return normal.collect(Collectors.toList());
    -050        });
    -051        registerAsyncCompletion("chatcolors", c -> {
    -052            Stream<ChatColor> colors = Stream.of(ChatColor.values());
    -053            if (c.hasConfig("colorsonly")) {
    -054                colors = colors.filter(color -> color.ordinal() <= 0xF);
    -055            }
    -056            String filter = c.getConfig("filter");
    -057            if (filter != null) {
    -058                Set<String> filters = Arrays.stream(ACFPatterns.COLON.split(filter))
    -059                        .map(ACFUtil::simplifyString).collect(Collectors.toSet());
    -060
    -061                colors = colors.filter(color -> filters.contains(ACFUtil.simplifyString(color.name())));
    -062            }
    -063
    -064            return colors.map(color -> ACFUtil.simplifyString(color.name())).collect(Collectors.toList());
    -065        });
    -066        registerAsyncCompletion("dyecolors", c -> ACFUtil.enumNames(DyeColor.values()));
    -067        registerCompletion("worlds", c -> (
    -068            Bukkit.getWorlds().stream().map(World::getName).collect(Collectors.toList())
    -069        ));
    -070
    -071        registerCompletion("players", c -> {
    -072            CommandSender sender = c.getSender();
    -073            Validate.notNull(sender, "Sender cannot be null");
    -074
    -075            Player senderPlayer = sender instanceof Player ? (Player) sender : null;
    -076
    -077            ArrayList<String> matchedPlayers = new ArrayList<>();
    -078            for (Player player : Bukkit.getOnlinePlayers()) {
    -079                String name = player.getName();
    -080                if ((senderPlayer == null || senderPlayer.canSee(player)) && StringUtil.startsWithIgnoreCase(name, c.getInput())) {
    -081                    matchedPlayers.add(name);
    -082                }
    -083            }
    -084
    +026import co.aikar.commands.bukkit.contexts.OnlinePlayer;
    +027import org.apache.commons.lang.Validate;
    +028import org.bukkit.Bukkit;
    +029import org.bukkit.ChatColor;
    +030import org.bukkit.DyeColor;
    +031import org.bukkit.World;
    +032import org.bukkit.command.CommandSender;
    +033import org.bukkit.entity.EntityType;
    +034import org.bukkit.entity.Player;
    +035import org.bukkit.util.StringUtil;
    +036
    +037import java.util.ArrayList;
    +038import java.util.Arrays;
    +039import java.util.Set;
    +040import java.util.stream.Collectors;
    +041import java.util.stream.Stream;
    +042
    +043@SuppressWarnings("WeakerAccess")
    +044public class BukkitCommandCompletions extends CommandCompletions<BukkitCommandCompletionContext> {
    +045    public BukkitCommandCompletions(BukkitCommandManager manager) {
    +046        super(manager);
    +047        registerAsyncCompletion("mobs", c -> {
    +048            final Stream<String> normal = Stream.of(EntityType.values())
    +049                    .map(entityType -> ACFUtil.simplifyString(entityType.getName()));
    +050            return normal.collect(Collectors.toList());
    +051        });
    +052        registerAsyncCompletion("chatcolors", c -> {
    +053            Stream<ChatColor> colors = Stream.of(ChatColor.values());
    +054            if (c.hasConfig("colorsonly")) {
    +055                colors = colors.filter(color -> color.ordinal() <= 0xF);
    +056            }
    +057            String filter = c.getConfig("filter");
    +058            if (filter != null) {
    +059                Set<String> filters = Arrays.stream(ACFPatterns.COLON.split(filter))
    +060                        .map(ACFUtil::simplifyString).collect(Collectors.toSet());
    +061
    +062                colors = colors.filter(color -> filters.contains(ACFUtil.simplifyString(color.name())));
    +063            }
    +064
    +065            return colors.map(color -> ACFUtil.simplifyString(color.name())).collect(Collectors.toList());
    +066        });
    +067        registerAsyncCompletion("dyecolors", c -> ACFUtil.enumNames(DyeColor.values()));
    +068        registerCompletion("worlds", c -> (
    +069                Bukkit.getWorlds().stream().map(World::getName).collect(Collectors.toList())
    +070        ));
    +071
    +072        registerCompletion("players", c -> {
    +073            CommandSender sender = c.getSender();
    +074            Validate.notNull(sender, "Sender cannot be null");
    +075
    +076            Player senderPlayer = sender instanceof Player ? (Player) sender : null;
    +077
    +078            ArrayList<String> matchedPlayers = new ArrayList<>();
    +079            for (Player player : Bukkit.getOnlinePlayers()) {
    +080                String name = player.getName();
    +081                if ((senderPlayer == null || senderPlayer.canSee(player)) && StringUtil.startsWithIgnoreCase(name, c.getInput())) {
    +082                    matchedPlayers.add(name);
    +083                }
    +084            }
     085
    -086            matchedPlayers.sort(String.CASE_INSENSITIVE_ORDER);
    -087            return matchedPlayers;
    -088        });
    -089    }
    +086
    +087            matchedPlayers.sort(String.CASE_INSENSITIVE_ORDER);
    +088            return matchedPlayers;
    +089        });
     090
    -091}
    +091        setDefaultCompletion("players", OnlinePlayer.class, co.aikar.commands.contexts.OnlinePlayer.class, Player.class);
    +092        setDefaultCompletion("worlds", World.class);
    +093    }
    +094
    +095}
     
     
     
    diff --git a/docs/acf-bukkit/src-html/co/aikar/commands/BukkitCommandManager.html b/docs/acf-bukkit/src-html/co/aikar/commands/BukkitCommandManager.html
    index e048a8d6..e900caba 100644
    --- a/docs/acf-bukkit/src-html/co/aikar/commands/BukkitCommandManager.html
    +++ b/docs/acf-bukkit/src-html/co/aikar/commands/BukkitCommandManager.html
    @@ -43,360 +43,364 @@
     035import org.bukkit.command.CommandSender;
     036import org.bukkit.command.PluginIdentifiableCommand;
     037import org.bukkit.command.SimpleCommandMap;
    -038import org.bukkit.entity.Player;
    -039import org.bukkit.inventory.ItemFactory;
    -040import org.bukkit.plugin.Plugin;
    -041import org.bukkit.plugin.PluginManager;
    -042import org.bukkit.plugin.java.JavaPlugin;
    -043import org.bukkit.scheduler.BukkitScheduler;
    -044import org.bukkit.scheduler.BukkitTask;
    -045import org.bukkit.scoreboard.ScoreboardManager;
    -046import org.jetbrains.annotations.NotNull;
    -047
    -048import java.lang.reflect.Field;
    -049import java.lang.reflect.Method;
    -050import java.util.Collection;
    -051import java.util.Collections;
    -052import java.util.HashMap;
    -053import java.util.List;
    -054import java.util.Locale;
    -055import java.util.Map;
    -056import java.util.Objects;
    -057import java.util.logging.Level;
    -058import java.util.logging.Logger;
    -059import java.util.regex.Matcher;
    -060import java.util.regex.Pattern;
    -061
    -062@SuppressWarnings("WeakerAccess")
    -063public class BukkitCommandManager extends CommandManager<
    -064        CommandSender,
    -065        BukkitCommandIssuer,
    -066        ChatColor,
    -067        BukkitMessageFormatter,
    -068        BukkitCommandExecutionContext,
    -069        BukkitConditionContext
    -070        > {
    -071
    -072    @SuppressWarnings("WeakerAccess")
    -073    protected final Plugin plugin;
    -074    private final CommandMap commandMap;
    -075    private final TimingManager timingManager;
    -076    private final BukkitTask localeTask;
    -077    private final Logger logger;
    -078    public final Integer mcMinorVersion;
    -079    public final Integer mcPatchVersion;
    -080    protected Map<String, Command> knownCommands = new HashMap<>();
    -081    protected Map<String, BukkitRootCommand> registeredCommands = new HashMap<>();
    -082    protected BukkitCommandContexts contexts;
    -083    protected BukkitCommandCompletions completions;
    -084    MCTiming commandTiming;
    -085    protected BukkitLocales locales;
    -086    private boolean cantReadLocale = false;
    -087    protected boolean autoDetectFromClient = true;
    -088
    -089    @SuppressWarnings("JavaReflectionMemberAccess")
    -090    public BukkitCommandManager(Plugin plugin) {
    -091        this.plugin = plugin;
    -092        this.logger = Logger.getLogger(this.plugin.getName());
    -093        this.timingManager = TimingManager.of(plugin);
    -094        this.commandTiming = this.timingManager.of("Commands");
    -095        this.commandMap = hookCommandMap();
    -096        this.formatters.put(MessageType.ERROR, defaultFormatter = new BukkitMessageFormatter(ChatColor.RED, ChatColor.YELLOW, ChatColor.RED));
    -097        this.formatters.put(MessageType.SYNTAX, new BukkitMessageFormatter(ChatColor.YELLOW, ChatColor.GREEN, ChatColor.WHITE));
    -098        this.formatters.put(MessageType.INFO, new BukkitMessageFormatter(ChatColor.BLUE, ChatColor.DARK_GREEN, ChatColor.GREEN));
    -099        this.formatters.put(MessageType.HELP, new BukkitMessageFormatter(ChatColor.AQUA, ChatColor.GREEN, ChatColor.YELLOW));
    -100        Pattern versionPattern = Pattern.compile("\\(MC: (\\d)\\.(\\d+)\\.?(\\d+?)?\\)");
    -101        Matcher matcher = versionPattern.matcher(Bukkit.getVersion());
    -102        if (matcher.find()) {
    -103            this.mcMinorVersion = ACFUtil.parseInt(matcher.toMatchResult().group(2), 0);
    -104            this.mcPatchVersion = ACFUtil.parseInt(matcher.toMatchResult().group(3), 0);
    -105        } else {
    -106            this.mcMinorVersion = -1;
    -107            this.mcPatchVersion = -1;
    -108        }
    -109
    -110        Bukkit.getPluginManager().registerEvents(new ACFBukkitListener(this, plugin), plugin);
    -111
    -112        getLocales(); // auto load locales
    -113        this.localeTask = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
    -114            if (this.cantReadLocale || !this.autoDetectFromClient) {
    -115                return;
    -116            }
    -117            Bukkit.getOnlinePlayers().forEach(this::readPlayerLocale);
    -118        }, 5, 5);
    -119
    -120        registerDependency(plugin.getClass(), plugin);
    -121        registerDependency(Plugin.class, plugin);
    -122        registerDependency(JavaPlugin.class, plugin);
    -123        registerDependency(PluginManager.class, Bukkit.getPluginManager());
    -124        registerDependency(Server.class, Bukkit.getServer());
    -125        registerDependency(BukkitScheduler.class, Bukkit.getScheduler());
    -126        registerDependency(ScoreboardManager.class, Bukkit.getScoreboardManager());
    -127        registerDependency(ItemFactory.class, Bukkit.getItemFactory());
    -128    }
    -129
    -130    @NotNull
    -131    private CommandMap hookCommandMap() {
    -132        CommandMap commandMap = null;
    -133        try {
    -134            Server server = Bukkit.getServer();
    -135            Method getCommandMap = server.getClass().getDeclaredMethod("getCommandMap");
    -136            getCommandMap.setAccessible(true);
    -137            commandMap = (CommandMap) getCommandMap.invoke(server);
    -138            if (!SimpleCommandMap.class.isAssignableFrom(commandMap.getClass())) {
    -139                this.log(LogLevel.ERROR, "ERROR: CommandMap has been hijacked! Offending command map is located at: " + commandMap.getClass().getName());
    -140                this.log(LogLevel.ERROR, "We are going to try to hijack it back and resolve this, but you are now in dangerous territory.");
    -141                this.log(LogLevel.ERROR, "We can not guarantee things are going to work.");
    -142                Field cmField = server.getClass().getDeclaredField("commandMap");
    -143                commandMap = new ProxyCommandMap(this, commandMap);
    -144                cmField.set(server, commandMap);
    -145                this.log(LogLevel.INFO, "Injected Proxy Command Map... good luck...");
    -146            }
    -147            Field knownCommands = SimpleCommandMap.class.getDeclaredField("knownCommands");
    -148            knownCommands.setAccessible(true);
    -149            //noinspection unchecked
    -150            this.knownCommands = (Map<String, Command>) knownCommands.get(commandMap);
    -151        } catch (Exception e) {
    -152            this.log(LogLevel.ERROR, "Failed to get Command Map. ACF will not function.");
    -153            ACFUtil.sneaky(e);
    -154        }
    -155        return commandMap;
    -156    }
    -157
    -158    public Plugin getPlugin() {
    -159        return this.plugin;
    +038import org.bukkit.configuration.file.FileConfiguration;
    +039import org.bukkit.entity.Player;
    +040import org.bukkit.inventory.ItemFactory;
    +041import org.bukkit.plugin.Plugin;
    +042import org.bukkit.plugin.PluginManager;
    +043import org.bukkit.plugin.java.JavaPlugin;
    +044import org.bukkit.scheduler.BukkitScheduler;
    +045import org.bukkit.scheduler.BukkitTask;
    +046import org.bukkit.scoreboard.ScoreboardManager;
    +047import org.jetbrains.annotations.NotNull;
    +048
    +049import java.lang.reflect.Field;
    +050import java.lang.reflect.Method;
    +051import java.util.Collection;
    +052import java.util.Collections;
    +053import java.util.HashMap;
    +054import java.util.List;
    +055import java.util.Locale;
    +056import java.util.Map;
    +057import java.util.Objects;
    +058import java.util.logging.Level;
    +059import java.util.logging.Logger;
    +060import java.util.regex.Matcher;
    +061import java.util.regex.Pattern;
    +062
    +063@SuppressWarnings("WeakerAccess")
    +064public class BukkitCommandManager extends CommandManager<
    +065        CommandSender,
    +066        BukkitCommandIssuer,
    +067        ChatColor,
    +068        BukkitMessageFormatter,
    +069        BukkitCommandExecutionContext,
    +070        BukkitConditionContext
    +071        > {
    +072
    +073    @SuppressWarnings("WeakerAccess")
    +074    protected final Plugin plugin;
    +075    private final CommandMap commandMap;
    +076    private final TimingManager timingManager;
    +077    private final BukkitTask localeTask;
    +078    private final Logger logger;
    +079    public final Integer mcMinorVersion;
    +080    public final Integer mcPatchVersion;
    +081    protected Map<String, Command> knownCommands = new HashMap<>();
    +082    protected Map<String, BukkitRootCommand> registeredCommands = new HashMap<>();
    +083    protected BukkitCommandContexts contexts;
    +084    protected BukkitCommandCompletions completions;
    +085    MCTiming commandTiming;
    +086    protected BukkitLocales locales;
    +087    private boolean cantReadLocale = false;
    +088    protected boolean autoDetectFromClient = true;
    +089
    +090    @SuppressWarnings("JavaReflectionMemberAccess")
    +091    public BukkitCommandManager(Plugin plugin) {
    +092        this.plugin = plugin;
    +093        this.logger = Logger.getLogger(this.plugin.getName());
    +094        this.timingManager = TimingManager.of(plugin);
    +095        this.commandTiming = this.timingManager.of("Commands");
    +096        this.commandMap = hookCommandMap();
    +097        this.formatters.put(MessageType.ERROR, defaultFormatter = new BukkitMessageFormatter(ChatColor.RED, ChatColor.YELLOW, ChatColor.RED));
    +098        this.formatters.put(MessageType.SYNTAX, new BukkitMessageFormatter(ChatColor.YELLOW, ChatColor.GREEN, ChatColor.WHITE));
    +099        this.formatters.put(MessageType.INFO, new BukkitMessageFormatter(ChatColor.BLUE, ChatColor.DARK_GREEN, ChatColor.GREEN));
    +100        this.formatters.put(MessageType.HELP, new BukkitMessageFormatter(ChatColor.AQUA, ChatColor.GREEN, ChatColor.YELLOW));
    +101        Pattern versionPattern = Pattern.compile("\\(MC: (\\d)\\.(\\d+)\\.?(\\d+?)?\\)");
    +102        Matcher matcher = versionPattern.matcher(Bukkit.getVersion());
    +103        if (matcher.find()) {
    +104            this.mcMinorVersion = ACFUtil.parseInt(matcher.toMatchResult().group(2), 0);
    +105            this.mcPatchVersion = ACFUtil.parseInt(matcher.toMatchResult().group(3), 0);
    +106        } else {
    +107            this.mcMinorVersion = -1;
    +108            this.mcPatchVersion = -1;
    +109        }
    +110
    +111        Bukkit.getPluginManager().registerEvents(new ACFBukkitListener(this, plugin), plugin);
    +112
    +113        getLocales(); // auto load locales
    +114        this.localeTask = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
    +115            if (this.cantReadLocale || !this.autoDetectFromClient) {
    +116                return;
    +117            }
    +118            Bukkit.getOnlinePlayers().forEach(this::readPlayerLocale);
    +119        }, 5, 5);
    +120
    +121        registerDependency(plugin.getClass(), plugin);
    +122        registerDependency(Logger.class, plugin.getLogger());
    +123        registerDependency(FileConfiguration.class, plugin.getConfig());
    +124        registerDependency(FileConfiguration.class, "config", plugin.getConfig());
    +125        registerDependency(Plugin.class, plugin);
    +126        registerDependency(JavaPlugin.class, plugin);
    +127        registerDependency(PluginManager.class, Bukkit.getPluginManager());
    +128        registerDependency(Server.class, Bukkit.getServer());
    +129        registerDependency(BukkitScheduler.class, Bukkit.getScheduler());
    +130        registerDependency(ScoreboardManager.class, Bukkit.getScoreboardManager());
    +131        registerDependency(ItemFactory.class, Bukkit.getItemFactory());
    +132    }
    +133
    +134    @NotNull
    +135    private CommandMap hookCommandMap() {
    +136        CommandMap commandMap = null;
    +137        try {
    +138            Server server = Bukkit.getServer();
    +139            Method getCommandMap = server.getClass().getDeclaredMethod("getCommandMap");
    +140            getCommandMap.setAccessible(true);
    +141            commandMap = (CommandMap) getCommandMap.invoke(server);
    +142            if (!SimpleCommandMap.class.isAssignableFrom(commandMap.getClass())) {
    +143                this.log(LogLevel.ERROR, "ERROR: CommandMap has been hijacked! Offending command map is located at: " + commandMap.getClass().getName());
    +144                this.log(LogLevel.ERROR, "We are going to try to hijack it back and resolve this, but you are now in dangerous territory.");
    +145                this.log(LogLevel.ERROR, "We can not guarantee things are going to work.");
    +146                Field cmField = server.getClass().getDeclaredField("commandMap");
    +147                commandMap = new ProxyCommandMap(this, commandMap);
    +148                cmField.set(server, commandMap);
    +149                this.log(LogLevel.INFO, "Injected Proxy Command Map... good luck...");
    +150            }
    +151            Field knownCommands = SimpleCommandMap.class.getDeclaredField("knownCommands");
    +152            knownCommands.setAccessible(true);
    +153            //noinspection unchecked
    +154            this.knownCommands = (Map<String, Command>) knownCommands.get(commandMap);
    +155        } catch (Exception e) {
    +156            this.log(LogLevel.ERROR, "Failed to get Command Map. ACF will not function.");
    +157            ACFUtil.sneaky(e);
    +158        }
    +159        return commandMap;
     160    }
     161
    -162    @Override
    -163    public boolean isCommandIssuer(Class<?> type) {
    -164        return CommandSender.class.isAssignableFrom(type);
    -165    }
    -166
    -167    @Override
    -168    public synchronized CommandContexts<BukkitCommandExecutionContext> getCommandContexts() {
    -169        if (this.contexts == null) {
    -170            this.contexts = new BukkitCommandContexts(this);
    -171        }
    -172        return contexts;
    -173    }
    -174
    -175    @Override
    -176    public synchronized CommandCompletions<BukkitCommandCompletionContext> getCommandCompletions() {
    -177        if (this.completions == null) {
    -178            this.completions = new BukkitCommandCompletions(this);
    -179        }
    -180        return completions;
    -181    }
    -182
    -183
    -184    @Override
    -185    public BukkitLocales getLocales() {
    -186        if (this.locales == null) {
    -187            this.locales = new BukkitLocales(this);
    -188            this.locales.loadLanguages();
    -189        }
    -190        return locales;
    -191    }
    -192
    -193
    -194    @Override
    -195    public boolean hasRegisteredCommands() {
    -196        return !registeredCommands.isEmpty();
    -197    }
    -198
    -199    public void registerCommand(BaseCommand command, boolean force) {
    -200        final String plugin = this.plugin.getName().toLowerCase();
    -201        command.onRegister(this);
    -202        for (Map.Entry<String, RootCommand> entry : command.registeredCommands.entrySet()) {
    -203            String commandName = entry.getKey().toLowerCase();
    -204            BukkitRootCommand bukkitCommand = (BukkitRootCommand) entry.getValue();
    -205            if (!bukkitCommand.isRegistered) {
    -206                Command oldCommand = commandMap.getCommand(commandName);
    -207                if (oldCommand instanceof PluginIdentifiableCommand && ((PluginIdentifiableCommand) oldCommand).getPlugin() == this.plugin) {
    -208                    knownCommands.remove(commandName);
    -209                    oldCommand.unregister(commandMap);
    -210                } else if (oldCommand != null && force) {
    -211                    knownCommands.remove(commandName);
    -212                    for (Map.Entry<String, Command> ce : knownCommands.entrySet()) {
    -213                        String key = ce.getKey();
    -214                        Command value = ce.getValue();
    -215                        if (key.contains(":") && oldCommand.equals(value)) {
    -216                            String[] split = ACFPatterns.COLON.split(key, 2);
    -217                            if (split.length > 1) {
    -218                                oldCommand.unregister(commandMap);
    -219                                oldCommand.setLabel(split[0] + ":" + command.getName());
    -220                                oldCommand.register(commandMap);
    -221                            }
    -222                        }
    -223                    }
    -224                }
    -225                commandMap.register(commandName, plugin, bukkitCommand);
    -226            }
    -227            bukkitCommand.isRegistered = true;
    -228            registeredCommands.put(commandName, bukkitCommand);
    -229        }
    -230    }
    -231
    -232    @Override
    -233    public void registerCommand(BaseCommand command) {
    -234        registerCommand(command, false);
    -235    }
    -236
    -237    public void unregisterCommand(BaseCommand command) {
    -238        for (RootCommand rootcommand : command.registeredCommands.values()) {
    -239            BukkitRootCommand bukkitCommand = (BukkitRootCommand) rootcommand;
    -240            bukkitCommand.getSubCommands().values().removeAll(command.subCommands.values());
    -241            if (bukkitCommand.isRegistered && bukkitCommand.getSubCommands().isEmpty()) {
    -242                unregisterCommand(bukkitCommand);
    -243                bukkitCommand.isRegistered = false;
    -244            }
    -245        }
    -246    }
    -247
    -248    /**
    -249     * @param command
    -250     * @deprecated Use unregisterCommand(BaseCommand) - this will be visibility reduced later.
    -251     */
    -252    @Deprecated
    -253    public void unregisterCommand(BukkitRootCommand command) {
    -254        final String plugin = this.plugin.getName().toLowerCase();
    -255        command.unregister(commandMap);
    -256        String key = command.getName();
    -257        Command registered = knownCommands.get(key);
    -258        if (command.equals(registered)) {
    -259            knownCommands.remove(key);
    -260        }
    -261        knownCommands.remove(plugin + ":" + key);
    -262    }
    -263
    -264    public void unregisterCommands() {
    -265        for (Map.Entry<String, BukkitRootCommand> entry : registeredCommands.entrySet()) {
    -266            unregisterCommand(entry.getValue());
    -267        }
    -268        this.registeredCommands.clear();
    -269    }
    -270
    -271
    -272    private Field getEntityField(Player player) throws NoSuchFieldException {
    -273        Class cls = player.getClass();
    -274        while (cls != Object.class) {
    -275            if (cls.getName().endsWith("CraftEntity")) {
    -276                Field field = cls.getDeclaredField("entity");
    -277                field.setAccessible(true);
    -278                return field;
    -279            }
    -280            cls = cls.getSuperclass();
    -281        }
    -282        return null;
    -283    }
    -284
    -285    public Locale setPlayerLocale(Player player, Locale locale) {
    -286        return this.setIssuerLocale(player, locale);
    +162    public Plugin getPlugin() {
    +163        return this.plugin;
    +164    }
    +165
    +166    @Override
    +167    public boolean isCommandIssuer(Class<?> type) {
    +168        return CommandSender.class.isAssignableFrom(type);
    +169    }
    +170
    +171    @Override
    +172    public synchronized CommandContexts<BukkitCommandExecutionContext> getCommandContexts() {
    +173        if (this.contexts == null) {
    +174            this.contexts = new BukkitCommandContexts(this);
    +175        }
    +176        return contexts;
    +177    }
    +178
    +179    @Override
    +180    public synchronized CommandCompletions<BukkitCommandCompletionContext> getCommandCompletions() {
    +181        if (this.completions == null) {
    +182            this.completions = new BukkitCommandCompletions(this);
    +183        }
    +184        return completions;
    +185    }
    +186
    +187
    +188    @Override
    +189    public BukkitLocales getLocales() {
    +190        if (this.locales == null) {
    +191            this.locales = new BukkitLocales(this);
    +192            this.locales.loadLanguages();
    +193        }
    +194        return locales;
    +195    }
    +196
    +197
    +198    @Override
    +199    public boolean hasRegisteredCommands() {
    +200        return !registeredCommands.isEmpty();
    +201    }
    +202
    +203    public void registerCommand(BaseCommand command, boolean force) {
    +204        final String plugin = this.plugin.getName().toLowerCase();
    +205        command.onRegister(this);
    +206        for (Map.Entry<String, RootCommand> entry : command.registeredCommands.entrySet()) {
    +207            String commandName = entry.getKey().toLowerCase();
    +208            BukkitRootCommand bukkitCommand = (BukkitRootCommand) entry.getValue();
    +209            if (!bukkitCommand.isRegistered) {
    +210                Command oldCommand = commandMap.getCommand(commandName);
    +211                if (oldCommand instanceof PluginIdentifiableCommand && ((PluginIdentifiableCommand) oldCommand).getPlugin() == this.plugin) {
    +212                    knownCommands.remove(commandName);
    +213                    oldCommand.unregister(commandMap);
    +214                } else if (oldCommand != null && force) {
    +215                    knownCommands.remove(commandName);
    +216                    for (Map.Entry<String, Command> ce : knownCommands.entrySet()) {
    +217                        String key = ce.getKey();
    +218                        Command value = ce.getValue();
    +219                        if (key.contains(":") && oldCommand.equals(value)) {
    +220                            String[] split = ACFPatterns.COLON.split(key, 2);
    +221                            if (split.length > 1) {
    +222                                oldCommand.unregister(commandMap);
    +223                                oldCommand.setLabel(split[0] + ":" + command.getName());
    +224                                oldCommand.register(commandMap);
    +225                            }
    +226                        }
    +227                    }
    +228                }
    +229                commandMap.register(commandName, plugin, bukkitCommand);
    +230            }
    +231            bukkitCommand.isRegistered = true;
    +232            registeredCommands.put(commandName, bukkitCommand);
    +233        }
    +234    }
    +235
    +236    @Override
    +237    public void registerCommand(BaseCommand command) {
    +238        registerCommand(command, false);
    +239    }
    +240
    +241    public void unregisterCommand(BaseCommand command) {
    +242        for (RootCommand rootcommand : command.registeredCommands.values()) {
    +243            BukkitRootCommand bukkitCommand = (BukkitRootCommand) rootcommand;
    +244            bukkitCommand.getSubCommands().values().removeAll(command.subCommands.values());
    +245            if (bukkitCommand.isRegistered && bukkitCommand.getSubCommands().isEmpty()) {
    +246                unregisterCommand(bukkitCommand);
    +247                bukkitCommand.isRegistered = false;
    +248            }
    +249        }
    +250    }
    +251
    +252    /**
    +253     * @param command
    +254     * @deprecated Use unregisterCommand(BaseCommand) - this will be visibility reduced later.
    +255     */
    +256    @Deprecated
    +257    public void unregisterCommand(BukkitRootCommand command) {
    +258        final String plugin = this.plugin.getName().toLowerCase();
    +259        command.unregister(commandMap);
    +260        String key = command.getName();
    +261        Command registered = knownCommands.get(key);
    +262        if (command.equals(registered)) {
    +263            knownCommands.remove(key);
    +264        }
    +265        knownCommands.remove(plugin + ":" + key);
    +266    }
    +267
    +268    public void unregisterCommands() {
    +269        for (Map.Entry<String, BukkitRootCommand> entry : registeredCommands.entrySet()) {
    +270            unregisterCommand(entry.getValue());
    +271        }
    +272        this.registeredCommands.clear();
    +273    }
    +274
    +275
    +276    private Field getEntityField(Player player) throws NoSuchFieldException {
    +277        Class cls = player.getClass();
    +278        while (cls != Object.class) {
    +279            if (cls.getName().endsWith("CraftEntity")) {
    +280                Field field = cls.getDeclaredField("entity");
    +281                field.setAccessible(true);
    +282                return field;
    +283            }
    +284            cls = cls.getSuperclass();
    +285        }
    +286        return null;
     287    }
     288
    -289    void readPlayerLocale(Player player) {
    -290        if (!player.isOnline() || cantReadLocale) {
    -291            return;
    -292        }
    -293        try {
    -294            Field entityField = getEntityField(player);
    -295            if (entityField == null) {
    -296                return;
    -297            }
    -298            Object nmsPlayer = entityField.get(player);
    -299            if (nmsPlayer != null) {
    -300                Field localeField = nmsPlayer.getClass().getDeclaredField("locale");
    -301                Object localeString = localeField.get(nmsPlayer);
    -302                if (localeString instanceof String) {
    -303                    String[] split = ACFPatterns.UNDERSCORE.split((String) localeString);
    -304                    Locale locale = split.length > 1 ? new Locale(split[0], split[1]) : new Locale(split[0]);
    -305                    Locale prev = issuersLocale.put(player.getUniqueId(), locale);
    -306                    if (!Objects.equals(locale, prev)) {
    -307                        this.notifyLocaleChange(getCommandIssuer(player), prev, locale);
    -308                    }
    -309                }
    -310            }
    -311        } catch (Exception e) {
    -312            cantReadLocale = true;
    -313            this.localeTask.cancel();
    -314            this.log(LogLevel.INFO, "Can't read players locale, you will be unable to automatically detect players language. Only Bukkit 1.7+ is supported for this.", e);
    -315        }
    -316    }
    -317
    -318    public TimingManager getTimings() {
    -319        return timingManager;
    +289    public Locale setPlayerLocale(Player player, Locale locale) {
    +290        return this.setIssuerLocale(player, locale);
    +291    }
    +292
    +293    void readPlayerLocale(Player player) {
    +294        if (!player.isOnline() || cantReadLocale) {
    +295            return;
    +296        }
    +297        try {
    +298            Field entityField = getEntityField(player);
    +299            if (entityField == null) {
    +300                return;
    +301            }
    +302            Object nmsPlayer = entityField.get(player);
    +303            if (nmsPlayer != null) {
    +304                Field localeField = nmsPlayer.getClass().getDeclaredField("locale");
    +305                Object localeString = localeField.get(nmsPlayer);
    +306                if (localeString instanceof String) {
    +307                    String[] split = ACFPatterns.UNDERSCORE.split((String) localeString);
    +308                    Locale locale = split.length > 1 ? new Locale(split[0], split[1]) : new Locale(split[0]);
    +309                    Locale prev = issuersLocale.put(player.getUniqueId(), locale);
    +310                    if (!Objects.equals(locale, prev)) {
    +311                        this.notifyLocaleChange(getCommandIssuer(player), prev, locale);
    +312                    }
    +313                }
    +314            }
    +315        } catch (Exception e) {
    +316            cantReadLocale = true;
    +317            this.localeTask.cancel();
    +318            this.log(LogLevel.INFO, "Can't read players locale, you will be unable to automatically detect players language. Only Bukkit 1.7+ is supported for this.", e);
    +319        }
     320    }
     321
    -322    @Override
    -323    public RootCommand createRootCommand(String cmd) {
    -324        return new BukkitRootCommand(this, cmd);
    -325    }
    -326
    -327    @Override
    -328    public Collection<RootCommand> getRegisteredRootCommands() {
    -329        return Collections.unmodifiableCollection(registeredCommands.values());
    -330    }
    -331
    -332    @Override
    -333    public BukkitCommandIssuer getCommandIssuer(Object issuer) {
    -334        if (!(issuer instanceof CommandSender)) {
    -335            throw new IllegalArgumentException(issuer.getClass().getName() + " is not a Command Issuer.");
    -336        }
    -337        return new BukkitCommandIssuer(this, (CommandSender) issuer);
    -338    }
    -339
    -340    @Override
    -341    public BukkitCommandExecutionContext createCommandContext(RegisteredCommand command, CommandParameter parameter, CommandIssuer sender, List<String> args, int i, Map<String, Object> passedArgs) {
    -342        return new BukkitCommandExecutionContext(command, parameter, (BukkitCommandIssuer) sender, args, i, passedArgs);
    -343    }
    -344
    -345    @Override
    -346    public BukkitCommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args) {
    -347        return new BukkitCommandCompletionContext(command, (BukkitCommandIssuer) sender, input, config, args);
    -348    }
    -349
    -350    @Override
    -351    public RegisteredCommand createRegisteredCommand(BaseCommand command, String cmdName, Method method, String prefSubCommand) {
    -352        return new BukkitRegisteredCommand(command, cmdName, method, prefSubCommand);
    -353    }
    -354
    -355    @Override
    -356    public BukkitConditionContext createConditionContext(CommandIssuer issuer, String config) {
    -357        return new BukkitConditionContext((BukkitCommandIssuer) issuer, config);
    -358    }
    -359
    -360
    -361    @Override
    -362    public void log(LogLevel level, String message, Throwable throwable) {
    -363        Level logLevel = level == LogLevel.INFO ? Level.INFO : Level.SEVERE;
    -364        logger.log(logLevel, LogLevel.LOG_PREFIX + message);
    -365        if (throwable != null) {
    -366            for (String line : ACFPatterns.NEWLINE.split(ApacheCommonsExceptionUtil.getFullStackTrace(throwable))) {
    -367                logger.log(logLevel, LogLevel.LOG_PREFIX + line);
    -368            }
    -369        }
    -370    }
    -371
    -372    public boolean usePerIssuerLocale(boolean usePerIssuerLocale, boolean autoDetectFromClient) {
    -373        boolean old = this.usePerIssuerLocale;
    -374        this.usePerIssuerLocale = usePerIssuerLocale;
    -375        this.autoDetectFromClient = autoDetectFromClient;
    -376        return old;
    -377    }
    -378
    -379    @Override
    -380    public String getCommandPrefix(CommandIssuer issuer) {
    -381        return issuer.isPlayer() ? "/" : "";
    -382    }
    -383
    -384    @Override
    -385    protected boolean handleUncaughtException(BaseCommand scope, RegisteredCommand registeredCommand, CommandIssuer sender, List<String> args, Throwable t) {
    -386        if (t instanceof CommandException && t.getCause() != null && t.getMessage().startsWith("Unhandled exception")) {
    -387            t = t.getCause();
    -388        }
    -389        return super.handleUncaughtException(scope, registeredCommand, sender, args, t);
    -390    }
    -391}
    +322    public TimingManager getTimings() {
    +323        return timingManager;
    +324    }
    +325
    +326    @Override
    +327    public RootCommand createRootCommand(String cmd) {
    +328        return new BukkitRootCommand(this, cmd);
    +329    }
    +330
    +331    @Override
    +332    public Collection<RootCommand> getRegisteredRootCommands() {
    +333        return Collections.unmodifiableCollection(registeredCommands.values());
    +334    }
    +335
    +336    @Override
    +337    public BukkitCommandIssuer getCommandIssuer(Object issuer) {
    +338        if (!(issuer instanceof CommandSender)) {
    +339            throw new IllegalArgumentException(issuer.getClass().getName() + " is not a Command Issuer.");
    +340        }
    +341        return new BukkitCommandIssuer(this, (CommandSender) issuer);
    +342    }
    +343
    +344    @Override
    +345    public BukkitCommandExecutionContext createCommandContext(RegisteredCommand command, CommandParameter parameter, CommandIssuer sender, List<String> args, int i, Map<String, Object> passedArgs) {
    +346        return new BukkitCommandExecutionContext(command, parameter, (BukkitCommandIssuer) sender, args, i, passedArgs);
    +347    }
    +348
    +349    @Override
    +350    public BukkitCommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args) {
    +351        return new BukkitCommandCompletionContext(command, (BukkitCommandIssuer) sender, input, config, args);
    +352    }
    +353
    +354    @Override
    +355    public RegisteredCommand createRegisteredCommand(BaseCommand command, String cmdName, Method method, String prefSubCommand) {
    +356        return new BukkitRegisteredCommand(command, cmdName, method, prefSubCommand);
    +357    }
    +358
    +359    @Override
    +360    public BukkitConditionContext createConditionContext(CommandIssuer issuer, String config) {
    +361        return new BukkitConditionContext((BukkitCommandIssuer) issuer, config);
    +362    }
    +363
    +364
    +365    @Override
    +366    public void log(LogLevel level, String message, Throwable throwable) {
    +367        Level logLevel = level == LogLevel.INFO ? Level.INFO : Level.SEVERE;
    +368        logger.log(logLevel, LogLevel.LOG_PREFIX + message);
    +369        if (throwable != null) {
    +370            for (String line : ACFPatterns.NEWLINE.split(ApacheCommonsExceptionUtil.getFullStackTrace(throwable))) {
    +371                logger.log(logLevel, LogLevel.LOG_PREFIX + line);
    +372            }
    +373        }
    +374    }
    +375
    +376    public boolean usePerIssuerLocale(boolean usePerIssuerLocale, boolean autoDetectFromClient) {
    +377        boolean old = this.usePerIssuerLocale;
    +378        this.usePerIssuerLocale = usePerIssuerLocale;
    +379        this.autoDetectFromClient = autoDetectFromClient;
    +380        return old;
    +381    }
    +382
    +383    @Override
    +384    public String getCommandPrefix(CommandIssuer issuer) {
    +385        return issuer.isPlayer() ? "/" : "";
    +386    }
    +387
    +388    @Override
    +389    protected boolean handleUncaughtException(BaseCommand scope, RegisteredCommand registeredCommand, CommandIssuer sender, List<String> args, Throwable t) {
    +390        if (t instanceof CommandException && t.getCause() != null && t.getMessage().startsWith("Unhandled exception")) {
    +391            t = t.getCause();
    +392        }
    +393        return super.handleUncaughtException(scope, registeredCommand, sender, args, t);
    +394    }
    +395}
     
     
     
    diff --git a/docs/acf-bungee/co/aikar/commands/BungeeCommandCompletions.html b/docs/acf-bungee/co/aikar/commands/BungeeCommandCompletions.html
    index cd19c308..29028492 100644
    --- a/docs/acf-bungee/co/aikar/commands/BungeeCommandCompletions.html
    +++ b/docs/acf-bungee/co/aikar/commands/BungeeCommandCompletions.html
    @@ -158,7 +158,7 @@ extends co.aikar.commands.CommandCompletions<
     
  • diff --git a/docs/acf-bungee/co/aikar/commands/BungeeCommandExecutionContext.html b/docs/acf-bungee/co/aikar/commands/BungeeCommandExecutionContext.html index cdd16efc..be86216d 100644 --- a/docs/acf-bungee/co/aikar/commands/BungeeCommandExecutionContext.html +++ b/docs/acf-bungee/co/aikar/commands/BungeeCommandExecutionContext.html @@ -162,7 +162,7 @@ extends co.aikar.commands.CommandExecutionContext<
  • diff --git a/docs/acf-bungee/co/aikar/commands/BungeeCommandManager.html b/docs/acf-bungee/co/aikar/commands/BungeeCommandManager.html index fa0c3187..03f08bfe 100644 --- a/docs/acf-bungee/co/aikar/commands/BungeeCommandManager.html +++ b/docs/acf-bungee/co/aikar/commands/BungeeCommandManager.html @@ -293,7 +293,7 @@ extends co.aikar.commands.CommandManager<net.md_5.bungee.api.CommandSender,

    Methods inherited from class co.aikar.commands.CommandManager

    -addSupportedLanguage, enableUnstableAPI, formatMessage, generateCommandHelp, generateCommandHelp, generateCommandHelp, generateCommandHelp, getCommandConditions, getCommandReplacements, getCurrentCommandIssuer, getCurrentCommandManager, getCurrentCommandOperationContext, getDefaultExceptionHandler, getDefaultFormatter, getDefaultHelpPerPage, getFormat, getHelpFormatter, getIssuerLocale, getRootCommand, getSupportedLanguages, handleUncaughtException, hasPermission, isLoggingUnhandledExceptions, log, notifyLocaleChange, obtainRootCommand, onLocaleChange, registerDependency, registerDependency, sendMessage, sendMessage, setDefaultExceptionHandler, setDefaultExceptionHandler, setDefaultFormatter, setDefaultHelpPerPage, setFormat, setFormat, setFormat, setHelpFormatter, setIssuerLocale, usePerIssuerLocale, usingPerIssuerLocale
  • +addSupportedLanguage, enableUnstableAPI, formatMessage, generateCommandHelp, generateCommandHelp, generateCommandHelp, generateCommandHelp, getCommandConditions, getCommandReplacements, getCurrentCommandIssuer, getCurrentCommandManager, getCurrentCommandOperationContext, getDefaultExceptionHandler, getDefaultFormatter, getDefaultHelpPerPage, getFormat, getHelpFormatter, getIssuerLocale, getRootCommand, getSupportedLanguages, handleUncaughtException, hasPermission, hasPermission, isLoggingUnhandledExceptions, log, notifyLocaleChange, obtainRootCommand, onLocaleChange, registerDependency, registerDependency, sendMessage, sendMessage, setDefaultExceptionHandler, setDefaultExceptionHandler, setDefaultFormatter, setDefaultHelpPerPage, setFormat, setFormat, setFormat, setHelpFormatter, setIssuerLocale, usePerIssuerLocale, usingPerIssuerLocale


  • -
    public static interface CommandCompletions.AsyncCommandCompletionHandler<C extends CommandCompletionContext>
    +
    public static interface CommandCompletions.AsyncCommandCompletionHandler<C extends CommandCompletionContext>
     extends CommandCompletions.CommandCompletionHandler<C>
  • diff --git a/docs/acf-core/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html b/docs/acf-core/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html index c78c0e3f..885ec98b 100644 --- a/docs/acf-core/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html +++ b/docs/acf-core/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html @@ -108,7 +108,7 @@ var activeTableTab = "activeTableTab";


    -
    public static interface CommandCompletions.CommandCompletionHandler<C extends CommandCompletionContext>
    +
    public static interface CommandCompletions.CommandCompletionHandler<C extends CommandCompletionContext>
  • @@ -154,7 +154,7 @@ var activeTableTab = "activeTableTab";
  • diff --git a/docs/acf-core/co/aikar/commands/CommandCompletions.html b/docs/acf-core/co/aikar/commands/CommandCompletions.html index 7d13aee3..ee4aa849 100644 --- a/docs/acf-core/co/aikar/commands/CommandCompletions.html +++ b/docs/acf-core/co/aikar/commands/CommandCompletions.html @@ -18,7 +18,7 @@ catch(err) { } //--> -var methods = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10}; +var methods = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -214,6 +214,13 @@ extends Register a static list of command completions that will never change. + +void +setDefaultCompletion(String id, + Class... classes) +
    Registers a completion handler such as @players to default apply to all command parameters of the specified types
    + +
  • @@ -259,7 +266,7 @@ extends
  • registerCompletion

    -
    public CommandCompletions.CommandCompletionHandler registerCompletion(String id,
    +
    public CommandCompletions.CommandCompletionHandler registerCompletion(String id,
                                                                           CommandCompletions.CommandCompletionHandler<C> handler)
    Registr a completion handler to provide command completions based on the user input.
    @@ -276,7 +283,7 @@ extends
  • registerAsyncCompletion

    -
    public CommandCompletions.CommandCompletionHandler registerAsyncCompletion(String id,
    +
    public CommandCompletions.CommandCompletionHandler registerAsyncCompletion(String id,
                                                                                CommandCompletions.AsyncCommandCompletionHandler<C> handler)
    Registr a completion handler to provide command completions based on the user input. This handler is declared to be safe to be executed asynchronously. @@ -301,7 +308,7 @@ extends
  • registerStaticCompletion

    -
    public CommandCompletions.CommandCompletionHandler registerStaticCompletion(String id,
    +
    public CommandCompletions.CommandCompletionHandler registerStaticCompletion(String id,
                                                                                 String list)
    Register a static list of command completions that will never change. Like @CommandCompletion, values are | (PIPE) separated. @@ -321,7 +328,7 @@ extends
  • registerStaticCompletion

    -
    public CommandCompletions.CommandCompletionHandler registerStaticCompletion(String id,
    +
    public CommandCompletions.CommandCompletionHandler registerStaticCompletion(String id,
                                                                                 String[] completions)
    Register a static list of command completions that will never change
    @@ -338,7 +345,7 @@ extends
  • registerStaticCompletion

    -
    public CommandCompletions.CommandCompletionHandler registerStaticCompletion(String id,
    +
    public CommandCompletions.CommandCompletionHandler registerStaticCompletion(String id,
                                                                                 Supplier<Collection<String>> supplier)
    Register a static list of command completions that will never change. The list is obtained from the supplier immediately as part of this method call.
    @@ -353,10 +360,10 @@ extends -
      + diff --git a/docs/acf-core/co/aikar/commands/CommandExecutionContext.html b/docs/acf-core/co/aikar/commands/CommandExecutionContext.html index 190d72f7..637071ff 100644 --- a/docs/acf-core/co/aikar/commands/CommandExecutionContext.html +++ b/docs/acf-core/co/aikar/commands/CommandExecutionContext.html @@ -18,7 +18,7 @@ catch(err) { } //--> -var methods = {"i0":10,"i1":42,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":42,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10,"i35":10,"i36":10}; +var methods = {"i0":10,"i1":42,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":42,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10,"i35":10,"i36":10,"i37":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -108,7 +108,7 @@ var activeTableTab = "activeTableTab";


    • -
      public class CommandExecutionContext<CEC extends CommandExecutionContext,I extends CommandIssuer>
      +
      public class CommandExecutionContext<CEC extends CommandExecutionContext,I extends CommandIssuer>
       extends Object
    @@ -266,51 +266,55 @@ extends +Set<String> +getParameterPermissions()  + + Map<String,Object> getPassedArgs()  - + Object getResolvedArg(Class<?>... classes)  - + Object getResolvedArg(String arg)  - + <T> T getResolvedArg(String key, Class<?>... classes)  - + <T extends Annotation>
    boolean
    hasAnnotation(Class<T> cls)  - + boolean hasFlag(String flag)  - + boolean isLastArg()  - + boolean isOptional()  - + String joinArgs()  - + String joinArgs(String sep)  - + String popFirstArg()  - + String popLastArg()  @@ -342,7 +346,7 @@ extends
  • issuer

    -
    protected final I extends CommandIssuer issuer
    +
    protected final I extends CommandIssuer issuer
  • @@ -359,7 +363,7 @@ extends
  • popFirstArg

    -
    public String popFirstArg()
    +
    public String popFirstArg()
  • @@ -368,7 +372,7 @@ extends
  • popLastArg

    -
    public String popLastArg()
    +
    public String popLastArg()
  • @@ -377,7 +381,7 @@ extends
  • getFirstArg

    -
    public String getFirstArg()
    +
    public String getFirstArg()
  • @@ -386,7 +390,7 @@ extends
  • getLastArg

    -
    public String getLastArg()
    +
    public String getLastArg()
  • @@ -395,7 +399,7 @@ extends
  • isLastArg

    -
    public boolean isLastArg()
    +
    public boolean isLastArg()
  • @@ -404,7 +408,7 @@ extends
  • getNumParams

    -
    public int getNumParams()
    +
    public int getNumParams()
  • @@ -413,7 +417,7 @@ extends
  • canOverridePlayerContext

    -
    public boolean canOverridePlayerContext()
    +
    public boolean canOverridePlayerContext()
  • @@ -422,7 +426,7 @@ extends
  • getResolvedArg

    -
    public Object getResolvedArg(String arg)
    +
    public Object getResolvedArg(String arg)
  • @@ -431,7 +435,7 @@ extends
  • getResolvedArg

    -
    public Object getResolvedArg(Class<?>... classes)
    +
    public Object getResolvedArg(Class<?>... classes)
  • @@ -440,17 +444,26 @@ extends
  • getResolvedArg

    -
    public <T> T getResolvedArg(String key,
    +
    public <T> T getResolvedArg(String key,
                                 Class<?>... classes)
  • + + + + @@ -459,7 +472,7 @@ extends
  • hasFlag

    -
    public boolean hasFlag(String flag)
    +
    public boolean hasFlag(String flag)
  • @@ -468,7 +481,7 @@ extends
  • getFlagValue

    -
    public String getFlagValue(String flag,
    +
    public String getFlagValue(String flag,
                                String def)
  • @@ -478,7 +491,7 @@ extends
  • getFlagValue

    -
    public Integer getFlagValue(String flag,
    +
    public Integer getFlagValue(String flag,
                                 Integer def)
  • @@ -488,7 +501,7 @@ extends
  • getFlagValue

    -
    public Long getFlagValue(String flag,
    +
    public Long getFlagValue(String flag,
                              Long def)
  • @@ -498,7 +511,7 @@ extends
  • getFlagValue

    -
    public Float getFlagValue(String flag,
    +
    public Float getFlagValue(String flag,
                               Float def)
  • @@ -508,7 +521,7 @@ extends
  • getFlagValue

    -
    public Double getFlagValue(String flag,
    +
    public Double getFlagValue(String flag,
                                Double def)
  • @@ -518,7 +531,7 @@ extends
  • getIntFlagValue

    -
    public Integer getIntFlagValue(String flag,
    +
    public Integer getIntFlagValue(String flag,
                                    Number def)
  • @@ -528,7 +541,7 @@ extends
  • getLongFlagValue

    -
    public Long getLongFlagValue(String flag,
    +
    public Long getLongFlagValue(String flag,
                                  Number def)
  • @@ -538,7 +551,7 @@ extends
  • getFloatFlagValue

    -
    public Float getFloatFlagValue(String flag,
    +
    public Float getFloatFlagValue(String flag,
                                    Number def)
  • @@ -548,7 +561,7 @@ extends
  • getDoubleFlagValue

    -
    public Double getDoubleFlagValue(String flag,
    +
    public Double getDoubleFlagValue(String flag,
                                      Number def)
  • @@ -558,7 +571,7 @@ extends
  • getBooleanFlagValue

    -
    public Boolean getBooleanFlagValue(String flag)
    +
    public Boolean getBooleanFlagValue(String flag)
  • @@ -567,7 +580,7 @@ extends
  • getBooleanFlagValue

    -
    public Boolean getBooleanFlagValue(String flag,
    +
    public Boolean getBooleanFlagValue(String flag,
                                        Boolean def)
  • @@ -577,7 +590,7 @@ extends
  • getFlagValue

    -
    public Double getFlagValue(String flag,
    +
    public Double getFlagValue(String flag,
                                Number def)
  • @@ -588,7 +601,7 @@ extends

    getAnnotation

    @Deprecated
    -public <T extends Annotation> T getAnnotation(Class<T> cls)
    +public <T extends Annotation> T getAnnotation(Class<T> cls)
    Deprecated. Use getAnnotationValue(Class)
    This method will not support annotation processors!! use getAnnotationValue or hasAnnotation
  • @@ -599,7 +612,7 @@ public <T extends
  • getAnnotationValue

    -
    public <T extends AnnotationString getAnnotationValue(Class<T> cls)
    +
    public <T extends AnnotationString getAnnotationValue(Class<T> cls)
  • @@ -608,7 +621,7 @@ public <T extends
  • getAnnotationValue

    -
    public <T extends AnnotationString getAnnotationValue(Class<T> cls,
    +
    public <T extends AnnotationString getAnnotationValue(Class<T> cls,
                                                             int options)
  • @@ -618,7 +631,7 @@ public <T extends
  • hasAnnotation

    -
    public <T extends Annotation> boolean hasAnnotation(Class<T> cls)
    +
    public <T extends Annotation> boolean hasAnnotation(Class<T> cls)
  • @@ -627,7 +640,7 @@ public <T extends
  • getCmd

    -
    public RegisteredCommand getCmd()
    +
    public RegisteredCommand getCmd()
  • @@ -637,7 +650,7 @@ public <T extends

    getParam

    @Deprecated
    -public Parameter getParam()
    +public Parameter getParam()
    Deprecated. 
  • @@ -647,7 +660,7 @@ public 
  • getIssuer

    -
    public I getIssuer()
    +
    public I getIssuer()
  • @@ -656,7 +669,7 @@ public 
  • getArgs

    -
    public List<StringgetArgs()
    +
    public List<StringgetArgs()
  • @@ -665,7 +678,7 @@ public 
  • getIndex

    -
    public int getIndex()
    +
    public int getIndex()
  • @@ -674,7 +687,7 @@ public 
  • getPassedArgs

    -
    public Map<String,ObjectgetPassedArgs()
    +
    public Map<String,ObjectgetPassedArgs()
  • @@ -683,7 +696,7 @@ public 
  • getFlags

    -
    public Map<String,StringgetFlags()
    +
    public Map<String,StringgetFlags()
  • @@ -692,7 +705,7 @@ public 
  • joinArgs

    -
    public String joinArgs()
    +
    public String joinArgs()
  • @@ -701,7 +714,7 @@ public 
  • joinArgs

    -
    public String joinArgs(String sep)
    +
    public String joinArgs(String sep)
  • diff --git a/docs/acf-core/co/aikar/commands/CommandManager.html b/docs/acf-core/co/aikar/commands/CommandManager.html index c443cc5c..c53192ae 100644 --- a/docs/acf-core/co/aikar/commands/CommandManager.html +++ b/docs/acf-core/co/aikar/commands/CommandManager.html @@ -18,7 +18,7 @@ catch(err) { } //--> -var methods = {"i0":10,"i1":6,"i2":6,"i3":10,"i4":10,"i5":6,"i6":42,"i7":10,"i8":42,"i9":42,"i10":42,"i11":42,"i12":6,"i13":10,"i14":6,"i15":6,"i16":10,"i17":10,"i18":9,"i19":9,"i20":9,"i21":10,"i22":10,"i23":42,"i24":10,"i25":42,"i26":10,"i27":6,"i28":6,"i29":10,"i30":10,"i31":10,"i32":10,"i33":6,"i34":6,"i35":10,"i36":10,"i37":6,"i38":10,"i39":10,"i40":10,"i41":6,"i42":10,"i43":10,"i44":10,"i45":10,"i46":10,"i47":10,"i48":10,"i49":42,"i50":10,"i51":10,"i52":10,"i53":42,"i54":10,"i55":10,"i56":10}; +var methods = {"i0":10,"i1":6,"i2":6,"i3":10,"i4":10,"i5":6,"i6":42,"i7":10,"i8":42,"i9":42,"i10":42,"i11":42,"i12":6,"i13":10,"i14":6,"i15":6,"i16":10,"i17":10,"i18":9,"i19":9,"i20":9,"i21":10,"i22":10,"i23":42,"i24":10,"i25":42,"i26":10,"i27":6,"i28":6,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10,"i34":6,"i35":6,"i36":10,"i37":10,"i38":6,"i39":10,"i40":10,"i41":10,"i42":6,"i43":10,"i44":10,"i45":10,"i46":10,"i47":10,"i48":10,"i49":10,"i50":42,"i51":10,"i52":10,"i53":10,"i54":42,"i55":10,"i56":10,"i57":10}; var tabs = {65535:["t0","All Methods"],1:["t1","Static Methods"],2:["t2","Instance Methods"],4:["t3","Abstract Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -408,53 +408,58 @@ extends boolean +hasPermission(CommandIssuer issuer, + Set<String> permissions)  + + +boolean hasPermission(CommandIssuer issuer, String permission)  - + abstract boolean hasRegisteredCommands()  - + abstract boolean isCommandIssuer(Class<?> type)  - + boolean isLoggingUnhandledExceptions()  - + void log(co.aikar.commands.LogLevel level, String message)  - + abstract void log(co.aikar.commands.LogLevel level, String message, Throwable throwable)  - + void notifyLocaleChange(I issuer, Locale oldLocale, Locale newLocale)  - + RootCommand obtainRootCommand(@NotNull String cmd)  - + void onLocaleChange(IssuerLocaleChangedCallback<I> onChange)  - + abstract void registerCommand(BaseCommand command)
    Registers a command with ACF
    - + <T> void registerDependency(Class<? extends T> clazz, String key, @@ -464,7 +469,7 @@ extends Dependency with the provided instance. - + <T> void registerDependency(Class<? extends T> clazz, T instance) @@ -473,38 +478,38 @@ extends Dependency with the provided instance. - + void sendMessage(CommandIssuer issuer, MessageType type, co.aikar.locales.MessageKeyProvider key, String... replacements)  - + void sendMessage(IT issuerArg, MessageType type, co.aikar.locales.MessageKeyProvider key, String... replacements)  - + void setDefaultExceptionHandler(ExceptionHandler exceptionHandler)
    Sets the default ExceptionHandler that is called when an exception occurs while executing a command, if the command doesn't have it's own exception handler registered.
    - + void setDefaultExceptionHandler(ExceptionHandler exceptionHandler, boolean logExceptions)
    Sets the default ExceptionHandler that is called when an exception occurs while executing a command, if the command doesn't have it's own exception handler registered, and lets you control if ACF should also log the exception still.
    - + void setDefaultFormatter(MF defaultFormatter)  - + void setDefaultHelpPerPage(int defaultHelpPerPage)
    Deprecated.  @@ -512,23 +517,23 @@ extends + void setFormat(MessageType type, FT... colors)  - + void setFormat(MessageType type, int i, FT color)  - + MF setFormat(MessageType type, MF formatter)  - + void setHelpFormatter(CommandHelpFormatter helpFormatter)
    Deprecated.  @@ -536,16 +541,16 @@ extends + Locale setIssuerLocale(IT issuer, Locale locale)  - + boolean usePerIssuerLocale(boolean setting)  - + boolean usingPerIssuerLocale()  @@ -821,7 +826,7 @@ extends
  • getCommandContexts

    -
    public abstract CommandContexts<?> getCommandContexts()
    +
    public abstract CommandContexts<?> getCommandContexts()
    Gets the command contexts manager
    Returns:
    @@ -835,7 +840,7 @@ extends
  • getCommandCompletions

    -
    public abstract CommandCompletions<?> getCommandCompletions()
    +
    public abstract CommandCompletions<?> getCommandCompletions()
    Gets the command completions manager
    Returns:
    @@ -850,7 +855,7 @@ extends

    generateCommandHelp

    @Deprecated
    -public CommandHelp generateCommandHelp(@NotNull
    +public CommandHelp generateCommandHelp(@NotNull
                                                        @NotNull String command)
    Deprecated. Unstable API
  • @@ -862,7 +867,7 @@ public 

    generateCommandHelp

    @Deprecated
    -public CommandHelp generateCommandHelp(CommandIssuer issuer,
    +public CommandHelp generateCommandHelp(CommandIssuer issuer,
                                                        @NotNull
                                                        @NotNull String command)
    Deprecated. Unstable API
    @@ -875,7 +880,7 @@ public 

    generateCommandHelp

    @Deprecated
    -public CommandHelp generateCommandHelp()
    +public CommandHelp generateCommandHelp()
  • Deprecated. Unstable API
  • @@ -886,7 +891,7 @@ public 

    generateCommandHelp

    @Deprecated
    -public CommandHelp generateCommandHelp(CommandIssuer issuer,
    +public CommandHelp generateCommandHelp(CommandIssuer issuer,
                                                        RootCommand rootCommand)
    Deprecated. Unstable API
  • @@ -898,7 +903,7 @@ public 

    getDefaultHelpPerPage

    @Deprecated
    -public int getDefaultHelpPerPage()
    +public int getDefaultHelpPerPage()
    Deprecated. Unstable API
  • @@ -909,7 +914,7 @@ public int 

    setDefaultHelpPerPage

    @Deprecated
    -public void setDefaultHelpPerPage(int defaultHelpPerPage)
    +public void setDefaultHelpPerPage(int defaultHelpPerPage)
    Deprecated. Unstable API
  • @@ -920,7 +925,7 @@ public void 

    setHelpFormatter

    @Deprecated
    -public void setHelpFormatter(CommandHelpFormatter helpFormatter)
    +public void setHelpFormatter(CommandHelpFormatter helpFormatter)
    Deprecated. Unstable API
  • @@ -931,7 +936,7 @@ public void 

    getHelpFormatter

    @Deprecated
    -public CommandHelpFormatter getHelpFormatter()
    +public CommandHelpFormatter getHelpFormatter()
    Deprecated. Unstable API
  • @@ -941,7 +946,7 @@ public 
  • registerCommand

    -
    public abstract void registerCommand(BaseCommand command)
    +
    public abstract void registerCommand(BaseCommand command)
    Registers a command with ACF
    Parameters:
    @@ -955,7 +960,7 @@ public 
  • hasRegisteredCommands

    -
    public abstract boolean hasRegisteredCommands()
    +
    public abstract boolean hasRegisteredCommands()
  • @@ -964,7 +969,7 @@ public 
  • isCommandIssuer

    -
    public abstract boolean isCommandIssuer(Class<?> type)
    +
    public abstract boolean isCommandIssuer(Class<?> type)
  • @@ -973,7 +978,7 @@ public 
  • getCommandIssuer

    -
    public abstract I getCommandIssuer(Object issuer)
    +
    public abstract I getCommandIssuer(Object issuer)
  • @@ -982,7 +987,7 @@ public 
  • createRootCommand

    -
    public abstract RootCommand createRootCommand(String cmd)
    +
    public abstract RootCommand createRootCommand(String cmd)
  • @@ -991,7 +996,7 @@ public 
  • getLocales

    -
    public abstract Locales getLocales()
    +
    public abstract Locales getLocales()
    Returns a Locales Manager to add and modify language tables for your commands.
    Returns:
    @@ -1004,7 +1009,7 @@ public 
  • usingPerIssuerLocale

    -
    public boolean usingPerIssuerLocale()
    +
    public boolean usingPerIssuerLocale()
  • @@ -1013,7 +1018,7 @@ public 
  • usePerIssuerLocale

    -
    public boolean usePerIssuerLocale(boolean setting)
    +
    public boolean usePerIssuerLocale(boolean setting)
  • @@ -1022,7 +1027,7 @@ public 
  • createConditionContext

    -
    public ConditionContext createConditionContext(CommandIssuer issuer,
    +
    public ConditionContext createConditionContext(CommandIssuer issuer,
                                                    String config)
  • @@ -1032,7 +1037,7 @@ public 
  • createCommandContext

    -
    public abstract CommandExecutionContext createCommandContext(RegisteredCommand command,
    +
    public abstract CommandExecutionContext createCommandContext(RegisteredCommand command,
                                                                  CommandParameter parameter,
                                                                  CommandIssuer sender,
                                                                  List<String> args,
    @@ -1046,7 +1051,7 @@ public 
     
  • createCompletionContext

    -
    public abstract CommandCompletionContext createCompletionContext(RegisteredCommand command,
    +
    public abstract CommandCompletionContext createCompletionContext(RegisteredCommand command,
                                                                      CommandIssuer sender,
                                                                      String input,
                                                                      String config,
    @@ -1059,7 +1064,7 @@ public 
     
  • log

    -
    public abstract void log(co.aikar.commands.LogLevel level,
    +
    public abstract void log(co.aikar.commands.LogLevel level,
                              String message,
                              Throwable throwable)
  • @@ -1070,7 +1075,7 @@ public 
  • log

    -
    public void log(co.aikar.commands.LogLevel level,
    +
    public void log(co.aikar.commands.LogLevel level,
                     String message)
  • @@ -1080,12 +1085,12 @@ public 
  • getCommandReplacements

    -
    public CommandReplacements getCommandReplacements()
    +
    public CommandReplacements getCommandReplacements()
    Lets you add custom string replacements that can be applied to annotation values, to reduce duplication/repetition of common values such as permission nodes and command prefixes. - +

    Any replacement registered starts with a % - +

    So for ex @CommandPermission("%staff")

    Returns:
    @@ -1093,13 +1098,23 @@ public 
  • + + + + @@ -1109,7 +1124,7 @@ public 
  • getRootCommand

    -
    public RootCommand getRootCommand(@NotNull
    +
    public RootCommand getRootCommand(@NotNull
                                       @NotNull String cmd)
  • @@ -1119,7 +1134,7 @@ public 
  • obtainRootCommand

    -
    public RootCommand obtainRootCommand(@NotNull
    +
    public RootCommand obtainRootCommand(@NotNull
                                          @NotNull String cmd)
  • @@ -1129,7 +1144,7 @@ public 
  • getRegisteredRootCommands

    -
    public abstract Collection<RootCommandgetRegisteredRootCommands()
    +
    public abstract Collection<RootCommandgetRegisteredRootCommands()
  • @@ -1138,7 +1153,7 @@ public 
  • createRegisteredCommand

    -
    public RegisteredCommand createRegisteredCommand(BaseCommand command,
    +
    public RegisteredCommand createRegisteredCommand(BaseCommand command,
                                                      String cmdName,
                                                      Method method,
                                                      String prefSubCommand)
    @@ -1150,7 +1165,7 @@ public 
  • setDefaultExceptionHandler

    -
    public void setDefaultExceptionHandler(ExceptionHandler exceptionHandler)
    +
    public void setDefaultExceptionHandler(ExceptionHandler exceptionHandler)
    Sets the default ExceptionHandler that is called when an exception occurs while executing a command, if the command doesn't have it's own exception handler registered.
    Parameters:
    @@ -1164,7 +1179,7 @@ public 
  • setDefaultExceptionHandler

    -
    public void setDefaultExceptionHandler(ExceptionHandler exceptionHandler,
    +
    public void setDefaultExceptionHandler(ExceptionHandler exceptionHandler,
                                            boolean logExceptions)
    Sets the default ExceptionHandler that is called when an exception occurs while executing a command, if the command doesn't have it's own exception handler registered, and lets you control if ACF should also log the exception still.

    @@ -1182,7 +1197,7 @@ public 

  • isLoggingUnhandledExceptions

    -
    public boolean isLoggingUnhandledExceptions()
    +
    public boolean isLoggingUnhandledExceptions()
  • @@ -1191,7 +1206,7 @@ public 
  • getDefaultExceptionHandler

    -
    public ExceptionHandler getDefaultExceptionHandler()
    +
    public ExceptionHandler getDefaultExceptionHandler()
    Gets the current default exception handler, might be null.
    Returns:
    @@ -1205,7 +1220,7 @@ public 
  • handleUncaughtException

    -
    protected boolean handleUncaughtException(BaseCommand scope,
    +
    protected boolean handleUncaughtException(BaseCommand scope,
                                               RegisteredCommand registeredCommand,
                                               CommandIssuer sender,
                                               List<String> args,
    @@ -1220,7 +1235,7 @@ public 
     
  • sendMessage

    -
    public void sendMessage(IT issuerArg,
    +
    public void sendMessage(IT issuerArg,
                             MessageType type,
                             co.aikar.locales.MessageKeyProvider key,
                             String... replacements)
    @@ -1232,7 +1247,7 @@ public 
  • sendMessage

    -
    public void sendMessage(CommandIssuer issuer,
    +
    public void sendMessage(CommandIssuer issuer,
                             MessageType type,
                             co.aikar.locales.MessageKeyProvider key,
                             String... replacements)
    @@ -1244,7 +1259,7 @@ public 
  • formatMessage

    -
    public String formatMessage(CommandIssuer issuer,
    +
    public String formatMessage(CommandIssuer issuer,
                                 MessageType type,
                                 co.aikar.locales.MessageKeyProvider key,
                                 String... replacements)
    @@ -1256,7 +1271,7 @@ public 
  • onLocaleChange

    -
    public void onLocaleChange(IssuerLocaleChangedCallback<I> onChange)
    +
    public void onLocaleChange(IssuerLocaleChangedCallback<I> onChange)
  • @@ -1267,7 +1282,7 @@ public 
  • notifyLocaleChange

    -
    public void notifyLocaleChange(I issuer,
    +
    public void notifyLocaleChange(I issuer,
                                    Locale oldLocale,
                                    Locale newLocale)
  • @@ -1280,7 +1295,7 @@ public 
  • setIssuerLocale

    -
    public Locale setIssuerLocale(IT issuer,
    +
    public Locale setIssuerLocale(IT issuer,
                                   Locale locale)
  • @@ -1290,7 +1305,7 @@ public 
  • getIssuerLocale

    -
    public Locale getIssuerLocale(CommandIssuer issuer)
    +
    public Locale getIssuerLocale(CommandIssuer issuer)
  • @@ -1299,7 +1314,7 @@ public 
  • getSupportedLanguages

    -
    public Set<LocalegetSupportedLanguages()
    +
    public Set<LocalegetSupportedLanguages()
    Gets a list of all currently supported languages for this manager. These locales will be automatically loaded from
    @@ -1313,7 +1328,7 @@ public 
  • addSupportedLanguage

    -
    public void addSupportedLanguage(Locale locale)
    +
    public void addSupportedLanguage(Locale locale)
    Adds a new locale to the list of automatic Locales to load Message Bundles for. All bundles loaded under the previous supported languages will now automatically load for this new locale too.
    @@ -1330,7 +1345,7 @@ public 
  • registerDependency

    -
    public <T> void registerDependency(Class<? extends T> clazz,
    +
    public <T> void registerDependency(Class<? extends T> clazz,
                                        T instance)
    Registers an instance of a class to be registered as an injectable dependency.
    The command manager will attempt to inject all fields in a command class that are annotated with @@ -1352,7 +1367,7 @@ public 
  • registerDependency

    -
    public <T> void registerDependency(Class<? extends T> clazz,
    +
    public <T> void registerDependency(Class<? extends T> clazz,
                                        String key,
                                        T instance)
    Registers an instance of a class to be registered as an injectable dependency.
    @@ -1375,7 +1390,7 @@ public 

    enableUnstableAPI

    @Deprecated
    -public void enableUnstableAPI(String api)
    +public void enableUnstableAPI(String api)
    Deprecated. Use this with caution! If you enable and use Unstable API's, your next compile using ACF may require you to update your implementation to those unstable API's
  • @@ -1386,7 +1401,7 @@ public void 
  • getCommandPrefix

    -
    public String getCommandPrefix(CommandIssuer issuer)
    +
    public String getCommandPrefix(CommandIssuer issuer)
  • diff --git a/docs/acf-core/co/aikar/commands/CommandOperationContext.html b/docs/acf-core/co/aikar/commands/CommandOperationContext.html index 76de0b12..2685c8ce 100644 --- a/docs/acf-core/co/aikar/commands/CommandOperationContext.html +++ b/docs/acf-core/co/aikar/commands/CommandOperationContext.html @@ -108,7 +108,7 @@ var activeTableTab = "activeTableTab";


  • -
    public class CommandOperationContext<I extends CommandIssuer>
    +
    public class CommandOperationContext<I extends CommandIssuer>
     extends Object
    Holds information about the currently executing command on this thread
  • @@ -210,7 +210,7 @@ extends
  • getCommandManager

    -
    public CommandManager getCommandManager()
    +
    public CommandManager getCommandManager()
  • @@ -219,7 +219,7 @@ extends
  • getCommandIssuer

    -
    public I getCommandIssuer()
    +
    public I getCommandIssuer()
  • @@ -228,7 +228,7 @@ extends
  • getCommand

    -
    public BaseCommand getCommand()
    +
    public BaseCommand getCommand()
  • @@ -237,7 +237,7 @@ extends
  • getCommandLabel

    -
    public String getCommandLabel()
    +
    public String getCommandLabel()
  • @@ -246,7 +246,7 @@ extends
  • getArgs

    -
    public String[] getArgs()
    +
    public String[] getArgs()
  • @@ -255,7 +255,7 @@ extends
  • isAsync

    -
    public boolean isAsync()
    +
    public boolean isAsync()
  • @@ -264,7 +264,7 @@ extends
  • setRegisteredCommand

    -
    public void setRegisteredCommand(RegisteredCommand registeredCommand)
    +
    public void setRegisteredCommand(RegisteredCommand registeredCommand)
  • @@ -273,7 +273,7 @@ extends
  • getRegisteredCommand

    -
    public RegisteredCommand getRegisteredCommand()
    +
    public RegisteredCommand getRegisteredCommand()
  • @@ -283,7 +283,7 @@ extends

    getAnnotation

    @Deprecated
    -public <T extends Annotation> T getAnnotation(Class<T> anno)
    +public <T extends Annotation> T getAnnotation(Class<T> anno)
  • Deprecated. Use getAnnotationValue(Class)
    This method will not support annotation processors!! use getAnnotationValue or hasAnnotation
  • @@ -294,7 +294,7 @@ public <T extends
  • getAnnotationValue

    -
    public <T extends AnnotationString getAnnotationValue(Class<T> cls)
    +
    public <T extends AnnotationString getAnnotationValue(Class<T> cls)
  • @@ -303,7 +303,7 @@ public <T extends
  • getAnnotationValue

    -
    public <T extends AnnotationString getAnnotationValue(Class<T> cls,
    +
    public <T extends AnnotationString getAnnotationValue(Class<T> cls,
                                                             int options)
  • @@ -313,7 +313,7 @@ public <T extends
  • hasAnnotation

    -
    public boolean hasAnnotation(Class<? extends Annotation> anno)
    +
    public boolean hasAnnotation(Class<? extends Annotation> anno)
  • diff --git a/docs/acf-core/co/aikar/commands/CommandParameter.html b/docs/acf-core/co/aikar/commands/CommandParameter.html index b46fb9b6..20048f0b 100644 --- a/docs/acf-core/co/aikar/commands/CommandParameter.html +++ b/docs/acf-core/co/aikar/commands/CommandParameter.html @@ -18,7 +18,7 @@ catch(err) { } //--> -var methods = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10}; +var methods = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -108,7 +108,7 @@ var activeTableTab = "activeTableTab";


  • -
    public class CommandParameter<CEC extends CommandExecutionContext<CEC,? extends CommandIssuer>>
    +
    public class CommandParameter<CEC extends CommandExecutionContext<CEC,? extends CommandIssuer>>
     extends Object
  • @@ -185,82 +185,86 @@ extends getParamIndex()  +Set<String> +getRequiredPermissions()  + + ContextResolver<?,CEC> getResolver()  - + String getSyntax()  - + Class<?> getType()  - + String[] getValues()  - + boolean isCommandIssuer()  - + boolean isOptional()  - + boolean isOptionalResolver()  - + boolean requiresInput()  - + void setCanConsumeInput(boolean canConsumeInput)  - + void setCommandIssuer(boolean commandIssuer)  - + void setConditions(String conditions)  - + void setDefaultValue(String defaultValue)  - + void setDescription(String description)  - + void setFlags(Map<String,String> flags)  - + void setOptional(boolean optional)  - + void setOptionalResolver(boolean optionalResolver)  - + void setRequiresInput(boolean requiresInput)  - + void setResolver(ContextResolver<?,CEC> resolver)  - + void setSyntax(String syntax)  - + void setValues(String[] values)  @@ -292,7 +296,7 @@ extends
  • CommandParameter

    -
    public CommandParameter(RegisteredCommand<CEC> command,
    +
    public CommandParameter(RegisteredCommand<CEC> command,
                             Parameter param,
                             int paramIndex,
                             boolean isLast)
    @@ -312,7 +316,7 @@ extends
  • getParameter

    -
    public Parameter getParameter()
    +
    public Parameter getParameter()
  • @@ -321,7 +325,7 @@ extends
  • getType

    -
    public Class<?> getType()
    +
    public Class<?> getType()
  • @@ -330,7 +334,7 @@ extends
  • getName

    -
    public String getName()
    +
    public String getName()
  • @@ -339,7 +343,7 @@ extends
  • getManager

    -
    public CommandManager getManager()
    +
    public CommandManager getManager()
  • @@ -348,7 +352,7 @@ extends
  • getParamIndex

    -
    public int getParamIndex()
    +
    public int getParamIndex()
  • @@ -357,7 +361,7 @@ extends
  • getResolver

    -
    public ContextResolver<?,CECgetResolver()
    +
    public ContextResolver<?,CECgetResolver()
  • @@ -366,7 +370,7 @@ extends
  • setResolver

    -
    public void setResolver(ContextResolver<?,CEC> resolver)
    +
    public void setResolver(ContextResolver<?,CEC> resolver)
  • @@ -375,7 +379,7 @@ extends
  • isOptional

    -
    public boolean isOptional()
    +
    public boolean isOptional()
  • @@ -384,7 +388,7 @@ extends
  • setOptional

    -
    public void setOptional(boolean optional)
    +
    public void setOptional(boolean optional)
  • @@ -393,7 +397,7 @@ extends
  • getDescription

    -
    public String getDescription()
    +
    public String getDescription()
  • @@ -402,7 +406,7 @@ extends
  • setDescription

    -
    public void setDescription(String description)
    +
    public void setDescription(String description)
  • @@ -411,7 +415,7 @@ extends
  • getDefaultValue

    -
    public String getDefaultValue()
    +
    public String getDefaultValue()
  • @@ -420,7 +424,7 @@ extends
  • setDefaultValue

    -
    public void setDefaultValue(String defaultValue)
    +
    public void setDefaultValue(String defaultValue)
  • @@ -429,7 +433,7 @@ extends
  • isCommandIssuer

    -
    public boolean isCommandIssuer()
    +
    public boolean isCommandIssuer()
  • @@ -438,7 +442,7 @@ extends
  • setCommandIssuer

    -
    public void setCommandIssuer(boolean commandIssuer)
    +
    public void setCommandIssuer(boolean commandIssuer)
  • @@ -447,7 +451,7 @@ extends
  • getValues

    -
    public String[] getValues()
    +
    public String[] getValues()
  • @@ -456,7 +460,7 @@ extends
  • setValues

    -
    public void setValues(String[] values)
    +
    public void setValues(String[] values)
  • @@ -465,7 +469,7 @@ extends
  • getFlags

    -
    public Map<String,StringgetFlags()
    +
    public Map<String,StringgetFlags()
  • @@ -474,7 +478,7 @@ extends
  • setFlags

    -
    public void setFlags(Map<String,String> flags)
    +
    public void setFlags(Map<String,String> flags)
  • @@ -483,7 +487,7 @@ extends
  • canConsumeInput

    -
    public boolean canConsumeInput()
    +
    public boolean canConsumeInput()
  • @@ -492,7 +496,7 @@ extends
  • setCanConsumeInput

    -
    public void setCanConsumeInput(boolean canConsumeInput)
    +
    public void setCanConsumeInput(boolean canConsumeInput)
  • @@ -501,7 +505,7 @@ extends
  • setOptionalResolver

    -
    public void setOptionalResolver(boolean optionalResolver)
    +
    public void setOptionalResolver(boolean optionalResolver)
  • @@ -510,7 +514,7 @@ extends
  • isOptionalResolver

    -
    public boolean isOptionalResolver()
    +
    public boolean isOptionalResolver()
  • @@ -519,7 +523,7 @@ extends
  • requiresInput

    -
    public boolean requiresInput()
    +
    public boolean requiresInput()
  • @@ -528,7 +532,7 @@ extends
  • setRequiresInput

    -
    public void setRequiresInput(boolean requiresInput)
    +
    public void setRequiresInput(boolean requiresInput)
  • @@ -537,7 +541,7 @@ extends
  • getSyntax

    -
    public String getSyntax()
    +
    public String getSyntax()
  • @@ -546,7 +550,7 @@ extends
  • setSyntax

    -
    public void setSyntax(String syntax)
    +
    public void setSyntax(String syntax)
  • @@ -555,16 +559,25 @@ extends
  • getConditions

    -
    public String getConditions()
    +
    public String getConditions()
  • -
      + + + + + diff --git a/docs/acf-core/co/aikar/commands/MessageKeys.html b/docs/acf-core/co/aikar/commands/MessageKeys.html index fd7a7080..e02eb27e 100644 --- a/docs/acf-core/co/aikar/commands/MessageKeys.html +++ b/docs/acf-core/co/aikar/commands/MessageKeys.html @@ -199,15 +199,18 @@ implements co.aikar.locales.MessageKeyProvider
    PERMISSION_DENIED  +PERMISSION_DENIED_PARAMETER  + + PLEASE_SPECIFY_AT_LEAST  - + PLEASE_SPECIFY_AT_MOST  - + PLEASE_SPECIFY_ONE_OF  - + UNKNOWN_COMMAND  @@ -280,13 +283,22 @@ the order they are declared.
  • public static final MessageKeys PERMISSION_DENIED
  • + + + + @@ -295,7 +307,7 @@ the order they are declared. @@ -304,7 +316,7 @@ the order they are declared. @@ -313,7 +325,7 @@ the order they are declared. @@ -322,7 +334,7 @@ the order they are declared. @@ -331,7 +343,7 @@ the order they are declared. @@ -340,7 +352,7 @@ the order they are declared. @@ -349,7 +361,7 @@ the order they are declared. @@ -358,7 +370,7 @@ the order they are declared. @@ -367,7 +379,7 @@ the order they are declared. @@ -376,7 +388,7 @@ the order they are declared. @@ -385,7 +397,7 @@ the order they are declared. @@ -394,7 +406,7 @@ the order they are declared. @@ -403,7 +415,7 @@ the order they are declared. @@ -412,7 +424,7 @@ the order they are declared. @@ -421,7 +433,7 @@ the order they are declared. @@ -430,7 +442,7 @@ the order they are declared. @@ -439,7 +451,7 @@ the order they are declared. @@ -448,7 +460,7 @@ the order they are declared. @@ -457,7 +469,7 @@ the order they are declared. @@ -466,7 +478,7 @@ the order they are declared. @@ -475,7 +487,7 @@ the order they are declared. @@ -484,7 +496,7 @@ the order they are declared.
  • @@ -543,7 +555,7 @@ not permitted.)
    • getMessageKey

      -
      public co.aikar.locales.MessageKey getMessageKey()
      +
      public co.aikar.locales.MessageKey getMessageKey()
      Specified by:
      getMessageKey in interface co.aikar.locales.MessageKeyProvider
      diff --git a/docs/acf-core/co/aikar/commands/RegisteredCommand.html b/docs/acf-core/co/aikar/commands/RegisteredCommand.html index 14c503ed..dd952ed5 100644 --- a/docs/acf-core/co/aikar/commands/RegisteredCommand.html +++ b/docs/acf-core/co/aikar/commands/RegisteredCommand.html @@ -265,7 +265,7 @@ extends

      getPermission

      @Deprecated
      -public String getPermission()
      +public String getPermission()
    Deprecated. 
    See Also:
    @@ -279,7 +279,7 @@ public 
  • getRequiredPermissions

    -
    public Set<StringgetRequiredPermissions()
    +
    public Set<StringgetRequiredPermissions()
  • @@ -288,7 +288,7 @@ public 
  • requiresPermission

    -
    public boolean requiresPermission(String permission)
    +
    public boolean requiresPermission(String permission)
  • @@ -297,7 +297,7 @@ public 
  • getPrefSubCommand

    -
    public String getPrefSubCommand()
    +
    public String getPrefSubCommand()
  • @@ -306,7 +306,7 @@ public 
  • getSyntaxText

    -
    public String getSyntaxText()
    +
    public String getSyntaxText()
  • @@ -315,7 +315,7 @@ public 
  • getHelpText

    -
    public String getHelpText()
    +
    public String getHelpText()
  • @@ -324,7 +324,7 @@ public 
  • isPrivate

    -
    public boolean isPrivate()
    +
    public boolean isPrivate()
  • @@ -333,7 +333,7 @@ public 
  • getCommand

    -
    public String getCommand()
    +
    public String getCommand()
  • @@ -342,7 +342,7 @@ public 
  • addSubcommand

    -
    public void addSubcommand(String cmd)
    +
    public void addSubcommand(String cmd)
  • @@ -351,7 +351,7 @@ public 
  • addSubcommands

    -
    public void addSubcommands(Collection<String> cmd)
    +
    public void addSubcommands(Collection<String> cmd)
  • @@ -360,7 +360,7 @@ public 
  • getAnnotation

    -
    public <T extends Annotation> T getAnnotation(Class<T> annotation)
    +
    public <T extends Annotation> T getAnnotation(Class<T> annotation)
  • diff --git a/docs/acf-core/co/aikar/commands/annotation/CommandPermission.html b/docs/acf-core/co/aikar/commands/annotation/CommandPermission.html index bf9c02a1..e972375a 100644 --- a/docs/acf-core/co/aikar/commands/annotation/CommandPermission.html +++ b/docs/acf-core/co/aikar/commands/annotation/CommandPermission.html @@ -93,10 +93,10 @@

    @Retention(value=RUNTIME)
    - @Target(value={METHOD,TYPE})
    + @Target(value={METHOD,TYPE,PARAMETER})
     public @interface CommandPermission
    Sets the permission required to perform this command. - +

    Permission format will vary based on implementation platform

  • diff --git a/docs/acf-core/co/aikar/commands/class-use/CommandIssuer.html b/docs/acf-core/co/aikar/commands/class-use/CommandIssuer.html index 5501b281..84ec62f8 100644 --- a/docs/acf-core/co/aikar/commands/class-use/CommandIssuer.html +++ b/docs/acf-core/co/aikar/commands/class-use/CommandIssuer.html @@ -348,95 +348,100 @@ boolean +CommandManager.hasPermission(CommandIssuer issuer, + Set<String> permissions)  + + +boolean CommandManager.hasPermission(CommandIssuer issuer, String permission)  - + void BaseCommand.help(CommandIssuer issuer, String[] args)  - + void CommandHelpFormatter.printDetailedHelpCommand(CommandHelp help, CommandIssuer issuer, HelpEntry entry)  - + void CommandHelpFormatter.printDetailedHelpFooter(CommandHelp help, CommandIssuer issuer, HelpEntry entry)  - + void CommandHelpFormatter.printDetailedHelpHeader(CommandHelp help, CommandIssuer issuer, HelpEntry entry)  - + void CommandHelpFormatter.printDetailedParameter(CommandHelp help, CommandIssuer issuer, HelpEntry entry, CommandParameter param)  - + void CommandHelpFormatter.printHelpCommand(CommandHelp help, CommandIssuer issuer, HelpEntry entry)  - + void CommandHelpFormatter.printHelpFooter(CommandHelp help, CommandIssuer issuer)  - + void CommandHelpFormatter.printHelpHeader(CommandHelp help, CommandIssuer issuer)  - + void CommandHelpFormatter.printSearchEntry(CommandHelp help, CommandIssuer issuer, HelpEntry page)  - + void CommandHelpFormatter.printSearchFooter(CommandHelp help, CommandIssuer issuer)  - + void CommandHelpFormatter.printSearchHeader(CommandHelp help, CommandIssuer issuer)  - + void CommandManager.sendMessage(CommandIssuer issuer, MessageType type, co.aikar.locales.MessageKeyProvider key, String... replacements)  - + void CommandHelp.showHelp(CommandIssuer issuer)  - + void BaseCommand.showSyntax(CommandIssuer issuer, RegisteredCommand<?> cmd)  - + List<String> ForwardingCommand.tabComplete(CommandIssuer issuer, RootCommand rootCommand, String[] args, boolean isAsync)  - + List<String> BaseCommand.tabComplete(CommandIssuer issuer, String commandLabel, @@ -444,7 +449,7 @@
    Gets tab completed data from the given command from the user.
    - + List<String> BaseCommand.tabComplete(CommandIssuer issuer, String commandLabel, diff --git a/docs/acf-core/index-all.html b/docs/acf-core/index-all.html index 7d6b3672..aa646f97 100644 --- a/docs/acf-core/index-all.html +++ b/docs/acf-core/index-all.html @@ -799,6 +799,8 @@
    Override this to control replacements
    +
    getParameterPermissions() - Method in class co.aikar.commands.CommandExecutionContext
    +
     
    getParameters() - Method in class co.aikar.commands.HelpEntry
     
    getParameterSyntax() - Method in class co.aikar.commands.HelpEntry
    @@ -825,6 +827,8 @@
     
    getRequiredPermissions() - Method in class co.aikar.commands.BaseCommand
     
    +
    getRequiredPermissions() - Method in class co.aikar.commands.CommandParameter
    +
     
    getRequiredPermissions() - Method in class co.aikar.commands.ForwardingCommand
     
    getRequiredPermissions() - Method in class co.aikar.commands.RegisteredCommand
    @@ -952,6 +956,8 @@
    Has permission node
    +
    hasPermission(CommandIssuer, Set<String>) - Method in class co.aikar.commands.CommandManager
    +
     
    hasPermission(CommandIssuer, String) - Method in class co.aikar.commands.CommandManager
     
    hasPermission(Object) - Method in class co.aikar.commands.ForwardingCommand
    @@ -1713,6 +1719,10 @@
     
    setContextFlags(Class<?>, String) - Method in class co.aikar.commands.BaseCommand
     
    +
    setDefaultCompletion(String, Class...) - Method in class co.aikar.commands.CommandCompletions
    +
    +
    Registers a completion handler such as @players to default apply to all command parameters of the specified types
    +
    setDefaultExceptionHandler(ExceptionHandler) - Method in class co.aikar.commands.CommandManager
    Sets the default ExceptionHandler that is called when an exception occurs while executing a command, if the command doesn't have it's own exception handler registered.
    diff --git a/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html b/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html index 2471cbd8..b3fe8a64 100644 --- a/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html +++ b/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html @@ -688,7 +688,7 @@ 680 * @return All results to complete the command. 681 */ 682 private List<String> completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) { -683 if (!cmd.hasPermission(issuer) || args.length > cmd.consumeInputResolvers || args.length == 0 || cmd.complete == null) { +683 if (!cmd.hasPermission(issuer) || args.length > cmd.consumeInputResolvers || args.length == 0) { 684 return Collections.emptyList(); 685 } 686 @@ -796,7 +796,7 @@ 788 } 789 790 public boolean hasPermission(CommandIssuer issuer) { -791 return getRequiredPermissions().isEmpty() || getRequiredPermissions().stream().allMatch(permission -> manager.hasPermission(issuer, permission)); +791 return this.manager.hasPermission(issuer, getRequiredPermissions()); 792 } 793 794 public Set<String> getRequiredPermissions() { diff --git a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.AsyncCommandCompletionHandler.html b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.AsyncCommandCompletionHandler.html index a2053fdb..616f583a 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.AsyncCommandCompletionHandler.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.AsyncCommandCompletionHandler.html @@ -47,207 +47,253 @@ 039 040@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"}) 041public class CommandCompletions<C extends CommandCompletionContext> { -042 private final CommandManager manager; -043 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); -044 private Map<Class, String> defaultCompletions = new HashMap<>(); -045 -046 public CommandCompletions(CommandManager manager) { -047 this.manager = manager; -048 registerAsyncCompletion("nothing", c -> Collections.emptyList()); -049 registerAsyncCompletion("range", (c) -> { -050 String config = c.getConfig(); -051 if (config == null) { -052 return Collections.emptyList(); -053 } -054 final String[] ranges = ACFPatterns.DASH.split(config); -055 int start; -056 int end; -057 if (ranges.length != 2) { -058 start = 0; -059 end = ACFUtil.parseInt(ranges[0], 0); -060 } else { -061 start = ACFUtil.parseInt(ranges[0], 0); -062 end = ACFUtil.parseInt(ranges[1], 0); -063 } -064 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); -065 }); -066 List<String> timeunits = Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"); -067 registerAsyncCompletion("timeunits", (c) -> timeunits); -068 } -069 -070 /** -071 * Registr a completion handler to provide command completions based on the user input. -072 * -073 * @param id -074 * @param handler -075 * @return -076 */ -077 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { -078 return this.completionMap.put("@" + id.toLowerCase(), handler); -079 } -080 -081 /** -082 * Registr a completion handler to provide command completions based on the user input. -083 * This handler is declared to be safe to be executed asynchronously. -084 * <p> -085 * Not all platforms support this, so if the platform does not support asynchronous execution, -086 * your handler will be executed on the main thread. -087 * <p> -088 * Use this anytime your handler does not need to access state that is not considered thread safe. +042 private static final String DEFAULT_ENUM_ID = "@__defaultenum__"; +043 private final CommandManager manager; +044 // TODO: use a CompletionProvider that can return a delegated Id or provide values such as enum support +045 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); +046 private Map<Class, String> defaultCompletions = new HashMap<>(); +047 +048 public CommandCompletions(CommandManager manager) { +049 this.manager = manager; +050 registerAsyncCompletion("nothing", c -> Collections.emptyList()); +051 registerAsyncCompletion("range", (c) -> { +052 String config = c.getConfig(); +053 if (config == null) { +054 return Collections.emptyList(); +055 } +056 final String[] ranges = ACFPatterns.DASH.split(config); +057 int start; +058 int end; +059 if (ranges.length != 2) { +060 start = 0; +061 end = ACFUtil.parseInt(ranges[0], 0); +062 } else { +063 start = ACFUtil.parseInt(ranges[0], 0); +064 end = ACFUtil.parseInt(ranges[1], 0); +065 } +066 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); +067 }); +068 List<String> timeunits = Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"); +069 registerAsyncCompletion("timeunits", (c) -> timeunits); +070 } +071 +072 /** +073 * Registr a completion handler to provide command completions based on the user input. +074 * +075 * @param id +076 * @param handler +077 * @return +078 */ +079 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { +080 return this.completionMap.put(prepareCompletionId(id), handler); +081 } +082 +083 /** +084 * Registr a completion handler to provide command completions based on the user input. +085 * This handler is declared to be safe to be executed asynchronously. +086 * <p> +087 * Not all platforms support this, so if the platform does not support asynchronous execution, +088 * your handler will be executed on the main thread. 089 * <p> -090 * Use context.isAsync() to determine if you are async or not. -091 * -092 * @param id -093 * @param handler -094 * @return -095 */ -096 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { -097 return this.completionMap.put("@" + id.toLowerCase(), handler); -098 } -099 -100 /** -101 * Register a static list of command completions that will never change. -102 * Like @CommandCompletion, values are | (PIPE) separated. -103 * <p> -104 * Example: foo|bar|baz -105 * -106 * @param id -107 * @param list -108 * @return -109 */ -110 public CommandCompletionHandler registerStaticCompletion(String id, String list) { -111 return registerStaticCompletion(id, ACFPatterns.PIPE.split(list)); -112 } -113 -114 /** -115 * Register a static list of command completions that will never change -116 * -117 * @param id -118 * @param completions -119 * @return -120 */ -121 public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) { -122 return registerStaticCompletion(id, Arrays.asList(completions)); -123 } -124 -125 /** -126 * Register a static list of command completions that will never change. The list is obtained from the supplier -127 * immediately as part of this method call. -128 * -129 * @param id -130 * @param supplier -131 * @return -132 */ -133 public CommandCompletionHandler registerStaticCompletion(String id, Supplier<Collection<String>> supplier) { -134 return registerStaticCompletion(id, supplier.get()); -135 } -136 -137 /** -138 * Register a static list of command completions that will never change -139 * -140 * @param id -141 * @param completions -142 * @return -143 */ -144 public CommandCompletionHandler registerStaticCompletion(String id, Collection<String> completions) { -145 return registerAsyncCompletion(id, x -> completions); -146 } -147 -148 /** -149 * @param id -150 * @param classes -151 * @return -152 * @deprecated Feature Not done yet -153 */ -154 CommandCompletionHandler setDefaultCompletion(String id, Class... classes) { -155 // get completion with specified id -156 id = id.toLowerCase(); -157 CommandCompletionHandler completion = completionMap.get(id); -158 -159 if (completion == null) { -160 // Throw something because no completion with specified id -161 throw new IllegalStateException("Completion not registered for " + id); -162 } -163 -164 for (Class clazz : classes) { -165 defaultCompletions.put(clazz, id); +090 * Use this anytime your handler does not need to access state that is not considered thread safe. +091 * <p> +092 * Use context.isAsync() to determine if you are async or not. +093 * +094 * @param id +095 * @param handler +096 * @return +097 */ +098 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { +099 return this.completionMap.put(prepareCompletionId(id), handler); +100 } +101 +102 /** +103 * Register a static list of command completions that will never change. +104 * Like @CommandCompletion, values are | (PIPE) separated. +105 * <p> +106 * Example: foo|bar|baz +107 * +108 * @param id +109 * @param list +110 * @return +111 */ +112 public CommandCompletionHandler registerStaticCompletion(String id, String list) { +113 return registerStaticCompletion(id, ACFPatterns.PIPE.split(list)); +114 } +115 +116 /** +117 * Register a static list of command completions that will never change +118 * +119 * @param id +120 * @param completions +121 * @return +122 */ +123 public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) { +124 return registerStaticCompletion(id, Arrays.asList(completions)); +125 } +126 +127 /** +128 * Register a static list of command completions that will never change. The list is obtained from the supplier +129 * immediately as part of this method call. +130 * +131 * @param id +132 * @param supplier +133 * @return +134 */ +135 public CommandCompletionHandler registerStaticCompletion(String id, Supplier<Collection<String>> supplier) { +136 return registerStaticCompletion(id, supplier.get()); +137 } +138 +139 /** +140 * Register a static list of command completions that will never change +141 * +142 * @param id +143 * @param completions +144 * @return +145 */ +146 public CommandCompletionHandler registerStaticCompletion(String id, Collection<String> completions) { +147 return registerAsyncCompletion(id, x -> completions); +148 } +149 +150 /** +151 * Registers a completion handler such as @players to default apply to all command parameters of the specified types +152 * <p> +153 * This enables automatic completion support for parameters without manually defining it for custom objects +154 * +155 * @param id +156 * @param classes +157 */ +158 public void setDefaultCompletion(String id, Class... classes) { +159 // get completion with specified id +160 id = prepareCompletionId(id); +161 CommandCompletionHandler completion = completionMap.get(id); +162 +163 if (completion == null) { +164 // Throw something because no completion with specified id +165 throw new IllegalStateException("Completion not registered for " + id); 166 } 167 -168 return completion; -169 } -170 -171 @NotNull -172 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { -173 String[] completions = ACFPatterns.SPACE.split(cmd.complete); -174 final int argIndex = args.length - 1; -175 -176 String input = args[argIndex]; +168 for (Class clazz : classes) { +169 defaultCompletions.put(clazz, id); +170 } +171 } +172 +173 @NotNull +174 private static String prepareCompletionId(String id) { +175 return (id.startsWith("@") ? "" : "@") + id.toLowerCase(); +176 } 177 -178 String completion = argIndex < completions.length ? completions[argIndex] : null; -179 if (completion == null && completions.length > 0) { -180 completion = completions[completions.length - 1]; -181 } -182 if (completion == null) { -183 return Collections.singletonList(input); -184 } -185 -186 return getCompletionValues(cmd, sender, completion, args, isAsync); -187 } -188 -189 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { -190 completion = manager.getCommandReplacements().replace(completion); -191 -192 List<String> allCompletions = new ArrayList<>(); -193 String input = args.length > 0 ? args[args.length - 1] : ""; -194 -195 for (String value : ACFPatterns.PIPE.split(completion)) { -196 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); -197 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); -198 if (handler != null) { -199 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { -200 ACFUtil.sneaky(new SyncCompletionRequired()); -201 return null; -202 } -203 String config = complete.length == 1 ? null : complete[1]; -204 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); -205 -206 try { -207 //noinspection unchecked -208 Collection<String> completions = handler.getCompletions(context); -209 if (completions != null) { -210 allCompletions.addAll(completions); -211 continue; -212 } -213 //noinspection ConstantIfStatement,ConstantConditions -214 if (false) { // Hack to fool compiler. since its sneakily thrown. -215 throw new CommandCompletionTextLookupException(); -216 } -217 } catch (CommandCompletionTextLookupException ignored) { -218 // This should only happen if some other feedback error occured. -219 } catch (Exception e) { -220 command.handleException(sender, Arrays.asList(args), e); +178 @NotNull +179 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { +180 String[] completions = ACFPatterns.SPACE.split(cmd.complete); +181 final int argIndex = args.length - 1; +182 +183 String input = args[argIndex]; +184 +185 String completion = argIndex < completions.length ? completions[argIndex] : null; +186 if (completion == null || "*".equals(completion)) { +187 completion = findDefaultCompletion(cmd, args); +188 } +189 +190 if (completion == null && completions.length > 0) { +191 String last = completions[completions.length - 1]; +192 if (last.startsWith("repeat@")) { +193 completion = last; +194 } +195 } +196 +197 if (completion == null) { +198 return Collections.singletonList(input); +199 } +200 +201 return getCompletionValues(cmd, sender, completion, args, isAsync); +202 } +203 +204 String findDefaultCompletion(RegisteredCommand cmd, String[] args) { +205 int i = 0; +206 for (CommandParameter param : cmd.parameters) { +207 if (param.canConsumeInput() && ++i == args.length) { +208 Class type = param.getType(); +209 while (type != null) { +210 String completion = this.defaultCompletions.get(type); +211 if (completion != null) { +212 return completion; +213 } +214 type = type.getSuperclass(); +215 } +216 if (param.getType().isEnum()) { +217 CommandOperationContext ctx = CommandManager.getCurrentCommandOperationContext(); +218 //noinspection unchecked +219 ctx.enumCompletionValues = ACFUtil.enumNames((Class<? extends Enum<?>>) param.getType()); +220 return DEFAULT_ENUM_ID; 221 } -222 // Something went wrong in lookup, fall back to input -223 return Collections.singletonList(input); -224 } else { -225 // Plaintext value -226 allCompletions.add(value); -227 } -228 } -229 return allCompletions; -230 } -231 -232 public interface CommandCompletionHandler<C extends CommandCompletionContext> { -233 Collection<String> getCompletions(C context) throws InvalidCommandArgument; -234 } -235 -236 public interface AsyncCommandCompletionHandler<C extends CommandCompletionContext> extends CommandCompletionHandler<C> { -237 } -238 -239 public static class SyncCompletionRequired extends RuntimeException { -240 } -241 -242} +222 break; +223 } +224 } +225 return null; +226 } +227 +228 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { +229 if (DEFAULT_ENUM_ID.equals(completion)) { +230 CommandOperationContext<?> ctx = CommandManager.getCurrentCommandOperationContext(); +231 return ctx.enumCompletionValues; +232 } +233 if (completion.startsWith("repeat@")) { +234 completion = completion.substring(6); +235 } +236 completion = manager.getCommandReplacements().replace(completion); +237 +238 List<String> allCompletions = new ArrayList<>(); +239 String input = args.length > 0 ? args[args.length - 1] : ""; +240 +241 for (String value : ACFPatterns.PIPE.split(completion)) { +242 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); +243 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); +244 if (handler != null) { +245 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { +246 ACFUtil.sneaky(new SyncCompletionRequired()); +247 return null; +248 } +249 String config = complete.length == 1 ? null : complete[1]; +250 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); +251 +252 try { +253 //noinspection unchecked +254 Collection<String> completions = handler.getCompletions(context); +255 if (completions != null) { +256 allCompletions.addAll(completions); +257 continue; +258 } +259 //noinspection ConstantIfStatement,ConstantConditions +260 if (false) { // Hack to fool compiler. since its sneakily thrown. +261 throw new CommandCompletionTextLookupException(); +262 } +263 } catch (CommandCompletionTextLookupException ignored) { +264 // This should only happen if some other feedback error occured. +265 } catch (Exception e) { +266 command.handleException(sender, Arrays.asList(args), e); +267 } +268 // Something went wrong in lookup, fall back to input +269 return Collections.singletonList(input); +270 } else { +271 // Plaintext value +272 allCompletions.add(value); +273 } +274 } +275 return allCompletions; +276 } +277 +278 public interface CommandCompletionHandler<C extends CommandCompletionContext> { +279 Collection<String> getCompletions(C context) throws InvalidCommandArgument; +280 } +281 +282 public interface AsyncCommandCompletionHandler<C extends CommandCompletionContext> extends CommandCompletionHandler<C> { +283 } +284 +285 public static class SyncCompletionRequired extends RuntimeException { +286 } +287 +288} diff --git a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html index a2053fdb..616f583a 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html @@ -47,207 +47,253 @@ 039 040@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"}) 041public class CommandCompletions<C extends CommandCompletionContext> { -042 private final CommandManager manager; -043 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); -044 private Map<Class, String> defaultCompletions = new HashMap<>(); -045 -046 public CommandCompletions(CommandManager manager) { -047 this.manager = manager; -048 registerAsyncCompletion("nothing", c -> Collections.emptyList()); -049 registerAsyncCompletion("range", (c) -> { -050 String config = c.getConfig(); -051 if (config == null) { -052 return Collections.emptyList(); -053 } -054 final String[] ranges = ACFPatterns.DASH.split(config); -055 int start; -056 int end; -057 if (ranges.length != 2) { -058 start = 0; -059 end = ACFUtil.parseInt(ranges[0], 0); -060 } else { -061 start = ACFUtil.parseInt(ranges[0], 0); -062 end = ACFUtil.parseInt(ranges[1], 0); -063 } -064 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); -065 }); -066 List<String> timeunits = Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"); -067 registerAsyncCompletion("timeunits", (c) -> timeunits); -068 } -069 -070 /** -071 * Registr a completion handler to provide command completions based on the user input. -072 * -073 * @param id -074 * @param handler -075 * @return -076 */ -077 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { -078 return this.completionMap.put("@" + id.toLowerCase(), handler); -079 } -080 -081 /** -082 * Registr a completion handler to provide command completions based on the user input. -083 * This handler is declared to be safe to be executed asynchronously. -084 * <p> -085 * Not all platforms support this, so if the platform does not support asynchronous execution, -086 * your handler will be executed on the main thread. -087 * <p> -088 * Use this anytime your handler does not need to access state that is not considered thread safe. +042 private static final String DEFAULT_ENUM_ID = "@__defaultenum__"; +043 private final CommandManager manager; +044 // TODO: use a CompletionProvider that can return a delegated Id or provide values such as enum support +045 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); +046 private Map<Class, String> defaultCompletions = new HashMap<>(); +047 +048 public CommandCompletions(CommandManager manager) { +049 this.manager = manager; +050 registerAsyncCompletion("nothing", c -> Collections.emptyList()); +051 registerAsyncCompletion("range", (c) -> { +052 String config = c.getConfig(); +053 if (config == null) { +054 return Collections.emptyList(); +055 } +056 final String[] ranges = ACFPatterns.DASH.split(config); +057 int start; +058 int end; +059 if (ranges.length != 2) { +060 start = 0; +061 end = ACFUtil.parseInt(ranges[0], 0); +062 } else { +063 start = ACFUtil.parseInt(ranges[0], 0); +064 end = ACFUtil.parseInt(ranges[1], 0); +065 } +066 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); +067 }); +068 List<String> timeunits = Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"); +069 registerAsyncCompletion("timeunits", (c) -> timeunits); +070 } +071 +072 /** +073 * Registr a completion handler to provide command completions based on the user input. +074 * +075 * @param id +076 * @param handler +077 * @return +078 */ +079 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { +080 return this.completionMap.put(prepareCompletionId(id), handler); +081 } +082 +083 /** +084 * Registr a completion handler to provide command completions based on the user input. +085 * This handler is declared to be safe to be executed asynchronously. +086 * <p> +087 * Not all platforms support this, so if the platform does not support asynchronous execution, +088 * your handler will be executed on the main thread. 089 * <p> -090 * Use context.isAsync() to determine if you are async or not. -091 * -092 * @param id -093 * @param handler -094 * @return -095 */ -096 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { -097 return this.completionMap.put("@" + id.toLowerCase(), handler); -098 } -099 -100 /** -101 * Register a static list of command completions that will never change. -102 * Like @CommandCompletion, values are | (PIPE) separated. -103 * <p> -104 * Example: foo|bar|baz -105 * -106 * @param id -107 * @param list -108 * @return -109 */ -110 public CommandCompletionHandler registerStaticCompletion(String id, String list) { -111 return registerStaticCompletion(id, ACFPatterns.PIPE.split(list)); -112 } -113 -114 /** -115 * Register a static list of command completions that will never change -116 * -117 * @param id -118 * @param completions -119 * @return -120 */ -121 public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) { -122 return registerStaticCompletion(id, Arrays.asList(completions)); -123 } -124 -125 /** -126 * Register a static list of command completions that will never change. The list is obtained from the supplier -127 * immediately as part of this method call. -128 * -129 * @param id -130 * @param supplier -131 * @return -132 */ -133 public CommandCompletionHandler registerStaticCompletion(String id, Supplier<Collection<String>> supplier) { -134 return registerStaticCompletion(id, supplier.get()); -135 } -136 -137 /** -138 * Register a static list of command completions that will never change -139 * -140 * @param id -141 * @param completions -142 * @return -143 */ -144 public CommandCompletionHandler registerStaticCompletion(String id, Collection<String> completions) { -145 return registerAsyncCompletion(id, x -> completions); -146 } -147 -148 /** -149 * @param id -150 * @param classes -151 * @return -152 * @deprecated Feature Not done yet -153 */ -154 CommandCompletionHandler setDefaultCompletion(String id, Class... classes) { -155 // get completion with specified id -156 id = id.toLowerCase(); -157 CommandCompletionHandler completion = completionMap.get(id); -158 -159 if (completion == null) { -160 // Throw something because no completion with specified id -161 throw new IllegalStateException("Completion not registered for " + id); -162 } -163 -164 for (Class clazz : classes) { -165 defaultCompletions.put(clazz, id); +090 * Use this anytime your handler does not need to access state that is not considered thread safe. +091 * <p> +092 * Use context.isAsync() to determine if you are async or not. +093 * +094 * @param id +095 * @param handler +096 * @return +097 */ +098 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { +099 return this.completionMap.put(prepareCompletionId(id), handler); +100 } +101 +102 /** +103 * Register a static list of command completions that will never change. +104 * Like @CommandCompletion, values are | (PIPE) separated. +105 * <p> +106 * Example: foo|bar|baz +107 * +108 * @param id +109 * @param list +110 * @return +111 */ +112 public CommandCompletionHandler registerStaticCompletion(String id, String list) { +113 return registerStaticCompletion(id, ACFPatterns.PIPE.split(list)); +114 } +115 +116 /** +117 * Register a static list of command completions that will never change +118 * +119 * @param id +120 * @param completions +121 * @return +122 */ +123 public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) { +124 return registerStaticCompletion(id, Arrays.asList(completions)); +125 } +126 +127 /** +128 * Register a static list of command completions that will never change. The list is obtained from the supplier +129 * immediately as part of this method call. +130 * +131 * @param id +132 * @param supplier +133 * @return +134 */ +135 public CommandCompletionHandler registerStaticCompletion(String id, Supplier<Collection<String>> supplier) { +136 return registerStaticCompletion(id, supplier.get()); +137 } +138 +139 /** +140 * Register a static list of command completions that will never change +141 * +142 * @param id +143 * @param completions +144 * @return +145 */ +146 public CommandCompletionHandler registerStaticCompletion(String id, Collection<String> completions) { +147 return registerAsyncCompletion(id, x -> completions); +148 } +149 +150 /** +151 * Registers a completion handler such as @players to default apply to all command parameters of the specified types +152 * <p> +153 * This enables automatic completion support for parameters without manually defining it for custom objects +154 * +155 * @param id +156 * @param classes +157 */ +158 public void setDefaultCompletion(String id, Class... classes) { +159 // get completion with specified id +160 id = prepareCompletionId(id); +161 CommandCompletionHandler completion = completionMap.get(id); +162 +163 if (completion == null) { +164 // Throw something because no completion with specified id +165 throw new IllegalStateException("Completion not registered for " + id); 166 } 167 -168 return completion; -169 } -170 -171 @NotNull -172 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { -173 String[] completions = ACFPatterns.SPACE.split(cmd.complete); -174 final int argIndex = args.length - 1; -175 -176 String input = args[argIndex]; +168 for (Class clazz : classes) { +169 defaultCompletions.put(clazz, id); +170 } +171 } +172 +173 @NotNull +174 private static String prepareCompletionId(String id) { +175 return (id.startsWith("@") ? "" : "@") + id.toLowerCase(); +176 } 177 -178 String completion = argIndex < completions.length ? completions[argIndex] : null; -179 if (completion == null && completions.length > 0) { -180 completion = completions[completions.length - 1]; -181 } -182 if (completion == null) { -183 return Collections.singletonList(input); -184 } -185 -186 return getCompletionValues(cmd, sender, completion, args, isAsync); -187 } -188 -189 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { -190 completion = manager.getCommandReplacements().replace(completion); -191 -192 List<String> allCompletions = new ArrayList<>(); -193 String input = args.length > 0 ? args[args.length - 1] : ""; -194 -195 for (String value : ACFPatterns.PIPE.split(completion)) { -196 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); -197 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); -198 if (handler != null) { -199 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { -200 ACFUtil.sneaky(new SyncCompletionRequired()); -201 return null; -202 } -203 String config = complete.length == 1 ? null : complete[1]; -204 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); -205 -206 try { -207 //noinspection unchecked -208 Collection<String> completions = handler.getCompletions(context); -209 if (completions != null) { -210 allCompletions.addAll(completions); -211 continue; -212 } -213 //noinspection ConstantIfStatement,ConstantConditions -214 if (false) { // Hack to fool compiler. since its sneakily thrown. -215 throw new CommandCompletionTextLookupException(); -216 } -217 } catch (CommandCompletionTextLookupException ignored) { -218 // This should only happen if some other feedback error occured. -219 } catch (Exception e) { -220 command.handleException(sender, Arrays.asList(args), e); +178 @NotNull +179 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { +180 String[] completions = ACFPatterns.SPACE.split(cmd.complete); +181 final int argIndex = args.length - 1; +182 +183 String input = args[argIndex]; +184 +185 String completion = argIndex < completions.length ? completions[argIndex] : null; +186 if (completion == null || "*".equals(completion)) { +187 completion = findDefaultCompletion(cmd, args); +188 } +189 +190 if (completion == null && completions.length > 0) { +191 String last = completions[completions.length - 1]; +192 if (last.startsWith("repeat@")) { +193 completion = last; +194 } +195 } +196 +197 if (completion == null) { +198 return Collections.singletonList(input); +199 } +200 +201 return getCompletionValues(cmd, sender, completion, args, isAsync); +202 } +203 +204 String findDefaultCompletion(RegisteredCommand cmd, String[] args) { +205 int i = 0; +206 for (CommandParameter param : cmd.parameters) { +207 if (param.canConsumeInput() && ++i == args.length) { +208 Class type = param.getType(); +209 while (type != null) { +210 String completion = this.defaultCompletions.get(type); +211 if (completion != null) { +212 return completion; +213 } +214 type = type.getSuperclass(); +215 } +216 if (param.getType().isEnum()) { +217 CommandOperationContext ctx = CommandManager.getCurrentCommandOperationContext(); +218 //noinspection unchecked +219 ctx.enumCompletionValues = ACFUtil.enumNames((Class<? extends Enum<?>>) param.getType()); +220 return DEFAULT_ENUM_ID; 221 } -222 // Something went wrong in lookup, fall back to input -223 return Collections.singletonList(input); -224 } else { -225 // Plaintext value -226 allCompletions.add(value); -227 } -228 } -229 return allCompletions; -230 } -231 -232 public interface CommandCompletionHandler<C extends CommandCompletionContext> { -233 Collection<String> getCompletions(C context) throws InvalidCommandArgument; -234 } -235 -236 public interface AsyncCommandCompletionHandler<C extends CommandCompletionContext> extends CommandCompletionHandler<C> { -237 } -238 -239 public static class SyncCompletionRequired extends RuntimeException { -240 } -241 -242} +222 break; +223 } +224 } +225 return null; +226 } +227 +228 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { +229 if (DEFAULT_ENUM_ID.equals(completion)) { +230 CommandOperationContext<?> ctx = CommandManager.getCurrentCommandOperationContext(); +231 return ctx.enumCompletionValues; +232 } +233 if (completion.startsWith("repeat@")) { +234 completion = completion.substring(6); +235 } +236 completion = manager.getCommandReplacements().replace(completion); +237 +238 List<String> allCompletions = new ArrayList<>(); +239 String input = args.length > 0 ? args[args.length - 1] : ""; +240 +241 for (String value : ACFPatterns.PIPE.split(completion)) { +242 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); +243 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); +244 if (handler != null) { +245 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { +246 ACFUtil.sneaky(new SyncCompletionRequired()); +247 return null; +248 } +249 String config = complete.length == 1 ? null : complete[1]; +250 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); +251 +252 try { +253 //noinspection unchecked +254 Collection<String> completions = handler.getCompletions(context); +255 if (completions != null) { +256 allCompletions.addAll(completions); +257 continue; +258 } +259 //noinspection ConstantIfStatement,ConstantConditions +260 if (false) { // Hack to fool compiler. since its sneakily thrown. +261 throw new CommandCompletionTextLookupException(); +262 } +263 } catch (CommandCompletionTextLookupException ignored) { +264 // This should only happen if some other feedback error occured. +265 } catch (Exception e) { +266 command.handleException(sender, Arrays.asList(args), e); +267 } +268 // Something went wrong in lookup, fall back to input +269 return Collections.singletonList(input); +270 } else { +271 // Plaintext value +272 allCompletions.add(value); +273 } +274 } +275 return allCompletions; +276 } +277 +278 public interface CommandCompletionHandler<C extends CommandCompletionContext> { +279 Collection<String> getCompletions(C context) throws InvalidCommandArgument; +280 } +281 +282 public interface AsyncCommandCompletionHandler<C extends CommandCompletionContext> extends CommandCompletionHandler<C> { +283 } +284 +285 public static class SyncCompletionRequired extends RuntimeException { +286 } +287 +288} diff --git a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.SyncCompletionRequired.html b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.SyncCompletionRequired.html index a2053fdb..616f583a 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.SyncCompletionRequired.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.SyncCompletionRequired.html @@ -47,207 +47,253 @@ 039 040@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"}) 041public class CommandCompletions<C extends CommandCompletionContext> { -042 private final CommandManager manager; -043 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); -044 private Map<Class, String> defaultCompletions = new HashMap<>(); -045 -046 public CommandCompletions(CommandManager manager) { -047 this.manager = manager; -048 registerAsyncCompletion("nothing", c -> Collections.emptyList()); -049 registerAsyncCompletion("range", (c) -> { -050 String config = c.getConfig(); -051 if (config == null) { -052 return Collections.emptyList(); -053 } -054 final String[] ranges = ACFPatterns.DASH.split(config); -055 int start; -056 int end; -057 if (ranges.length != 2) { -058 start = 0; -059 end = ACFUtil.parseInt(ranges[0], 0); -060 } else { -061 start = ACFUtil.parseInt(ranges[0], 0); -062 end = ACFUtil.parseInt(ranges[1], 0); -063 } -064 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); -065 }); -066 List<String> timeunits = Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"); -067 registerAsyncCompletion("timeunits", (c) -> timeunits); -068 } -069 -070 /** -071 * Registr a completion handler to provide command completions based on the user input. -072 * -073 * @param id -074 * @param handler -075 * @return -076 */ -077 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { -078 return this.completionMap.put("@" + id.toLowerCase(), handler); -079 } -080 -081 /** -082 * Registr a completion handler to provide command completions based on the user input. -083 * This handler is declared to be safe to be executed asynchronously. -084 * <p> -085 * Not all platforms support this, so if the platform does not support asynchronous execution, -086 * your handler will be executed on the main thread. -087 * <p> -088 * Use this anytime your handler does not need to access state that is not considered thread safe. +042 private static final String DEFAULT_ENUM_ID = "@__defaultenum__"; +043 private final CommandManager manager; +044 // TODO: use a CompletionProvider that can return a delegated Id or provide values such as enum support +045 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); +046 private Map<Class, String> defaultCompletions = new HashMap<>(); +047 +048 public CommandCompletions(CommandManager manager) { +049 this.manager = manager; +050 registerAsyncCompletion("nothing", c -> Collections.emptyList()); +051 registerAsyncCompletion("range", (c) -> { +052 String config = c.getConfig(); +053 if (config == null) { +054 return Collections.emptyList(); +055 } +056 final String[] ranges = ACFPatterns.DASH.split(config); +057 int start; +058 int end; +059 if (ranges.length != 2) { +060 start = 0; +061 end = ACFUtil.parseInt(ranges[0], 0); +062 } else { +063 start = ACFUtil.parseInt(ranges[0], 0); +064 end = ACFUtil.parseInt(ranges[1], 0); +065 } +066 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); +067 }); +068 List<String> timeunits = Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"); +069 registerAsyncCompletion("timeunits", (c) -> timeunits); +070 } +071 +072 /** +073 * Registr a completion handler to provide command completions based on the user input. +074 * +075 * @param id +076 * @param handler +077 * @return +078 */ +079 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { +080 return this.completionMap.put(prepareCompletionId(id), handler); +081 } +082 +083 /** +084 * Registr a completion handler to provide command completions based on the user input. +085 * This handler is declared to be safe to be executed asynchronously. +086 * <p> +087 * Not all platforms support this, so if the platform does not support asynchronous execution, +088 * your handler will be executed on the main thread. 089 * <p> -090 * Use context.isAsync() to determine if you are async or not. -091 * -092 * @param id -093 * @param handler -094 * @return -095 */ -096 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { -097 return this.completionMap.put("@" + id.toLowerCase(), handler); -098 } -099 -100 /** -101 * Register a static list of command completions that will never change. -102 * Like @CommandCompletion, values are | (PIPE) separated. -103 * <p> -104 * Example: foo|bar|baz -105 * -106 * @param id -107 * @param list -108 * @return -109 */ -110 public CommandCompletionHandler registerStaticCompletion(String id, String list) { -111 return registerStaticCompletion(id, ACFPatterns.PIPE.split(list)); -112 } -113 -114 /** -115 * Register a static list of command completions that will never change -116 * -117 * @param id -118 * @param completions -119 * @return -120 */ -121 public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) { -122 return registerStaticCompletion(id, Arrays.asList(completions)); -123 } -124 -125 /** -126 * Register a static list of command completions that will never change. The list is obtained from the supplier -127 * immediately as part of this method call. -128 * -129 * @param id -130 * @param supplier -131 * @return -132 */ -133 public CommandCompletionHandler registerStaticCompletion(String id, Supplier<Collection<String>> supplier) { -134 return registerStaticCompletion(id, supplier.get()); -135 } -136 -137 /** -138 * Register a static list of command completions that will never change -139 * -140 * @param id -141 * @param completions -142 * @return -143 */ -144 public CommandCompletionHandler registerStaticCompletion(String id, Collection<String> completions) { -145 return registerAsyncCompletion(id, x -> completions); -146 } -147 -148 /** -149 * @param id -150 * @param classes -151 * @return -152 * @deprecated Feature Not done yet -153 */ -154 CommandCompletionHandler setDefaultCompletion(String id, Class... classes) { -155 // get completion with specified id -156 id = id.toLowerCase(); -157 CommandCompletionHandler completion = completionMap.get(id); -158 -159 if (completion == null) { -160 // Throw something because no completion with specified id -161 throw new IllegalStateException("Completion not registered for " + id); -162 } -163 -164 for (Class clazz : classes) { -165 defaultCompletions.put(clazz, id); +090 * Use this anytime your handler does not need to access state that is not considered thread safe. +091 * <p> +092 * Use context.isAsync() to determine if you are async or not. +093 * +094 * @param id +095 * @param handler +096 * @return +097 */ +098 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { +099 return this.completionMap.put(prepareCompletionId(id), handler); +100 } +101 +102 /** +103 * Register a static list of command completions that will never change. +104 * Like @CommandCompletion, values are | (PIPE) separated. +105 * <p> +106 * Example: foo|bar|baz +107 * +108 * @param id +109 * @param list +110 * @return +111 */ +112 public CommandCompletionHandler registerStaticCompletion(String id, String list) { +113 return registerStaticCompletion(id, ACFPatterns.PIPE.split(list)); +114 } +115 +116 /** +117 * Register a static list of command completions that will never change +118 * +119 * @param id +120 * @param completions +121 * @return +122 */ +123 public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) { +124 return registerStaticCompletion(id, Arrays.asList(completions)); +125 } +126 +127 /** +128 * Register a static list of command completions that will never change. The list is obtained from the supplier +129 * immediately as part of this method call. +130 * +131 * @param id +132 * @param supplier +133 * @return +134 */ +135 public CommandCompletionHandler registerStaticCompletion(String id, Supplier<Collection<String>> supplier) { +136 return registerStaticCompletion(id, supplier.get()); +137 } +138 +139 /** +140 * Register a static list of command completions that will never change +141 * +142 * @param id +143 * @param completions +144 * @return +145 */ +146 public CommandCompletionHandler registerStaticCompletion(String id, Collection<String> completions) { +147 return registerAsyncCompletion(id, x -> completions); +148 } +149 +150 /** +151 * Registers a completion handler such as @players to default apply to all command parameters of the specified types +152 * <p> +153 * This enables automatic completion support for parameters without manually defining it for custom objects +154 * +155 * @param id +156 * @param classes +157 */ +158 public void setDefaultCompletion(String id, Class... classes) { +159 // get completion with specified id +160 id = prepareCompletionId(id); +161 CommandCompletionHandler completion = completionMap.get(id); +162 +163 if (completion == null) { +164 // Throw something because no completion with specified id +165 throw new IllegalStateException("Completion not registered for " + id); 166 } 167 -168 return completion; -169 } -170 -171 @NotNull -172 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { -173 String[] completions = ACFPatterns.SPACE.split(cmd.complete); -174 final int argIndex = args.length - 1; -175 -176 String input = args[argIndex]; +168 for (Class clazz : classes) { +169 defaultCompletions.put(clazz, id); +170 } +171 } +172 +173 @NotNull +174 private static String prepareCompletionId(String id) { +175 return (id.startsWith("@") ? "" : "@") + id.toLowerCase(); +176 } 177 -178 String completion = argIndex < completions.length ? completions[argIndex] : null; -179 if (completion == null && completions.length > 0) { -180 completion = completions[completions.length - 1]; -181 } -182 if (completion == null) { -183 return Collections.singletonList(input); -184 } -185 -186 return getCompletionValues(cmd, sender, completion, args, isAsync); -187 } -188 -189 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { -190 completion = manager.getCommandReplacements().replace(completion); -191 -192 List<String> allCompletions = new ArrayList<>(); -193 String input = args.length > 0 ? args[args.length - 1] : ""; -194 -195 for (String value : ACFPatterns.PIPE.split(completion)) { -196 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); -197 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); -198 if (handler != null) { -199 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { -200 ACFUtil.sneaky(new SyncCompletionRequired()); -201 return null; -202 } -203 String config = complete.length == 1 ? null : complete[1]; -204 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); -205 -206 try { -207 //noinspection unchecked -208 Collection<String> completions = handler.getCompletions(context); -209 if (completions != null) { -210 allCompletions.addAll(completions); -211 continue; -212 } -213 //noinspection ConstantIfStatement,ConstantConditions -214 if (false) { // Hack to fool compiler. since its sneakily thrown. -215 throw new CommandCompletionTextLookupException(); -216 } -217 } catch (CommandCompletionTextLookupException ignored) { -218 // This should only happen if some other feedback error occured. -219 } catch (Exception e) { -220 command.handleException(sender, Arrays.asList(args), e); +178 @NotNull +179 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { +180 String[] completions = ACFPatterns.SPACE.split(cmd.complete); +181 final int argIndex = args.length - 1; +182 +183 String input = args[argIndex]; +184 +185 String completion = argIndex < completions.length ? completions[argIndex] : null; +186 if (completion == null || "*".equals(completion)) { +187 completion = findDefaultCompletion(cmd, args); +188 } +189 +190 if (completion == null && completions.length > 0) { +191 String last = completions[completions.length - 1]; +192 if (last.startsWith("repeat@")) { +193 completion = last; +194 } +195 } +196 +197 if (completion == null) { +198 return Collections.singletonList(input); +199 } +200 +201 return getCompletionValues(cmd, sender, completion, args, isAsync); +202 } +203 +204 String findDefaultCompletion(RegisteredCommand cmd, String[] args) { +205 int i = 0; +206 for (CommandParameter param : cmd.parameters) { +207 if (param.canConsumeInput() && ++i == args.length) { +208 Class type = param.getType(); +209 while (type != null) { +210 String completion = this.defaultCompletions.get(type); +211 if (completion != null) { +212 return completion; +213 } +214 type = type.getSuperclass(); +215 } +216 if (param.getType().isEnum()) { +217 CommandOperationContext ctx = CommandManager.getCurrentCommandOperationContext(); +218 //noinspection unchecked +219 ctx.enumCompletionValues = ACFUtil.enumNames((Class<? extends Enum<?>>) param.getType()); +220 return DEFAULT_ENUM_ID; 221 } -222 // Something went wrong in lookup, fall back to input -223 return Collections.singletonList(input); -224 } else { -225 // Plaintext value -226 allCompletions.add(value); -227 } -228 } -229 return allCompletions; -230 } -231 -232 public interface CommandCompletionHandler<C extends CommandCompletionContext> { -233 Collection<String> getCompletions(C context) throws InvalidCommandArgument; -234 } -235 -236 public interface AsyncCommandCompletionHandler<C extends CommandCompletionContext> extends CommandCompletionHandler<C> { -237 } -238 -239 public static class SyncCompletionRequired extends RuntimeException { -240 } -241 -242} +222 break; +223 } +224 } +225 return null; +226 } +227 +228 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { +229 if (DEFAULT_ENUM_ID.equals(completion)) { +230 CommandOperationContext<?> ctx = CommandManager.getCurrentCommandOperationContext(); +231 return ctx.enumCompletionValues; +232 } +233 if (completion.startsWith("repeat@")) { +234 completion = completion.substring(6); +235 } +236 completion = manager.getCommandReplacements().replace(completion); +237 +238 List<String> allCompletions = new ArrayList<>(); +239 String input = args.length > 0 ? args[args.length - 1] : ""; +240 +241 for (String value : ACFPatterns.PIPE.split(completion)) { +242 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); +243 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); +244 if (handler != null) { +245 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { +246 ACFUtil.sneaky(new SyncCompletionRequired()); +247 return null; +248 } +249 String config = complete.length == 1 ? null : complete[1]; +250 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); +251 +252 try { +253 //noinspection unchecked +254 Collection<String> completions = handler.getCompletions(context); +255 if (completions != null) { +256 allCompletions.addAll(completions); +257 continue; +258 } +259 //noinspection ConstantIfStatement,ConstantConditions +260 if (false) { // Hack to fool compiler. since its sneakily thrown. +261 throw new CommandCompletionTextLookupException(); +262 } +263 } catch (CommandCompletionTextLookupException ignored) { +264 // This should only happen if some other feedback error occured. +265 } catch (Exception e) { +266 command.handleException(sender, Arrays.asList(args), e); +267 } +268 // Something went wrong in lookup, fall back to input +269 return Collections.singletonList(input); +270 } else { +271 // Plaintext value +272 allCompletions.add(value); +273 } +274 } +275 return allCompletions; +276 } +277 +278 public interface CommandCompletionHandler<C extends CommandCompletionContext> { +279 Collection<String> getCompletions(C context) throws InvalidCommandArgument; +280 } +281 +282 public interface AsyncCommandCompletionHandler<C extends CommandCompletionContext> extends CommandCompletionHandler<C> { +283 } +284 +285 public static class SyncCompletionRequired extends RuntimeException { +286 } +287 +288} diff --git a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.html b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.html index a2053fdb..616f583a 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.html @@ -47,207 +47,253 @@ 039 040@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"}) 041public class CommandCompletions<C extends CommandCompletionContext> { -042 private final CommandManager manager; -043 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); -044 private Map<Class, String> defaultCompletions = new HashMap<>(); -045 -046 public CommandCompletions(CommandManager manager) { -047 this.manager = manager; -048 registerAsyncCompletion("nothing", c -> Collections.emptyList()); -049 registerAsyncCompletion("range", (c) -> { -050 String config = c.getConfig(); -051 if (config == null) { -052 return Collections.emptyList(); -053 } -054 final String[] ranges = ACFPatterns.DASH.split(config); -055 int start; -056 int end; -057 if (ranges.length != 2) { -058 start = 0; -059 end = ACFUtil.parseInt(ranges[0], 0); -060 } else { -061 start = ACFUtil.parseInt(ranges[0], 0); -062 end = ACFUtil.parseInt(ranges[1], 0); -063 } -064 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); -065 }); -066 List<String> timeunits = Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"); -067 registerAsyncCompletion("timeunits", (c) -> timeunits); -068 } -069 -070 /** -071 * Registr a completion handler to provide command completions based on the user input. -072 * -073 * @param id -074 * @param handler -075 * @return -076 */ -077 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { -078 return this.completionMap.put("@" + id.toLowerCase(), handler); -079 } -080 -081 /** -082 * Registr a completion handler to provide command completions based on the user input. -083 * This handler is declared to be safe to be executed asynchronously. -084 * <p> -085 * Not all platforms support this, so if the platform does not support asynchronous execution, -086 * your handler will be executed on the main thread. -087 * <p> -088 * Use this anytime your handler does not need to access state that is not considered thread safe. +042 private static final String DEFAULT_ENUM_ID = "@__defaultenum__"; +043 private final CommandManager manager; +044 // TODO: use a CompletionProvider that can return a delegated Id or provide values such as enum support +045 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); +046 private Map<Class, String> defaultCompletions = new HashMap<>(); +047 +048 public CommandCompletions(CommandManager manager) { +049 this.manager = manager; +050 registerAsyncCompletion("nothing", c -> Collections.emptyList()); +051 registerAsyncCompletion("range", (c) -> { +052 String config = c.getConfig(); +053 if (config == null) { +054 return Collections.emptyList(); +055 } +056 final String[] ranges = ACFPatterns.DASH.split(config); +057 int start; +058 int end; +059 if (ranges.length != 2) { +060 start = 0; +061 end = ACFUtil.parseInt(ranges[0], 0); +062 } else { +063 start = ACFUtil.parseInt(ranges[0], 0); +064 end = ACFUtil.parseInt(ranges[1], 0); +065 } +066 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); +067 }); +068 List<String> timeunits = Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"); +069 registerAsyncCompletion("timeunits", (c) -> timeunits); +070 } +071 +072 /** +073 * Registr a completion handler to provide command completions based on the user input. +074 * +075 * @param id +076 * @param handler +077 * @return +078 */ +079 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { +080 return this.completionMap.put(prepareCompletionId(id), handler); +081 } +082 +083 /** +084 * Registr a completion handler to provide command completions based on the user input. +085 * This handler is declared to be safe to be executed asynchronously. +086 * <p> +087 * Not all platforms support this, so if the platform does not support asynchronous execution, +088 * your handler will be executed on the main thread. 089 * <p> -090 * Use context.isAsync() to determine if you are async or not. -091 * -092 * @param id -093 * @param handler -094 * @return -095 */ -096 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { -097 return this.completionMap.put("@" + id.toLowerCase(), handler); -098 } -099 -100 /** -101 * Register a static list of command completions that will never change. -102 * Like @CommandCompletion, values are | (PIPE) separated. -103 * <p> -104 * Example: foo|bar|baz -105 * -106 * @param id -107 * @param list -108 * @return -109 */ -110 public CommandCompletionHandler registerStaticCompletion(String id, String list) { -111 return registerStaticCompletion(id, ACFPatterns.PIPE.split(list)); -112 } -113 -114 /** -115 * Register a static list of command completions that will never change -116 * -117 * @param id -118 * @param completions -119 * @return -120 */ -121 public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) { -122 return registerStaticCompletion(id, Arrays.asList(completions)); -123 } -124 -125 /** -126 * Register a static list of command completions that will never change. The list is obtained from the supplier -127 * immediately as part of this method call. -128 * -129 * @param id -130 * @param supplier -131 * @return -132 */ -133 public CommandCompletionHandler registerStaticCompletion(String id, Supplier<Collection<String>> supplier) { -134 return registerStaticCompletion(id, supplier.get()); -135 } -136 -137 /** -138 * Register a static list of command completions that will never change -139 * -140 * @param id -141 * @param completions -142 * @return -143 */ -144 public CommandCompletionHandler registerStaticCompletion(String id, Collection<String> completions) { -145 return registerAsyncCompletion(id, x -> completions); -146 } -147 -148 /** -149 * @param id -150 * @param classes -151 * @return -152 * @deprecated Feature Not done yet -153 */ -154 CommandCompletionHandler setDefaultCompletion(String id, Class... classes) { -155 // get completion with specified id -156 id = id.toLowerCase(); -157 CommandCompletionHandler completion = completionMap.get(id); -158 -159 if (completion == null) { -160 // Throw something because no completion with specified id -161 throw new IllegalStateException("Completion not registered for " + id); -162 } -163 -164 for (Class clazz : classes) { -165 defaultCompletions.put(clazz, id); +090 * Use this anytime your handler does not need to access state that is not considered thread safe. +091 * <p> +092 * Use context.isAsync() to determine if you are async or not. +093 * +094 * @param id +095 * @param handler +096 * @return +097 */ +098 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { +099 return this.completionMap.put(prepareCompletionId(id), handler); +100 } +101 +102 /** +103 * Register a static list of command completions that will never change. +104 * Like @CommandCompletion, values are | (PIPE) separated. +105 * <p> +106 * Example: foo|bar|baz +107 * +108 * @param id +109 * @param list +110 * @return +111 */ +112 public CommandCompletionHandler registerStaticCompletion(String id, String list) { +113 return registerStaticCompletion(id, ACFPatterns.PIPE.split(list)); +114 } +115 +116 /** +117 * Register a static list of command completions that will never change +118 * +119 * @param id +120 * @param completions +121 * @return +122 */ +123 public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) { +124 return registerStaticCompletion(id, Arrays.asList(completions)); +125 } +126 +127 /** +128 * Register a static list of command completions that will never change. The list is obtained from the supplier +129 * immediately as part of this method call. +130 * +131 * @param id +132 * @param supplier +133 * @return +134 */ +135 public CommandCompletionHandler registerStaticCompletion(String id, Supplier<Collection<String>> supplier) { +136 return registerStaticCompletion(id, supplier.get()); +137 } +138 +139 /** +140 * Register a static list of command completions that will never change +141 * +142 * @param id +143 * @param completions +144 * @return +145 */ +146 public CommandCompletionHandler registerStaticCompletion(String id, Collection<String> completions) { +147 return registerAsyncCompletion(id, x -> completions); +148 } +149 +150 /** +151 * Registers a completion handler such as @players to default apply to all command parameters of the specified types +152 * <p> +153 * This enables automatic completion support for parameters without manually defining it for custom objects +154 * +155 * @param id +156 * @param classes +157 */ +158 public void setDefaultCompletion(String id, Class... classes) { +159 // get completion with specified id +160 id = prepareCompletionId(id); +161 CommandCompletionHandler completion = completionMap.get(id); +162 +163 if (completion == null) { +164 // Throw something because no completion with specified id +165 throw new IllegalStateException("Completion not registered for " + id); 166 } 167 -168 return completion; -169 } -170 -171 @NotNull -172 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { -173 String[] completions = ACFPatterns.SPACE.split(cmd.complete); -174 final int argIndex = args.length - 1; -175 -176 String input = args[argIndex]; +168 for (Class clazz : classes) { +169 defaultCompletions.put(clazz, id); +170 } +171 } +172 +173 @NotNull +174 private static String prepareCompletionId(String id) { +175 return (id.startsWith("@") ? "" : "@") + id.toLowerCase(); +176 } 177 -178 String completion = argIndex < completions.length ? completions[argIndex] : null; -179 if (completion == null && completions.length > 0) { -180 completion = completions[completions.length - 1]; -181 } -182 if (completion == null) { -183 return Collections.singletonList(input); -184 } -185 -186 return getCompletionValues(cmd, sender, completion, args, isAsync); -187 } -188 -189 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { -190 completion = manager.getCommandReplacements().replace(completion); -191 -192 List<String> allCompletions = new ArrayList<>(); -193 String input = args.length > 0 ? args[args.length - 1] : ""; -194 -195 for (String value : ACFPatterns.PIPE.split(completion)) { -196 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); -197 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); -198 if (handler != null) { -199 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { -200 ACFUtil.sneaky(new SyncCompletionRequired()); -201 return null; -202 } -203 String config = complete.length == 1 ? null : complete[1]; -204 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); -205 -206 try { -207 //noinspection unchecked -208 Collection<String> completions = handler.getCompletions(context); -209 if (completions != null) { -210 allCompletions.addAll(completions); -211 continue; -212 } -213 //noinspection ConstantIfStatement,ConstantConditions -214 if (false) { // Hack to fool compiler. since its sneakily thrown. -215 throw new CommandCompletionTextLookupException(); -216 } -217 } catch (CommandCompletionTextLookupException ignored) { -218 // This should only happen if some other feedback error occured. -219 } catch (Exception e) { -220 command.handleException(sender, Arrays.asList(args), e); +178 @NotNull +179 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { +180 String[] completions = ACFPatterns.SPACE.split(cmd.complete); +181 final int argIndex = args.length - 1; +182 +183 String input = args[argIndex]; +184 +185 String completion = argIndex < completions.length ? completions[argIndex] : null; +186 if (completion == null || "*".equals(completion)) { +187 completion = findDefaultCompletion(cmd, args); +188 } +189 +190 if (completion == null && completions.length > 0) { +191 String last = completions[completions.length - 1]; +192 if (last.startsWith("repeat@")) { +193 completion = last; +194 } +195 } +196 +197 if (completion == null) { +198 return Collections.singletonList(input); +199 } +200 +201 return getCompletionValues(cmd, sender, completion, args, isAsync); +202 } +203 +204 String findDefaultCompletion(RegisteredCommand cmd, String[] args) { +205 int i = 0; +206 for (CommandParameter param : cmd.parameters) { +207 if (param.canConsumeInput() && ++i == args.length) { +208 Class type = param.getType(); +209 while (type != null) { +210 String completion = this.defaultCompletions.get(type); +211 if (completion != null) { +212 return completion; +213 } +214 type = type.getSuperclass(); +215 } +216 if (param.getType().isEnum()) { +217 CommandOperationContext ctx = CommandManager.getCurrentCommandOperationContext(); +218 //noinspection unchecked +219 ctx.enumCompletionValues = ACFUtil.enumNames((Class<? extends Enum<?>>) param.getType()); +220 return DEFAULT_ENUM_ID; 221 } -222 // Something went wrong in lookup, fall back to input -223 return Collections.singletonList(input); -224 } else { -225 // Plaintext value -226 allCompletions.add(value); -227 } -228 } -229 return allCompletions; -230 } -231 -232 public interface CommandCompletionHandler<C extends CommandCompletionContext> { -233 Collection<String> getCompletions(C context) throws InvalidCommandArgument; -234 } -235 -236 public interface AsyncCommandCompletionHandler<C extends CommandCompletionContext> extends CommandCompletionHandler<C> { -237 } -238 -239 public static class SyncCompletionRequired extends RuntimeException { -240 } -241 -242} +222 break; +223 } +224 } +225 return null; +226 } +227 +228 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { +229 if (DEFAULT_ENUM_ID.equals(completion)) { +230 CommandOperationContext<?> ctx = CommandManager.getCurrentCommandOperationContext(); +231 return ctx.enumCompletionValues; +232 } +233 if (completion.startsWith("repeat@")) { +234 completion = completion.substring(6); +235 } +236 completion = manager.getCommandReplacements().replace(completion); +237 +238 List<String> allCompletions = new ArrayList<>(); +239 String input = args.length > 0 ? args[args.length - 1] : ""; +240 +241 for (String value : ACFPatterns.PIPE.split(completion)) { +242 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); +243 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); +244 if (handler != null) { +245 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { +246 ACFUtil.sneaky(new SyncCompletionRequired()); +247 return null; +248 } +249 String config = complete.length == 1 ? null : complete[1]; +250 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); +251 +252 try { +253 //noinspection unchecked +254 Collection<String> completions = handler.getCompletions(context); +255 if (completions != null) { +256 allCompletions.addAll(completions); +257 continue; +258 } +259 //noinspection ConstantIfStatement,ConstantConditions +260 if (false) { // Hack to fool compiler. since its sneakily thrown. +261 throw new CommandCompletionTextLookupException(); +262 } +263 } catch (CommandCompletionTextLookupException ignored) { +264 // This should only happen if some other feedback error occured. +265 } catch (Exception e) { +266 command.handleException(sender, Arrays.asList(args), e); +267 } +268 // Something went wrong in lookup, fall back to input +269 return Collections.singletonList(input); +270 } else { +271 // Plaintext value +272 allCompletions.add(value); +273 } +274 } +275 return allCompletions; +276 } +277 +278 public interface CommandCompletionHandler<C extends CommandCompletionContext> { +279 Collection<String> getCompletions(C context) throws InvalidCommandArgument; +280 } +281 +282 public interface AsyncCommandCompletionHandler<C extends CommandCompletionContext> extends CommandCompletionHandler<C> { +283 } +284 +285 public static class SyncCompletionRequired extends RuntimeException { +286 } +287 +288} diff --git a/docs/acf-core/src-html/co/aikar/commands/CommandContexts.html b/docs/acf-core/src-html/co/aikar/commands/CommandContexts.html index 2f8d0dd4..2c13c8bf 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandContexts.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandContexts.html @@ -213,7 +213,7 @@ 205 Enum<?> match = ACFUtil.simpleMatch(enumCls, first); 206 if (match == null) { 207 List<String> names = ACFUtil.enumNames(enumCls); -208 throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, "{valid}", ACFUtil.join(names)); +208 throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, "{valid}", ACFUtil.join(names, ", ")); 209 } 210 return match; 211 }); diff --git a/docs/acf-core/src-html/co/aikar/commands/CommandExecutionContext.html b/docs/acf-core/src-html/co/aikar/commands/CommandExecutionContext.html index b00fbd79..5acbca05 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandExecutionContext.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandExecutionContext.html @@ -35,80 +35,80 @@ 027import java.lang.reflect.Parameter; 028import java.util.List; 029import java.util.Map; -030 -031@SuppressWarnings({"WeakerAccess"}) -032public class CommandExecutionContext <CEC extends CommandExecutionContext, I extends CommandIssuer> { -033 private final RegisteredCommand cmd; -034 private final CommandParameter param; -035 protected final I issuer; -036 private final List<String> args; -037 private final int index; -038 private final Map<String, Object> passedArgs; -039 private final Map<String, String> flags; -040 private final CommandManager manager; -041 -042 CommandExecutionContext(RegisteredCommand cmd, CommandParameter param, I sender, List<String> args, -043 int index, Map<String, Object> passedArgs) { -044 this.cmd = cmd; -045 this.manager = cmd.scope.manager; -046 this.param = param; -047 this.issuer = sender; -048 this.args = args; -049 this.index = index; -050 this.passedArgs = passedArgs; -051 this.flags = param.getFlags(); -052 -053 } -054 -055 public String popFirstArg() { -056 return !args.isEmpty() ? args.remove(0) : null; -057 } -058 -059 public String popLastArg() { -060 return !args.isEmpty() ? args.remove(args.size() - 1) : null; -061 } -062 -063 public String getFirstArg() { -064 return !args.isEmpty() ? args.get(0) : null; -065 } -066 -067 public String getLastArg() { -068 return !args.isEmpty() ? args.get(args.size() - 1) : null; -069 } -070 -071 public boolean isLastArg() { -072 return cmd.parameters.length -1 == index; -073 } -074 -075 public int getNumParams() { -076 return cmd.parameters.length; -077 } -078 -079 public boolean canOverridePlayerContext() { -080 return cmd.requiredResolvers >= args.size(); -081 } -082 -083 public Object getResolvedArg(String arg) { -084 return passedArgs.get(arg); -085 } -086 -087 public Object getResolvedArg(Class<?>... classes) { -088 for (Class<?> clazz : classes) { -089 for (Object passedArg : passedArgs.values()) { -090 if (clazz.isInstance(passedArg)) { -091 return passedArg; -092 } -093 } -094 } -095 -096 return null; -097 } -098 -099 public <T> T getResolvedArg(String key, Class<?>... classes) { -100 final Object o = passedArgs.get(key); -101 for (Class<?> clazz : classes) { -102 if (clazz.isInstance(o)) { -103 //noinspection unchecked +030import java.util.Set; +031 +032@SuppressWarnings({"WeakerAccess", "unchecked"}) +033public class CommandExecutionContext<CEC extends CommandExecutionContext, I extends CommandIssuer> { +034 private final RegisteredCommand cmd; +035 private final CommandParameter param; +036 protected final I issuer; +037 private final List<String> args; +038 private final int index; +039 private final Map<String, Object> passedArgs; +040 private final Map<String, String> flags; +041 private final CommandManager manager; +042 +043 CommandExecutionContext(RegisteredCommand cmd, CommandParameter param, I sender, List<String> args, +044 int index, Map<String, Object> passedArgs) { +045 this.cmd = cmd; +046 this.manager = cmd.scope.manager; +047 this.param = param; +048 this.issuer = sender; +049 this.args = args; +050 this.index = index; +051 this.passedArgs = passedArgs; +052 this.flags = param.getFlags(); +053 +054 } +055 +056 public String popFirstArg() { +057 return !args.isEmpty() ? args.remove(0) : null; +058 } +059 +060 public String popLastArg() { +061 return !args.isEmpty() ? args.remove(args.size() - 1) : null; +062 } +063 +064 public String getFirstArg() { +065 return !args.isEmpty() ? args.get(0) : null; +066 } +067 +068 public String getLastArg() { +069 return !args.isEmpty() ? args.get(args.size() - 1) : null; +070 } +071 +072 public boolean isLastArg() { +073 return cmd.parameters.length - 1 == index; +074 } +075 +076 public int getNumParams() { +077 return cmd.parameters.length; +078 } +079 +080 public boolean canOverridePlayerContext() { +081 return cmd.requiredResolvers >= args.size(); +082 } +083 +084 public Object getResolvedArg(String arg) { +085 return passedArgs.get(arg); +086 } +087 +088 public Object getResolvedArg(Class<?>... classes) { +089 for (Class<?> clazz : classes) { +090 for (Object passedArg : passedArgs.values()) { +091 if (clazz.isInstance(passedArg)) { +092 return passedArg; +093 } +094 } +095 } +096 +097 return null; +098 } +099 +100 public <T> T getResolvedArg(String key, Class<?>... classes) { +101 final Object o = passedArgs.get(key); +102 for (Class<?> clazz : classes) { +103 if (clazz.isInstance(o)) { 104 return (T) o; 105 } 106 } @@ -116,128 +116,134 @@ 108 return null; 109 } 110 -111 public boolean isOptional() { -112 return param.isOptional(); +111 public Set<String> getParameterPermissions() { +112 return param.getRequiredPermissions(); 113 } 114 -115 public boolean hasFlag(String flag) { -116 return flags.containsKey(flag); +115 public boolean isOptional() { +116 return param.isOptional(); 117 } 118 -119 public String getFlagValue(String flag, String def) { -120 return flags.getOrDefault(flag, def); +119 public boolean hasFlag(String flag) { +120 return flags.containsKey(flag); 121 } 122 -123 public Integer getFlagValue(String flag, Integer def) { -124 return ACFUtil.parseInt(this.flags.get(flag), def); +123 public String getFlagValue(String flag, String def) { +124 return flags.getOrDefault(flag, def); 125 } 126 -127 public Long getFlagValue(String flag, Long def) { -128 return ACFUtil.parseLong(this.flags.get(flag), def); +127 public Integer getFlagValue(String flag, Integer def) { +128 return ACFUtil.parseInt(this.flags.get(flag), def); 129 } 130 -131 public Float getFlagValue(String flag, Float def) { -132 return ACFUtil.parseFloat(this.flags.get(flag), def); +131 public Long getFlagValue(String flag, Long def) { +132 return ACFUtil.parseLong(this.flags.get(flag), def); 133 } 134 -135 public Double getFlagValue(String flag, Double def) { -136 return ACFUtil.parseDouble(this.flags.get(flag), def); +135 public Float getFlagValue(String flag, Float def) { +136 return ACFUtil.parseFloat(this.flags.get(flag), def); 137 } 138 -139 public Integer getIntFlagValue(String flag, Number def) { -140 return ACFUtil.parseInt(this.flags.get(flag), def != null ? def.intValue() : null); +139 public Double getFlagValue(String flag, Double def) { +140 return ACFUtil.parseDouble(this.flags.get(flag), def); 141 } 142 -143 public Long getLongFlagValue(String flag, Number def) { -144 return ACFUtil.parseLong(this.flags.get(flag), def != null ? def.longValue() : null); +143 public Integer getIntFlagValue(String flag, Number def) { +144 return ACFUtil.parseInt(this.flags.get(flag), def != null ? def.intValue() : null); 145 } 146 -147 public Float getFloatFlagValue(String flag, Number def) { -148 return ACFUtil.parseFloat(this.flags.get(flag), def != null ? def.floatValue() : null); +147 public Long getLongFlagValue(String flag, Number def) { +148 return ACFUtil.parseLong(this.flags.get(flag), def != null ? def.longValue() : null); 149 } 150 -151 public Double getDoubleFlagValue(String flag, Number def) { -152 return ACFUtil.parseDouble(this.flags.get(flag), def != null ? def.doubleValue() : null); +151 public Float getFloatFlagValue(String flag, Number def) { +152 return ACFUtil.parseFloat(this.flags.get(flag), def != null ? def.floatValue() : null); 153 } 154 -155 public Boolean getBooleanFlagValue(String flag) { -156 return getBooleanFlagValue(flag, false); +155 public Double getDoubleFlagValue(String flag, Number def) { +156 return ACFUtil.parseDouble(this.flags.get(flag), def != null ? def.doubleValue() : null); 157 } 158 -159 public Boolean getBooleanFlagValue(String flag, Boolean def) { -160 String val = this.flags.get(flag); -161 if (val == null) { -162 return def; -163 } -164 return ACFUtil.isTruthy(val); -165 } -166 -167 public Double getFlagValue(String flag, Number def) { -168 return ACFUtil.parseDouble(this.flags.get(flag), def != null ? def.doubleValue() : null); +159 public Boolean getBooleanFlagValue(String flag) { +160 return getBooleanFlagValue(flag, false); +161 } +162 +163 public Boolean getBooleanFlagValue(String flag, Boolean def) { +164 String val = this.flags.get(flag); +165 if (val == null) { +166 return def; +167 } +168 return ACFUtil.isTruthy(val); 169 } 170 -171 /** -172 * This method will not support annotation processors!! use getAnnotationValue or hasAnnotation -173 * @deprecated Use {@link #getAnnotationValue(Class)} -174 */ -175 @Deprecated -176 public <T extends Annotation> T getAnnotation(Class<T> cls) { -177 return param.getParameter().getAnnotation(cls); -178 } -179 -180 public <T extends Annotation> String getAnnotationValue(Class<T> cls) { -181 return manager.getAnnotations().getAnnotationValue(param.getParameter(), cls); -182 } -183 -184 public <T extends Annotation> String getAnnotationValue(Class<T> cls, int options) { -185 return manager.getAnnotations().getAnnotationValue(param.getParameter(), cls, options); -186 } -187 -188 public <T extends Annotation> boolean hasAnnotation(Class<T> cls) { -189 return manager.getAnnotations().hasAnnotation(param.getParameter(), cls); -190 } -191 -192 public RegisteredCommand getCmd() { -193 return this.cmd; -194 } -195 -196 @UnstableAPI -197 CommandParameter getCommandParameter() { -198 return this.param; +171 public Double getFlagValue(String flag, Number def) { +172 return ACFUtil.parseDouble(this.flags.get(flag), def != null ? def.doubleValue() : null); +173 } +174 +175 /** +176 * This method will not support annotation processors!! use getAnnotationValue or hasAnnotation +177 * +178 * @deprecated Use {@link #getAnnotationValue(Class)} +179 */ +180 @Deprecated +181 public <T extends Annotation> T getAnnotation(Class<T> cls) { +182 return param.getParameter().getAnnotation(cls); +183 } +184 +185 public <T extends Annotation> String getAnnotationValue(Class<T> cls) { +186 return manager.getAnnotations().getAnnotationValue(param.getParameter(), cls); +187 } +188 +189 public <T extends Annotation> String getAnnotationValue(Class<T> cls, int options) { +190 return manager.getAnnotations().getAnnotationValue(param.getParameter(), cls, options); +191 } +192 +193 public <T extends Annotation> boolean hasAnnotation(Class<T> cls) { +194 return manager.getAnnotations().hasAnnotation(param.getParameter(), cls); +195 } +196 +197 public RegisteredCommand getCmd() { +198 return this.cmd; 199 } 200 -201 @Deprecated -202 public Parameter getParam() { -203 return this.param.getParameter(); +201 @UnstableAPI +202 CommandParameter getCommandParameter() { +203 return this.param; 204 } 205 -206 public I getIssuer() { -207 return this.issuer; -208 } -209 -210 public List<String> getArgs() { -211 return this.args; -212 } -213 -214 public int getIndex() { -215 return this.index; -216 } -217 -218 public Map<String, Object> getPassedArgs() { -219 return this.passedArgs; -220 } -221 -222 public Map<String, String> getFlags() { -223 return this.flags; -224 } -225 -226 public String joinArgs() { -227 return ACFUtil.join(args, " "); -228 } -229 public String joinArgs(String sep) { -230 return ACFUtil.join(args, sep); -231 } -232} +206 @Deprecated +207 public Parameter getParam() { +208 return this.param.getParameter(); +209 } +210 +211 public I getIssuer() { +212 return this.issuer; +213 } +214 +215 public List<String> getArgs() { +216 return this.args; +217 } +218 +219 public int getIndex() { +220 return this.index; +221 } +222 +223 public Map<String, Object> getPassedArgs() { +224 return this.passedArgs; +225 } +226 +227 public Map<String, String> getFlags() { +228 return this.flags; +229 } +230 +231 public String joinArgs() { +232 return ACFUtil.join(args, " "); +233 } +234 +235 public String joinArgs(String sep) { +236 return ACFUtil.join(args, sep); +237 } +238} diff --git a/docs/acf-core/src-html/co/aikar/commands/CommandManager.html b/docs/acf-core/src-html/co/aikar/commands/CommandManager.html index 6cd98236..3c7c8d80 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandManager.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandManager.html @@ -56,14 +56,14 @@ 048 049 050@SuppressWarnings("WeakerAccess") -051public abstract class CommandManager < +051public abstract class CommandManager< 052 IT, 053 I extends CommandIssuer, 054 FT, 055 MF extends MessageFormatter<FT>, 056 CEC extends CommandExecutionContext<CEC, I>, 057 CC extends ConditionContext<I> -058 > { +058 > { 059 060 /** 061 * This is a stack incase a command calls a command @@ -121,7 +121,7 @@ 113 public void setFormat(MessageType type, FT... colors) { 114 MF format = getFormat(type); 115 for (int i = 1; i <= colors.length; i++) { -116 format.setColor(i, colors[i-1]); +116 format.setColor(i, colors[i - 1]); 117 } 118 } 119 @@ -144,402 +144,452 @@ 136 137 /** 138 * Gets the command contexts manager -139 * @return Command Contexts -140 */ -141 public abstract CommandContexts<?> getCommandContexts(); -142 -143 /** -144 * Gets the command completions manager -145 * @return Command Completions -146 */ -147 public abstract CommandCompletions<?> getCommandCompletions(); -148 -149 /** @deprecated Unstable API */ @Deprecated @UnstableAPI -150 public CommandHelp generateCommandHelp(@NotNull String command) { -151 verifyUnstableAPI("help"); -152 CommandOperationContext context = getCurrentCommandOperationContext(); -153 if (context == null) { -154 throw new IllegalStateException("This method can only be called as part of a command execution."); -155 } -156 return generateCommandHelp(context.getCommandIssuer(), command); -157 } -158 -159 /** @deprecated Unstable API */ @Deprecated @UnstableAPI -160 public CommandHelp generateCommandHelp(CommandIssuer issuer, @NotNull String command) { -161 verifyUnstableAPI("help"); -162 return generateCommandHelp(issuer, obtainRootCommand(command)); +139 * +140 * @return Command Contexts +141 */ +142 public abstract CommandContexts<?> getCommandContexts(); +143 +144 /** +145 * Gets the command completions manager +146 * +147 * @return Command Completions +148 */ +149 public abstract CommandCompletions<?> getCommandCompletions(); +150 +151 /** +152 * @deprecated Unstable API +153 */ +154 @Deprecated +155 @UnstableAPI +156 public CommandHelp generateCommandHelp(@NotNull String command) { +157 verifyUnstableAPI("help"); +158 CommandOperationContext context = getCurrentCommandOperationContext(); +159 if (context == null) { +160 throw new IllegalStateException("This method can only be called as part of a command execution."); +161 } +162 return generateCommandHelp(context.getCommandIssuer(), command); 163 } 164 -165 /** @deprecated Unstable API */ @Deprecated @UnstableAPI -166 public CommandHelp generateCommandHelp() { -167 verifyUnstableAPI("help"); -168 CommandOperationContext context = getCurrentCommandOperationContext(); -169 if (context == null) { -170 throw new IllegalStateException("This method can only be called as part of a command execution."); -171 } -172 String commandLabel = context.getCommandLabel(); -173 return generateCommandHelp(context.getCommandIssuer(), this.obtainRootCommand(commandLabel)); -174 } -175 -176 /** @deprecated Unstable API */ @Deprecated @UnstableAPI -177 public CommandHelp generateCommandHelp(CommandIssuer issuer, RootCommand rootCommand) { -178 verifyUnstableAPI("help"); -179 return new CommandHelp(this, rootCommand, issuer); -180 } -181 -182 /** @deprecated Unstable API */ @Deprecated @UnstableAPI -183 public int getDefaultHelpPerPage() { -184 verifyUnstableAPI("help"); -185 return defaultHelpPerPage; -186 } -187 -188 /** @deprecated Unstable API */ @Deprecated @UnstableAPI -189 public void setDefaultHelpPerPage(int defaultHelpPerPage) { -190 verifyUnstableAPI("help"); -191 this.defaultHelpPerPage = defaultHelpPerPage; -192 } -193 /** @deprecated Unstable API */ @Deprecated @UnstableAPI -194 public void setHelpFormatter(CommandHelpFormatter helpFormatter) { -195 this.helpFormatter = helpFormatter; -196 } -197 -198 /** @deprecated Unstable API */ @Deprecated @UnstableAPI -199 public CommandHelpFormatter getHelpFormatter() { -200 return helpFormatter; -201 } -202 -203 CommandRouter getRouter() { -204 return router; -205 } -206 -207 /** -208 * Registers a command with ACF -209 * -210 * @param command The command to register -211 * @return boolean +165 /** +166 * @deprecated Unstable API +167 */ +168 @Deprecated +169 @UnstableAPI +170 public CommandHelp generateCommandHelp(CommandIssuer issuer, @NotNull String command) { +171 verifyUnstableAPI("help"); +172 return generateCommandHelp(issuer, obtainRootCommand(command)); +173 } +174 +175 /** +176 * @deprecated Unstable API +177 */ +178 @Deprecated +179 @UnstableAPI +180 public CommandHelp generateCommandHelp() { +181 verifyUnstableAPI("help"); +182 CommandOperationContext context = getCurrentCommandOperationContext(); +183 if (context == null) { +184 throw new IllegalStateException("This method can only be called as part of a command execution."); +185 } +186 String commandLabel = context.getCommandLabel(); +187 return generateCommandHelp(context.getCommandIssuer(), this.obtainRootCommand(commandLabel)); +188 } +189 +190 /** +191 * @deprecated Unstable API +192 */ +193 @Deprecated +194 @UnstableAPI +195 public CommandHelp generateCommandHelp(CommandIssuer issuer, RootCommand rootCommand) { +196 verifyUnstableAPI("help"); +197 return new CommandHelp(this, rootCommand, issuer); +198 } +199 +200 /** +201 * @deprecated Unstable API +202 */ +203 @Deprecated +204 @UnstableAPI +205 public int getDefaultHelpPerPage() { +206 verifyUnstableAPI("help"); +207 return defaultHelpPerPage; +208 } +209 +210 /** +211 * @deprecated Unstable API 212 */ -213 public abstract void registerCommand(BaseCommand command); -214 public abstract boolean hasRegisteredCommands(); -215 public abstract boolean isCommandIssuer(Class<?> type); -216 -217 // TODO: Change this to IT if we make a breaking change -218 public abstract I getCommandIssuer(Object issuer); +213 @Deprecated +214 @UnstableAPI +215 public void setDefaultHelpPerPage(int defaultHelpPerPage) { +216 verifyUnstableAPI("help"); +217 this.defaultHelpPerPage = defaultHelpPerPage; +218 } 219 -220 public abstract RootCommand createRootCommand(String cmd); -221 -222 /** -223 * Returns a Locales Manager to add and modify language tables for your commands. -224 * @return -225 */ -226 public abstract Locales getLocales(); -227 -228 public boolean usingPerIssuerLocale() { -229 return usePerIssuerLocale; -230 } -231 -232 public boolean usePerIssuerLocale(boolean setting) { -233 boolean old = usePerIssuerLocale; -234 usePerIssuerLocale = setting; -235 return old; +220 /** +221 * @deprecated Unstable API +222 */ +223 @Deprecated +224 @UnstableAPI +225 public void setHelpFormatter(CommandHelpFormatter helpFormatter) { +226 this.helpFormatter = helpFormatter; +227 } +228 +229 /** +230 * @deprecated Unstable API +231 */ +232 @Deprecated +233 @UnstableAPI +234 public CommandHelpFormatter getHelpFormatter() { +235 return helpFormatter; 236 } 237 -238 public ConditionContext createConditionContext(CommandIssuer issuer, String config) { -239 //noinspection unchecked -240 return new ConditionContext(issuer, config); -241 } -242 -243 public abstract CommandExecutionContext createCommandContext(RegisteredCommand command, CommandParameter parameter, CommandIssuer sender, List<String> args, int i, Map<String, Object> passedArgs); -244 -245 public abstract CommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args); -246 -247 public abstract void log(final LogLevel level, final String message, final Throwable throwable); -248 -249 public void log(final LogLevel level, final String message) { -250 log(level, message, null); -251 } -252 -253 /** -254 * Lets you add custom string replacements that can be applied to annotation values, -255 * to reduce duplication/repetition of common values such as permission nodes and command prefixes. -256 * -257 * Any replacement registered starts with a % -258 * -259 * So for ex @CommandPermission("%staff") -260 * @return Replacements Manager -261 */ -262 public CommandReplacements getCommandReplacements() { -263 return replacements; -264 } +238 CommandRouter getRouter() { +239 return router; +240 } +241 +242 /** +243 * Registers a command with ACF +244 * +245 * @param command The command to register +246 * @return boolean +247 */ +248 public abstract void registerCommand(BaseCommand command); +249 +250 public abstract boolean hasRegisteredCommands(); +251 +252 public abstract boolean isCommandIssuer(Class<?> type); +253 +254 // TODO: Change this to IT if we make a breaking change +255 public abstract I getCommandIssuer(Object issuer); +256 +257 public abstract RootCommand createRootCommand(String cmd); +258 +259 /** +260 * Returns a Locales Manager to add and modify language tables for your commands. +261 * +262 * @return +263 */ +264 public abstract Locales getLocales(); 265 -266 public boolean hasPermission(CommandIssuer issuer, String permission) { -267 if (permission == null || permission.isEmpty()) { -268 return true; -269 } -270 for (String perm : ACFPatterns.COMMA.split(permission)) { -271 if (!perm.isEmpty() && !issuer.hasPermission(perm)) { -272 return false; -273 } -274 } -275 return true; -276 } -277 -278 public synchronized RootCommand getRootCommand(@NotNull String cmd) { -279 return rootCommands.get(ACFPatterns.SPACE.split(cmd.toLowerCase(), 2)[0]); -280 } -281 -282 public synchronized RootCommand obtainRootCommand(@NotNull String cmd) { -283 return rootCommands.computeIfAbsent(ACFPatterns.SPACE.split(cmd.toLowerCase(), 2)[0], this::createRootCommand); -284 } -285 -286 public abstract Collection<RootCommand> getRegisteredRootCommands(); -287 -288 public RegisteredCommand createRegisteredCommand(BaseCommand command, String cmdName, Method method, String prefSubCommand) { -289 return new RegisteredCommand(command, cmdName, method, prefSubCommand); -290 } -291 -292 /** -293 * Sets the default {@link ExceptionHandler} that is called when an exception occurs while executing a command, if the command doesn't have it's own exception handler registered. -294 * -295 * @param exceptionHandler the handler that should handle uncaught exceptions. May not be null if logExceptions is false -296 */ -297 public void setDefaultExceptionHandler(ExceptionHandler exceptionHandler) { -298 if (exceptionHandler == null && !this.logUnhandledExceptions) { -299 throw new IllegalArgumentException("You may not disable the default exception handler and have logging of unhandled exceptions disabled"); -300 } -301 defaultExceptionHandler = exceptionHandler; -302 } -303 -304 /** -305 * Sets the default {@link ExceptionHandler} that is called when an exception occurs while executing a command, if the command doesn't have it's own exception handler registered, and lets you control if ACF should also log the exception still. -306 * <p> -307 * If you disable logging, you need to log it yourself in your handler. -308 * -309 * @param exceptionHandler the handler that should handle uncaught exceptions. May not be null if logExceptions is false -310 * @param logExceptions Whether or not to log exceptions. -311 */ -312 public void setDefaultExceptionHandler(ExceptionHandler exceptionHandler, boolean logExceptions) { -313 if (exceptionHandler == null && !logExceptions) { -314 throw new IllegalArgumentException("You may not disable the default exception handler and have logging of unhandled exceptions disabled"); -315 } -316 this.logUnhandledExceptions = logExceptions; -317 this.defaultExceptionHandler = exceptionHandler; -318 } -319 -320 public boolean isLoggingUnhandledExceptions() { -321 return this.logUnhandledExceptions; -322 } -323 -324 /** -325 * Gets the current default exception handler, might be null. -326 * -327 * @return the default exception handler -328 */ -329 public ExceptionHandler getDefaultExceptionHandler() { -330 return defaultExceptionHandler; -331 } -332 -333 protected boolean handleUncaughtException(BaseCommand scope, RegisteredCommand registeredCommand, CommandIssuer sender, List<String> args, Throwable t) { -334 if (t instanceof InvocationTargetException && t.getCause() != null) { -335 t = t.getCause(); -336 } -337 boolean result = false; -338 if (scope.getExceptionHandler() != null) { -339 result = scope.getExceptionHandler().execute(scope, registeredCommand, sender, args, t); -340 } else if (defaultExceptionHandler != null) { -341 result = defaultExceptionHandler.execute(scope, registeredCommand, sender, args, t); -342 } -343 return result; -344 } -345 -346 public void sendMessage(IT issuerArg, MessageType type, MessageKeyProvider key, String... replacements) { -347 sendMessage(getCommandIssuer(issuerArg), type, key, replacements); -348 } -349 -350 public void sendMessage(CommandIssuer issuer, MessageType type, MessageKeyProvider key, String... replacements) { -351 String message = formatMessage(issuer, type, key, replacements); -352 -353 for (String msg : ACFPatterns.NEWLINE.split(message)) { -354 issuer.sendMessageInternal(ACFUtil.rtrim(msg)); -355 } -356 } -357 -358 public String formatMessage(CommandIssuer issuer, MessageType type, MessageKeyProvider key, String... replacements) { -359 String message = getLocales().getMessage(issuer, key.getMessageKey()); -360 if (replacements.length > 0) { -361 message = ACFUtil.replaceStrings(message, replacements); -362 } -363 -364 message = getCommandReplacements().replace(message); -365 message = getLocales().replaceI18NStrings(message); -366 -367 MessageFormatter formatter = formatters.getOrDefault(type, defaultFormatter); -368 if (formatter != null) { -369 message = formatter.format(message); -370 } -371 return message; -372 } -373 -374 public void onLocaleChange(IssuerLocaleChangedCallback<I> onChange) { -375 localeChangedCallbacks.add(onChange); -376 } -377 -378 public void notifyLocaleChange(I issuer, Locale oldLocale, Locale newLocale) { -379 localeChangedCallbacks.forEach(cb -> { -380 try { -381 cb.onIssuerLocaleChange(issuer, oldLocale, newLocale); -382 } catch (Exception e) { -383 this.log(LogLevel.ERROR, "Error in notifyLocaleChange", e); -384 } -385 }); -386 } -387 -388 public Locale setIssuerLocale(IT issuer, Locale locale) { -389 I commandIssuer = getCommandIssuer(issuer); -390 -391 Locale old = issuersLocale.put(commandIssuer.getUniqueId(), locale); -392 if (!Objects.equals(old, locale)) { -393 this.notifyLocaleChange(commandIssuer, old, locale); -394 } -395 -396 return old; -397 } -398 -399 public Locale getIssuerLocale(CommandIssuer issuer) { -400 if (usingPerIssuerLocale() && issuer != null) { -401 Locale locale = issuersLocale.get(issuer.getUniqueId()); -402 if (locale != null) { -403 return locale; -404 } -405 } -406 -407 return getLocales().getDefaultLocale(); -408 } -409 -410 CommandOperationContext<I> createCommandOperationContext(BaseCommand command, CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) { -411 //noinspection unchecked -412 return new CommandOperationContext<>( -413 this, -414 (I) issuer, -415 command, -416 commandLabel, -417 args, -418 isAsync -419 ); +266 public boolean usingPerIssuerLocale() { +267 return usePerIssuerLocale; +268 } +269 +270 public boolean usePerIssuerLocale(boolean setting) { +271 boolean old = usePerIssuerLocale; +272 usePerIssuerLocale = setting; +273 return old; +274 } +275 +276 public ConditionContext createConditionContext(CommandIssuer issuer, String config) { +277 //noinspection unchecked +278 return new ConditionContext(issuer, config); +279 } +280 +281 public abstract CommandExecutionContext createCommandContext(RegisteredCommand command, CommandParameter parameter, CommandIssuer sender, List<String> args, int i, Map<String, Object> passedArgs); +282 +283 public abstract CommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args); +284 +285 public abstract void log(final LogLevel level, final String message, final Throwable throwable); +286 +287 public void log(final LogLevel level, final String message) { +288 log(level, message, null); +289 } +290 +291 /** +292 * Lets you add custom string replacements that can be applied to annotation values, +293 * to reduce duplication/repetition of common values such as permission nodes and command prefixes. +294 * <p> +295 * Any replacement registered starts with a % +296 * <p> +297 * So for ex @CommandPermission("%staff") +298 * +299 * @return Replacements Manager +300 */ +301 public CommandReplacements getCommandReplacements() { +302 return replacements; +303 } +304 +305 public boolean hasPermission(CommandIssuer issuer, Set<String> permissions) { +306 for (String permission : permissions) { +307 if (!hasPermission(issuer, permission)) { +308 return false; +309 } +310 } +311 return true; +312 } +313 +314 public boolean hasPermission(CommandIssuer issuer, String permission) { +315 if (permission == null || permission.isEmpty()) { +316 return true; +317 } +318 for (String perm : ACFPatterns.COMMA.split(permission)) { +319 if (!perm.isEmpty() && !issuer.hasPermission(perm)) { +320 return false; +321 } +322 } +323 return true; +324 } +325 +326 public synchronized RootCommand getRootCommand(@NotNull String cmd) { +327 return rootCommands.get(ACFPatterns.SPACE.split(cmd.toLowerCase(), 2)[0]); +328 } +329 +330 public synchronized RootCommand obtainRootCommand(@NotNull String cmd) { +331 return rootCommands.computeIfAbsent(ACFPatterns.SPACE.split(cmd.toLowerCase(), 2)[0], this::createRootCommand); +332 } +333 +334 public abstract Collection<RootCommand> getRegisteredRootCommands(); +335 +336 public RegisteredCommand createRegisteredCommand(BaseCommand command, String cmdName, Method method, String prefSubCommand) { +337 return new RegisteredCommand(command, cmdName, method, prefSubCommand); +338 } +339 +340 /** +341 * Sets the default {@link ExceptionHandler} that is called when an exception occurs while executing a command, if the command doesn't have it's own exception handler registered. +342 * +343 * @param exceptionHandler the handler that should handle uncaught exceptions. May not be null if logExceptions is false +344 */ +345 public void setDefaultExceptionHandler(ExceptionHandler exceptionHandler) { +346 if (exceptionHandler == null && !this.logUnhandledExceptions) { +347 throw new IllegalArgumentException("You may not disable the default exception handler and have logging of unhandled exceptions disabled"); +348 } +349 defaultExceptionHandler = exceptionHandler; +350 } +351 +352 /** +353 * Sets the default {@link ExceptionHandler} that is called when an exception occurs while executing a command, if the command doesn't have it's own exception handler registered, and lets you control if ACF should also log the exception still. +354 * <p> +355 * If you disable logging, you need to log it yourself in your handler. +356 * +357 * @param exceptionHandler the handler that should handle uncaught exceptions. May not be null if logExceptions is false +358 * @param logExceptions Whether or not to log exceptions. +359 */ +360 public void setDefaultExceptionHandler(ExceptionHandler exceptionHandler, boolean logExceptions) { +361 if (exceptionHandler == null && !logExceptions) { +362 throw new IllegalArgumentException("You may not disable the default exception handler and have logging of unhandled exceptions disabled"); +363 } +364 this.logUnhandledExceptions = logExceptions; +365 this.defaultExceptionHandler = exceptionHandler; +366 } +367 +368 public boolean isLoggingUnhandledExceptions() { +369 return this.logUnhandledExceptions; +370 } +371 +372 /** +373 * Gets the current default exception handler, might be null. +374 * +375 * @return the default exception handler +376 */ +377 public ExceptionHandler getDefaultExceptionHandler() { +378 return defaultExceptionHandler; +379 } +380 +381 protected boolean handleUncaughtException(BaseCommand scope, RegisteredCommand registeredCommand, CommandIssuer sender, List<String> args, Throwable t) { +382 if (t instanceof InvocationTargetException && t.getCause() != null) { +383 t = t.getCause(); +384 } +385 boolean result = false; +386 if (scope.getExceptionHandler() != null) { +387 result = scope.getExceptionHandler().execute(scope, registeredCommand, sender, args, t); +388 } else if (defaultExceptionHandler != null) { +389 result = defaultExceptionHandler.execute(scope, registeredCommand, sender, args, t); +390 } +391 return result; +392 } +393 +394 public void sendMessage(IT issuerArg, MessageType type, MessageKeyProvider key, String... replacements) { +395 sendMessage(getCommandIssuer(issuerArg), type, key, replacements); +396 } +397 +398 public void sendMessage(CommandIssuer issuer, MessageType type, MessageKeyProvider key, String... replacements) { +399 String message = formatMessage(issuer, type, key, replacements); +400 +401 for (String msg : ACFPatterns.NEWLINE.split(message)) { +402 issuer.sendMessageInternal(ACFUtil.rtrim(msg)); +403 } +404 } +405 +406 public String formatMessage(CommandIssuer issuer, MessageType type, MessageKeyProvider key, String... replacements) { +407 String message = getLocales().getMessage(issuer, key.getMessageKey()); +408 if (replacements.length > 0) { +409 message = ACFUtil.replaceStrings(message, replacements); +410 } +411 +412 message = getCommandReplacements().replace(message); +413 message = getLocales().replaceI18NStrings(message); +414 +415 MessageFormatter formatter = formatters.getOrDefault(type, defaultFormatter); +416 if (formatter != null) { +417 message = formatter.format(message); +418 } +419 return message; 420 } 421 -422 /** -423 * Gets a list of all currently supported languages for this manager. -424 * These locales will be automatically loaded from -425 * @return -426 */ -427 public Set<Locale> getSupportedLanguages() { -428 return supportedLanguages; -429 } -430 -431 /** -432 * Adds a new locale to the list of automatic Locales to load Message Bundles for. -433 * All bundles loaded under the previous supported languages will now automatically load for this new locale too. -434 * -435 * @param locale -436 */ -437 public void addSupportedLanguage(Locale locale) { -438 supportedLanguages.add(locale); -439 getLocales().loadMissingBundles(); -440 } -441 -442 /** -443 * Registers an instance of a class to be registered as an injectable dependency.<br> -444 * The command manager will attempt to inject all fields in a command class that are annotated with -445 * {@link co.aikar.commands.annotation.Dependency} with the provided instance. -446 * -447 * @param clazz the class the injector should look for when injecting -448 * @param instance the instance of the class that should be injected -449 * @throws IllegalStateException when there is already an instance for the provided class registered -450 */ -451 public <T> void registerDependency(Class<? extends T> clazz, T instance){ -452 registerDependency(clazz, clazz.getName(), instance); -453 } +422 public void onLocaleChange(IssuerLocaleChangedCallback<I> onChange) { +423 localeChangedCallbacks.add(onChange); +424 } +425 +426 public void notifyLocaleChange(I issuer, Locale oldLocale, Locale newLocale) { +427 localeChangedCallbacks.forEach(cb -> { +428 try { +429 cb.onIssuerLocaleChange(issuer, oldLocale, newLocale); +430 } catch (Exception e) { +431 this.log(LogLevel.ERROR, "Error in notifyLocaleChange", e); +432 } +433 }); +434 } +435 +436 public Locale setIssuerLocale(IT issuer, Locale locale) { +437 I commandIssuer = getCommandIssuer(issuer); +438 +439 Locale old = issuersLocale.put(commandIssuer.getUniqueId(), locale); +440 if (!Objects.equals(old, locale)) { +441 this.notifyLocaleChange(commandIssuer, old, locale); +442 } +443 +444 return old; +445 } +446 +447 public Locale getIssuerLocale(CommandIssuer issuer) { +448 if (usingPerIssuerLocale() && issuer != null) { +449 Locale locale = issuersLocale.get(issuer.getUniqueId()); +450 if (locale != null) { +451 return locale; +452 } +453 } 454 -455 /** -456 * Registers an instance of a class to be registered as an injectable dependency.<br> -457 * The command manager will attempt to inject all fields in a command class that are annotated with -458 * {@link co.aikar.commands.annotation.Dependency} with the provided instance. -459 * -460 * @param clazz the class the injector should look for when injecting -461 * @param key the key which needs to be present if that -462 * @param instance the instance of the class that should be injected -463 * @throws IllegalStateException when there is already an instance for the provided class registered -464 */ -465 public <T> void registerDependency(Class<? extends T> clazz, String key, T instance){ -466 if (dependencies.containsKey(clazz, key)) { -467 throw new IllegalStateException("There is already an instance of " + clazz.getName() + " with the key " + key + " registered!"); -468 } +455 return getLocales().getDefaultLocale(); +456 } +457 +458 CommandOperationContext<I> createCommandOperationContext(BaseCommand command, CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) { +459 //noinspection unchecked +460 return new CommandOperationContext<>( +461 this, +462 (I) issuer, +463 command, +464 commandLabel, +465 args, +466 isAsync +467 ); +468 } 469 -470 dependencies.put(clazz, key, instance); -471 } -472 -473 /** -474 * Attempts to inject instances of classes registered with {@link CommandManager#registerDependency(Class, Object)} -475 * into all fields of the class and its superclasses that are marked with {@link Dependency}. -476 * -477 * @param baseCommand the instance which fields should be filled -478 */ -479 void injectDependencies(BaseCommand baseCommand) { -480 Class clazz = baseCommand.getClass(); -481 do { -482 for (Field field : clazz.getDeclaredFields()) { -483 if (annotations.hasAnnotation(field, Dependency.class)) { -484 String dependency = annotations.getAnnotationValue(field, Dependency.class); -485 String key = (key = dependency).isEmpty() ? field.getType().getName() : key; -486 Object object = dependencies.row(field.getType()).get(key); -487 if (object == null) { -488 throw new UnresolvedDependencyException("Could not find a registered instance of " + -489 field.getType().getName() + " with key " + key + " for field " + field.getName() + -490 " in class " + baseCommand.getClass().getName()); -491 } -492 -493 try { -494 boolean accessible = field.isAccessible(); -495 if (!accessible) { -496 field.setAccessible(true); -497 } -498 field.set(baseCommand, object); -499 field.setAccessible(accessible); -500 } catch (IllegalAccessException e) { -501 e.printStackTrace(); //TODO should we print our own exception here to make a more descriptive error? -502 } -503 } -504 } -505 clazz = clazz.getSuperclass(); -506 } while (!clazz.equals(BaseCommand.class)); -507 } -508 -509 /** -510 * @deprecated Use this with caution! If you enable and use Unstable API's, your next compile using ACF -511 * may require you to update your implementation to those unstable API's -512 */ -513 @Deprecated -514 public void enableUnstableAPI(String api) { -515 unstableAPIs.add(api); -516 } -517 void verifyUnstableAPI(String api) { -518 if (!unstableAPIs.contains(api)) { -519 throw new IllegalStateException("Using an unstable API that has not been enabled ( " + api + "). See https://acfunstable.emc.gs"); -520 } -521 } -522 -523 boolean hasUnstableAPI(String api) { -524 return unstableAPIs.contains(api); -525 } -526 -527 Annotations getAnnotations() { -528 return annotations; -529 } -530 -531 public String getCommandPrefix(CommandIssuer issuer) { -532 return ""; -533 } -534} +470 /** +471 * Gets a list of all currently supported languages for this manager. +472 * These locales will be automatically loaded from +473 * +474 * @return +475 */ +476 public Set<Locale> getSupportedLanguages() { +477 return supportedLanguages; +478 } +479 +480 /** +481 * Adds a new locale to the list of automatic Locales to load Message Bundles for. +482 * All bundles loaded under the previous supported languages will now automatically load for this new locale too. +483 * +484 * @param locale +485 */ +486 public void addSupportedLanguage(Locale locale) { +487 supportedLanguages.add(locale); +488 getLocales().loadMissingBundles(); +489 } +490 +491 /** +492 * Registers an instance of a class to be registered as an injectable dependency.<br> +493 * The command manager will attempt to inject all fields in a command class that are annotated with +494 * {@link co.aikar.commands.annotation.Dependency} with the provided instance. +495 * +496 * @param clazz the class the injector should look for when injecting +497 * @param instance the instance of the class that should be injected +498 * @throws IllegalStateException when there is already an instance for the provided class registered +499 */ +500 public <T> void registerDependency(Class<? extends T> clazz, T instance) { +501 registerDependency(clazz, clazz.getName(), instance); +502 } +503 +504 /** +505 * Registers an instance of a class to be registered as an injectable dependency.<br> +506 * The command manager will attempt to inject all fields in a command class that are annotated with +507 * {@link co.aikar.commands.annotation.Dependency} with the provided instance. +508 * +509 * @param clazz the class the injector should look for when injecting +510 * @param key the key which needs to be present if that +511 * @param instance the instance of the class that should be injected +512 * @throws IllegalStateException when there is already an instance for the provided class registered +513 */ +514 public <T> void registerDependency(Class<? extends T> clazz, String key, T instance) { +515 if (dependencies.containsKey(clazz, key)) { +516 throw new IllegalStateException("There is already an instance of " + clazz.getName() + " with the key " + key + " registered!"); +517 } +518 +519 dependencies.put(clazz, key, instance); +520 } +521 +522 /** +523 * Attempts to inject instances of classes registered with {@link CommandManager#registerDependency(Class, Object)} +524 * into all fields of the class and its superclasses that are marked with {@link Dependency}. +525 * +526 * @param baseCommand the instance which fields should be filled +527 */ +528 void injectDependencies(BaseCommand baseCommand) { +529 Class clazz = baseCommand.getClass(); +530 do { +531 for (Field field : clazz.getDeclaredFields()) { +532 if (annotations.hasAnnotation(field, Dependency.class)) { +533 String dependency = annotations.getAnnotationValue(field, Dependency.class); +534 String key = (key = dependency).isEmpty() ? field.getType().getName() : key; +535 Object object = dependencies.row(field.getType()).get(key); +536 if (object == null) { +537 throw new UnresolvedDependencyException("Could not find a registered instance of " + +538 field.getType().getName() + " with key " + key + " for field " + field.getName() + +539 " in class " + baseCommand.getClass().getName()); +540 } +541 +542 try { +543 boolean accessible = field.isAccessible(); +544 if (!accessible) { +545 field.setAccessible(true); +546 } +547 field.set(baseCommand, object); +548 field.setAccessible(accessible); +549 } catch (IllegalAccessException e) { +550 e.printStackTrace(); //TODO should we print our own exception here to make a more descriptive error? +551 } +552 } +553 } +554 clazz = clazz.getSuperclass(); +555 } while (!clazz.equals(BaseCommand.class)); +556 } +557 +558 /** +559 * @deprecated Use this with caution! If you enable and use Unstable API's, your next compile using ACF +560 * may require you to update your implementation to those unstable API's +561 */ +562 @Deprecated +563 public void enableUnstableAPI(String api) { +564 unstableAPIs.add(api); +565 } +566 +567 void verifyUnstableAPI(String api) { +568 if (!unstableAPIs.contains(api)) { +569 throw new IllegalStateException("Using an unstable API that has not been enabled ( " + api + "). See https://acfunstable.emc.gs"); +570 } +571 } +572 +573 boolean hasUnstableAPI(String api) { +574 return unstableAPIs.contains(api); +575 } +576 +577 Annotations getAnnotations() { +578 return annotations; +579 } +580 +581 public String getCommandPrefix(CommandIssuer issuer) { +582 return ""; +583 } +584} diff --git a/docs/acf-core/src-html/co/aikar/commands/CommandOperationContext.html b/docs/acf-core/src-html/co/aikar/commands/CommandOperationContext.html index 5852da15..3440a71d 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandOperationContext.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandOperationContext.html @@ -32,83 +32,86 @@ 024package co.aikar.commands; 025 026import java.lang.annotation.Annotation; -027 -028/** -029 * Holds information about the currently executing command on this thread -030 */ -031public class CommandOperationContext <I extends CommandIssuer> { -032 -033 private final CommandManager manager; -034 private final I issuer; -035 private final BaseCommand command; -036 private final String commandLabel; -037 private final String[] args; -038 private final boolean isAsync; -039 private RegisteredCommand registeredCommand; -040 -041 CommandOperationContext(CommandManager manager, I issuer, BaseCommand command, String commandLabel, String[] args, boolean isAsync) { -042 this.manager = manager; -043 this.issuer = issuer; -044 this.command = command; -045 this.commandLabel = commandLabel; -046 this.args = args; -047 this.isAsync = isAsync; -048 } -049 -050 public CommandManager getCommandManager() { -051 return manager; -052 } -053 -054 public I getCommandIssuer() { -055 return issuer; -056 } -057 -058 public BaseCommand getCommand() { -059 return command; -060 } -061 -062 public String getCommandLabel() { -063 return commandLabel; -064 } -065 -066 public String[] getArgs() { -067 return args; -068 } -069 -070 public boolean isAsync() { -071 return isAsync; -072 } -073 -074 public void setRegisteredCommand(RegisteredCommand registeredCommand) { -075 this.registeredCommand = registeredCommand; -076 } -077 -078 public RegisteredCommand getRegisteredCommand() { -079 return registeredCommand; -080 } -081 -082 /** -083 * This method will not support annotation processors!! use getAnnotationValue or hasAnnotation -084 * @deprecated Use {@link #getAnnotationValue(Class)} -085 */ -086 @Deprecated -087 public <T extends Annotation> T getAnnotation(Class<T> anno) { -088 return registeredCommand.method.getAnnotation(anno); -089 } -090 -091 public <T extends Annotation> String getAnnotationValue(Class<T> cls) { -092 return manager.getAnnotations().getAnnotationValue(registeredCommand.method, cls); -093 } -094 -095 public <T extends Annotation> String getAnnotationValue(Class<T> cls, int options) { -096 return manager.getAnnotations().getAnnotationValue(registeredCommand.method, cls, options); -097 } -098 -099 public boolean hasAnnotation(Class<? extends Annotation> anno) { -100 return getAnnotation(anno) != null; -101 } -102 -103} +027import java.util.List; +028 +029/** +030 * Holds information about the currently executing command on this thread +031 */ +032public class CommandOperationContext<I extends CommandIssuer> { +033 +034 private final CommandManager manager; +035 private final I issuer; +036 private final BaseCommand command; +037 private final String commandLabel; +038 private final String[] args; +039 private final boolean isAsync; +040 private RegisteredCommand registeredCommand; +041 List<String> enumCompletionValues; +042 +043 CommandOperationContext(CommandManager manager, I issuer, BaseCommand command, String commandLabel, String[] args, boolean isAsync) { +044 this.manager = manager; +045 this.issuer = issuer; +046 this.command = command; +047 this.commandLabel = commandLabel; +048 this.args = args; +049 this.isAsync = isAsync; +050 } +051 +052 public CommandManager getCommandManager() { +053 return manager; +054 } +055 +056 public I getCommandIssuer() { +057 return issuer; +058 } +059 +060 public BaseCommand getCommand() { +061 return command; +062 } +063 +064 public String getCommandLabel() { +065 return commandLabel; +066 } +067 +068 public String[] getArgs() { +069 return args; +070 } +071 +072 public boolean isAsync() { +073 return isAsync; +074 } +075 +076 public void setRegisteredCommand(RegisteredCommand registeredCommand) { +077 this.registeredCommand = registeredCommand; +078 } +079 +080 public RegisteredCommand getRegisteredCommand() { +081 return registeredCommand; +082 } +083 +084 /** +085 * This method will not support annotation processors!! use getAnnotationValue or hasAnnotation +086 * +087 * @deprecated Use {@link #getAnnotationValue(Class)} +088 */ +089 @Deprecated +090 public <T extends Annotation> T getAnnotation(Class<T> anno) { +091 return registeredCommand.method.getAnnotation(anno); +092 } +093 +094 public <T extends Annotation> String getAnnotationValue(Class<T> cls) { +095 return manager.getAnnotations().getAnnotationValue(registeredCommand.method, cls); +096 } +097 +098 public <T extends Annotation> String getAnnotationValue(Class<T> cls, int options) { +099 return manager.getAnnotations().getAnnotationValue(registeredCommand.method, cls, options); +100 } +101 +102 public boolean hasAnnotation(Class<? extends Annotation> anno) { +103 return getAnnotation(anno) != null; +104 } +105 +106} diff --git a/docs/acf-core/src-html/co/aikar/commands/CommandParameter.html b/docs/acf-core/src-html/co/aikar/commands/CommandParameter.html index 362a6689..795614ab 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandParameter.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandParameter.html @@ -31,240 +31,259 @@ 023 024package co.aikar.commands; 025 -026import co.aikar.commands.annotation.Conditions; -027import co.aikar.commands.annotation.Default; -028import co.aikar.commands.annotation.Description; -029import co.aikar.commands.annotation.Flags; -030import co.aikar.commands.annotation.Optional; -031import co.aikar.commands.annotation.Single; -032import co.aikar.commands.annotation.Syntax; -033import co.aikar.commands.annotation.Values; -034import co.aikar.commands.contexts.ContextResolver; -035import co.aikar.commands.contexts.IssuerAwareContextResolver; -036import co.aikar.commands.contexts.IssuerOnlyContextResolver; -037import co.aikar.commands.contexts.OptionalContextResolver; -038 -039import java.lang.reflect.Parameter; -040import java.util.HashMap; -041import java.util.Map; -042 -043public class CommandParameter <CEC extends CommandExecutionContext<CEC, ? extends CommandIssuer>> { -044 private final Parameter parameter; -045 private final Class<?> type; -046 private final String name; -047 private final CommandManager manager; -048 private final int paramIndex; -049 -050 private ContextResolver<?, CEC> resolver; -051 private boolean optional; -052 private String description; -053 private String defaultValue; -054 private String syntax; -055 private String conditions; -056 private boolean requiresInput; -057 private boolean commandIssuer; -058 private String[] values; -059 private Map<String, String> flags; -060 private boolean canConsumeInput; -061 private boolean optionalResolver; -062 boolean consumesRest; -063 -064 public CommandParameter(RegisteredCommand<CEC> command, Parameter param, int paramIndex, boolean isLast) { -065 this.parameter = param; -066 this.type = param.getType(); -067 this.name = param.getName(); // do we care for an annotation to supply name? -068 this.manager = command.manager; -069 this.paramIndex = paramIndex; -070 Annotations annotations = manager.getAnnotations(); -071 -072 this.defaultValue = annotations.getAnnotationValue(param, Default.class, Annotations.REPLACEMENTS | (type != String.class ? Annotations.NO_EMPTY : 0)); -073 this.description = annotations.getAnnotationValue(param, Description.class, Annotations.REPLACEMENTS | Annotations.DEFAULT_EMPTY); -074 this.conditions = annotations.getAnnotationValue(param, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); -075 -076 //noinspection unchecked -077 this.resolver = manager.getCommandContexts().getResolver(type); -078 if (this.resolver == null) { -079 ACFUtil.sneaky(new InvalidCommandContextException( -080 "Parameter " + type.getSimpleName() + " of " + command + " has no applicable context resolver" -081 )); -082 } -083 -084 this.optional = annotations.hasAnnotation(param, Optional.class) || this.defaultValue != null || (isLast && type == String[].class); -085 this.optionalResolver = isOptionalResolver(resolver); -086 this.requiresInput = !this.optional && !this.optionalResolver; -087 //noinspection unchecked -088 this.commandIssuer = paramIndex == 0 && manager.isCommandIssuer(type); -089 this.canConsumeInput = !this.commandIssuer && !(resolver instanceof IssuerOnlyContextResolver); -090 this.consumesRest = (type == String.class && !annotations.hasAnnotation(param, Single.class)) || (isLast && type == String[].class); -091 -092 this.values = annotations.getAnnotationValues(param, Values.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); -093 -094 this.syntax = null; -095 if (!commandIssuer) { -096 this.syntax = annotations.getAnnotationValue(param, Syntax.class); -097 if (syntax == null) { -098 if (!requiresInput && canConsumeInput) { -099 this.syntax = "[" + name + "]"; -100 } else if (requiresInput) { -101 this.syntax = "<" + name + ">"; -102 } -103 } -104 } -105 -106 this.flags = new HashMap<>(); -107 String flags = annotations.getAnnotationValue(param, Flags.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); -108 if (flags != null) { -109 parseFlags(flags); -110 } -111 inheritContextFlags(command.scope); -112 } -113 -114 private void inheritContextFlags(BaseCommand scope) { -115 if (!scope.contextFlags.isEmpty()) { -116 Class<?> pCls = this.type; -117 do { -118 parseFlags(scope.contextFlags.get(pCls)); -119 } while ((pCls = pCls.getSuperclass()) != null); -120 } -121 if (scope.parentCommand != null) { -122 inheritContextFlags(scope.parentCommand); -123 } -124 } -125 -126 private void parseFlags(String flags) { -127 if (flags != null) { -128 for (String s : ACFPatterns.COMMA.split(manager.getCommandReplacements().replace(flags))) { -129 String[] v = ACFPatterns.EQUALS.split(s, 2); -130 if (!this.flags.containsKey(v[0])) { -131 this.flags.put(v[0], v.length > 1 ? v[1] : null); -132 } -133 } -134 } -135 } -136 -137 private boolean isOptionalResolver(ContextResolver<?, CEC> resolver) { -138 return resolver instanceof IssuerAwareContextResolver -139 || resolver instanceof IssuerOnlyContextResolver -140 || resolver instanceof OptionalContextResolver; -141 } -142 -143 -144 public Parameter getParameter() { -145 return parameter; -146 } -147 -148 public Class<?> getType() { -149 return type; +026import co.aikar.commands.annotation.CommandPermission; +027import co.aikar.commands.annotation.Conditions; +028import co.aikar.commands.annotation.Default; +029import co.aikar.commands.annotation.Description; +030import co.aikar.commands.annotation.Flags; +031import co.aikar.commands.annotation.Optional; +032import co.aikar.commands.annotation.Single; +033import co.aikar.commands.annotation.Syntax; +034import co.aikar.commands.annotation.Values; +035import co.aikar.commands.contexts.ContextResolver; +036import co.aikar.commands.contexts.IssuerAwareContextResolver; +037import co.aikar.commands.contexts.IssuerOnlyContextResolver; +038import co.aikar.commands.contexts.OptionalContextResolver; +039 +040import java.lang.reflect.Parameter; +041import java.util.Arrays; +042import java.util.HashMap; +043import java.util.HashSet; +044import java.util.Map; +045import java.util.Set; +046 +047public class CommandParameter<CEC extends CommandExecutionContext<CEC, ? extends CommandIssuer>> { +048 private final Parameter parameter; +049 private final Class<?> type; +050 private final String name; +051 private final CommandManager manager; +052 private final int paramIndex; +053 +054 private ContextResolver<?, CEC> resolver; +055 private boolean optional; +056 private Set<String> permissions = new HashSet<>(); +057 private String permission; +058 private String description; +059 private String defaultValue; +060 private String syntax; +061 private String conditions; +062 private boolean requiresInput; +063 private boolean commandIssuer; +064 private String[] values; +065 private Map<String, String> flags; +066 private boolean canConsumeInput; +067 private boolean optionalResolver; +068 boolean consumesRest; +069 +070 public CommandParameter(RegisteredCommand<CEC> command, Parameter param, int paramIndex, boolean isLast) { +071 this.parameter = param; +072 this.type = param.getType(); +073 this.name = param.getName(); // do we care for an annotation to supply name? +074 this.manager = command.manager; +075 this.paramIndex = paramIndex; +076 Annotations annotations = manager.getAnnotations(); +077 +078 this.defaultValue = annotations.getAnnotationValue(param, Default.class, Annotations.REPLACEMENTS | (type != String.class ? Annotations.NO_EMPTY : 0)); +079 this.description = annotations.getAnnotationValue(param, Description.class, Annotations.REPLACEMENTS | Annotations.DEFAULT_EMPTY); +080 this.conditions = annotations.getAnnotationValue(param, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); +081 +082 //noinspection unchecked +083 this.resolver = manager.getCommandContexts().getResolver(type); +084 if (this.resolver == null) { +085 ACFUtil.sneaky(new InvalidCommandContextException( +086 "Parameter " + type.getSimpleName() + " of " + command + " has no applicable context resolver" +087 )); +088 } +089 +090 this.optional = annotations.hasAnnotation(param, Optional.class) || this.defaultValue != null || (isLast && type == String[].class); +091 this.permission = annotations.getAnnotationValue(param, CommandPermission.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); +092 this.optionalResolver = isOptionalResolver(resolver); +093 this.requiresInput = !this.optional && !this.optionalResolver; +094 //noinspection unchecked +095 this.commandIssuer = paramIndex == 0 && manager.isCommandIssuer(type); +096 this.canConsumeInput = !this.commandIssuer && !(resolver instanceof IssuerOnlyContextResolver); +097 this.consumesRest = (type == String.class && !annotations.hasAnnotation(param, Single.class)) || (isLast && type == String[].class); +098 +099 this.values = annotations.getAnnotationValues(param, Values.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); +100 +101 this.syntax = null; +102 if (!commandIssuer) { +103 this.syntax = annotations.getAnnotationValue(param, Syntax.class); +104 if (syntax == null) { +105 if (!requiresInput && canConsumeInput) { +106 this.syntax = "[" + name + "]"; +107 } else if (requiresInput) { +108 this.syntax = "<" + name + ">"; +109 } +110 } +111 } +112 +113 this.flags = new HashMap<>(); +114 String flags = annotations.getAnnotationValue(param, Flags.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); +115 if (flags != null) { +116 parseFlags(flags); +117 } +118 inheritContextFlags(command.scope); +119 this.computePermissions(); +120 } +121 +122 private void inheritContextFlags(BaseCommand scope) { +123 if (!scope.contextFlags.isEmpty()) { +124 Class<?> pCls = this.type; +125 do { +126 parseFlags(scope.contextFlags.get(pCls)); +127 } while ((pCls = pCls.getSuperclass()) != null); +128 } +129 if (scope.parentCommand != null) { +130 inheritContextFlags(scope.parentCommand); +131 } +132 } +133 +134 private void parseFlags(String flags) { +135 if (flags != null) { +136 for (String s : ACFPatterns.COMMA.split(manager.getCommandReplacements().replace(flags))) { +137 String[] v = ACFPatterns.EQUALS.split(s, 2); +138 if (!this.flags.containsKey(v[0])) { +139 this.flags.put(v[0], v.length > 1 ? v[1] : null); +140 } +141 } +142 } +143 } +144 +145 private void computePermissions() { +146 this.permissions.clear(); +147 if (this.permission != null && !this.permission.isEmpty()) { +148 this.permissions.addAll(Arrays.asList(ACFPatterns.COMMA.split(this.permission))); +149 } 150 } 151 -152 public String getName() { -153 return name; -154 } -155 -156 public CommandManager getManager() { -157 return manager; -158 } -159 -160 public int getParamIndex() { -161 return paramIndex; -162 } -163 -164 public ContextResolver<?, CEC> getResolver() { -165 return resolver; -166 } -167 -168 public void setResolver(ContextResolver<?, CEC> resolver) { -169 this.resolver = resolver; -170 } -171 -172 public boolean isOptional() { -173 return optional; -174 } -175 -176 public void setOptional(boolean optional) { -177 this.optional = optional; -178 } -179 -180 public String getDescription() { -181 return description; -182 } -183 -184 public void setDescription(String description) { -185 this.description = description; -186 } -187 -188 public String getDefaultValue() { -189 return defaultValue; -190 } -191 -192 public void setDefaultValue(String defaultValue) { -193 this.defaultValue = defaultValue; -194 } -195 -196 public boolean isCommandIssuer() { -197 return commandIssuer; -198 } -199 -200 public void setCommandIssuer(boolean commandIssuer) { -201 this.commandIssuer = commandIssuer; -202 } -203 -204 public String[] getValues() { -205 return values; -206 } -207 -208 public void setValues(String[] values) { -209 this.values = values; -210 } -211 -212 public Map<String, String> getFlags() { -213 return flags; -214 } -215 -216 public void setFlags(Map<String, String> flags) { -217 this.flags = flags; -218 } -219 -220 public boolean canConsumeInput() { -221 return canConsumeInput; -222 } -223 -224 public void setCanConsumeInput(boolean canConsumeInput) { -225 this.canConsumeInput = canConsumeInput; -226 } -227 -228 public void setOptionalResolver(boolean optionalResolver) { -229 this.optionalResolver = optionalResolver; -230 } -231 -232 public boolean isOptionalResolver() { -233 return optionalResolver; -234 } -235 -236 public boolean requiresInput() { -237 return requiresInput; -238 } -239 -240 public void setRequiresInput(boolean requiresInput) { -241 this.requiresInput = requiresInput; -242 } -243 -244 public String getSyntax() { -245 return syntax; -246 } -247 -248 public void setSyntax(String syntax) { -249 this.syntax = syntax; -250 } -251 -252 public String getConditions() { -253 return conditions; -254 } -255 -256 public void setConditions(String conditions) { -257 this.conditions = conditions; -258 } -259} +152 private boolean isOptionalResolver(ContextResolver<?, CEC> resolver) { +153 return resolver instanceof IssuerAwareContextResolver +154 || resolver instanceof IssuerOnlyContextResolver +155 || resolver instanceof OptionalContextResolver; +156 } +157 +158 +159 public Parameter getParameter() { +160 return parameter; +161 } +162 +163 public Class<?> getType() { +164 return type; +165 } +166 +167 public String getName() { +168 return name; +169 } +170 +171 public CommandManager getManager() { +172 return manager; +173 } +174 +175 public int getParamIndex() { +176 return paramIndex; +177 } +178 +179 public ContextResolver<?, CEC> getResolver() { +180 return resolver; +181 } +182 +183 public void setResolver(ContextResolver<?, CEC> resolver) { +184 this.resolver = resolver; +185 } +186 +187 public boolean isOptional() { +188 return optional; +189 } +190 +191 public void setOptional(boolean optional) { +192 this.optional = optional; +193 } +194 +195 public String getDescription() { +196 return description; +197 } +198 +199 public void setDescription(String description) { +200 this.description = description; +201 } +202 +203 public String getDefaultValue() { +204 return defaultValue; +205 } +206 +207 public void setDefaultValue(String defaultValue) { +208 this.defaultValue = defaultValue; +209 } +210 +211 public boolean isCommandIssuer() { +212 return commandIssuer; +213 } +214 +215 public void setCommandIssuer(boolean commandIssuer) { +216 this.commandIssuer = commandIssuer; +217 } +218 +219 public String[] getValues() { +220 return values; +221 } +222 +223 public void setValues(String[] values) { +224 this.values = values; +225 } +226 +227 public Map<String, String> getFlags() { +228 return flags; +229 } +230 +231 public void setFlags(Map<String, String> flags) { +232 this.flags = flags; +233 } +234 +235 public boolean canConsumeInput() { +236 return canConsumeInput; +237 } +238 +239 public void setCanConsumeInput(boolean canConsumeInput) { +240 this.canConsumeInput = canConsumeInput; +241 } +242 +243 public void setOptionalResolver(boolean optionalResolver) { +244 this.optionalResolver = optionalResolver; +245 } +246 +247 public boolean isOptionalResolver() { +248 return optionalResolver; +249 } +250 +251 public boolean requiresInput() { +252 return requiresInput; +253 } +254 +255 public void setRequiresInput(boolean requiresInput) { +256 this.requiresInput = requiresInput; +257 } +258 +259 public String getSyntax() { +260 return syntax; +261 } +262 +263 public void setSyntax(String syntax) { +264 this.syntax = syntax; +265 } +266 +267 public String getConditions() { +268 return conditions; +269 } +270 +271 public void setConditions(String conditions) { +272 this.conditions = conditions; +273 } +274 +275 public Set<String> getRequiredPermissions() { +276 return permissions; +277 } +278} diff --git a/docs/acf-core/src-html/co/aikar/commands/MessageKeys.html b/docs/acf-core/src-html/co/aikar/commands/MessageKeys.html index 5dc53266..b337aad8 100644 --- a/docs/acf-core/src-html/co/aikar/commands/MessageKeys.html +++ b/docs/acf-core/src-html/co/aikar/commands/MessageKeys.html @@ -40,36 +40,38 @@ 032@SuppressWarnings("WeakerAccess") 033public enum MessageKeys implements MessageKeyProvider { 034 PERMISSION_DENIED, -035 ERROR_GENERIC_LOGGED, -036 UNKNOWN_COMMAND, -037 INVALID_SYNTAX, -038 ERROR_PREFIX, -039 ERROR_PERFORMING_COMMAND, -040 INFO_MESSAGE, -041 PLEASE_SPECIFY_ONE_OF, -042 MUST_BE_A_NUMBER, -043 MUST_BE_MIN_LENGTH, -044 MUST_BE_MAX_LENGTH, -045 PLEASE_SPECIFY_AT_LEAST, -046 PLEASE_SPECIFY_AT_MOST, -047 NOT_ALLOWED_ON_CONSOLE, -048 COULD_NOT_FIND_PLAYER, -049 NO_COMMAND_MATCHED_SEARCH, -050 HELP_PAGE_INFORMATION, -051 HELP_NO_RESULTS, -052 HELP_HEADER, -053 HELP_FORMAT, -054 HELP_DETAILED_HEADER, -055 HELP_DETAILED_COMMAND_FORMAT, -056 HELP_DETAILED_PARAMETER_FORMAT, -057 HELP_SEARCH_HEADER, -058 ; -059 -060 private final MessageKey key = MessageKey.of("acf-core." + this.name().toLowerCase()); -061 public MessageKey getMessageKey() { -062 return key; -063 } -064} +035 PERMISSION_DENIED_PARAMETER, +036 ERROR_GENERIC_LOGGED, +037 UNKNOWN_COMMAND, +038 INVALID_SYNTAX, +039 ERROR_PREFIX, +040 ERROR_PERFORMING_COMMAND, +041 INFO_MESSAGE, +042 PLEASE_SPECIFY_ONE_OF, +043 MUST_BE_A_NUMBER, +044 MUST_BE_MIN_LENGTH, +045 MUST_BE_MAX_LENGTH, +046 PLEASE_SPECIFY_AT_LEAST, +047 PLEASE_SPECIFY_AT_MOST, +048 NOT_ALLOWED_ON_CONSOLE, +049 COULD_NOT_FIND_PLAYER, +050 NO_COMMAND_MATCHED_SEARCH, +051 HELP_PAGE_INFORMATION, +052 HELP_NO_RESULTS, +053 HELP_HEADER, +054 HELP_FORMAT, +055 HELP_DETAILED_HEADER, +056 HELP_DETAILED_COMMAND_FORMAT, +057 HELP_DETAILED_PARAMETER_FORMAT, +058 HELP_SEARCH_HEADER, +059 ; +060 +061 private final MessageKey key = MessageKey.of("acf-core." + this.name().toLowerCase()); +062 +063 public MessageKey getMessageKey() { +064 return key; +065 } +066} diff --git a/docs/acf-core/src-html/co/aikar/commands/RegisteredCommand.html b/docs/acf-core/src-html/co/aikar/commands/RegisteredCommand.html index a049087d..20a17f21 100644 --- a/docs/acf-core/src-html/co/aikar/commands/RegisteredCommand.html +++ b/docs/acf-core/src-html/co/aikar/commands/RegisteredCommand.html @@ -96,7 +96,7 @@ 088 this.prefSubCommand = prefSubCommand; 089 090 this.permission = annotations.getAnnotationValue(method, CommandPermission.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); -091 this.complete = annotations.getAnnotationValue(method, CommandCompletion.class); +091 this.complete = annotations.getAnnotationValue(method, CommandCompletion.class, Annotations.DEFAULT_EMPTY); // no replacements as it should be per-issuer 092 this.helpText = annotations.getAnnotationValue(method, Description.class, Annotations.REPLACEMENTS | Annotations.DEFAULT_EMPTY); 093 this.conditions = annotations.getAnnotationValue(method, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); 094 this.helpSearchTags = annotations.getAnnotationValue(method, HelpSearchTags.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); @@ -234,117 +234,132 @@ 226 if (requiresInput && remainingRequired > 0) { 227 remainingRequired--; 228 } -229 if (args.isEmpty() && !(isLast && type == String[].class)) { -230 if (allowOptional && parameter.getDefaultValue() != null) { -231 args.add(parameter.getDefaultValue()); -232 } else if (allowOptional && parameter.isOptional()) { -233 Object value = parameter.isOptionalResolver() ? resolver.getContext(context) : null; -234 if (value == null && parameter.getClass().isPrimitive()) { -235 throw new IllegalStateException("Parameter " + parameter.getName() + " is primitive and does not support Optional."); -236 } -237 //noinspection unchecked -238 this.manager.conditions.validateConditions(context, value); -239 passedArgs.put(parameterName, value); -240 //noinspection UnnecessaryContinue -241 continue; -242 } else if (requiresInput) { -243 scope.showSyntax(sender, this); -244 return null; -245 } -246 } -247 if (parameter.getValues() != null) { -248 String arg = !args.isEmpty() ? args.get(0) : ""; -249 -250 Set<String> possible = new HashSet<>(); -251 CommandCompletions commandCompletions = this.manager.getCommandCompletions(); -252 for (String s : parameter.getValues()) { -253 //noinspection unchecked -254 List<String> check = commandCompletions.getCompletionValues(this, sender, s, origArgs, opContext.isAsync()); -255 if (!check.isEmpty()) { -256 possible.addAll(check.stream().map(String::toLowerCase).collect(Collectors.toList())); -257 } else { -258 possible.add(s.toLowerCase()); -259 } -260 } +229 +230 Set<String> parameterPermissions = parameter.getRequiredPermissions(); +231 if (args.isEmpty() && !(isLast && type == String[].class)) { +232 if (allowOptional && parameter.getDefaultValue() != null) { +233 args.add(parameter.getDefaultValue()); +234 } else if (allowOptional && parameter.isOptional()) { +235 if (!this.manager.hasPermission(sender, parameterPermissions)) { +236 sender.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED_PARAMETER, "{param}", parameterName); +237 throw new InvalidCommandArgument(false); +238 } +239 Object value = parameter.isOptionalResolver() ? resolver.getContext(context) : null; +240 +241 if (value == null && parameter.getClass().isPrimitive()) { +242 throw new IllegalStateException("Parameter " + parameter.getName() + " is primitive and does not support Optional."); +243 } +244 //noinspection unchecked +245 this.manager.conditions.validateConditions(context, value); +246 passedArgs.put(parameterName, value); +247 continue; +248 } else if (requiresInput) { +249 scope.showSyntax(sender, this); +250 return null; +251 } +252 } else { +253 if (!this.manager.hasPermission(sender, parameterPermissions)) { +254 sender.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED_PARAMETER, "{param}", parameterName); +255 throw new InvalidCommandArgument(false); +256 } +257 } +258 +259 if (parameter.getValues() != null) { +260 String arg = !args.isEmpty() ? args.get(0) : ""; 261 -262 if (!possible.contains(arg.toLowerCase())) { -263 throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, -264 "{valid}", ACFUtil.join(possible, ", ")); -265 } -266 } -267 Object paramValue = resolver.getContext(context); -268 //noinspection unchecked -269 this.manager.conditions.validateConditions(context, paramValue); -270 passedArgs.put(parameterName, paramValue); -271 } -272 return passedArgs; -273 } -274 -275 boolean hasPermission(CommandIssuer issuer) { -276 return (permission == null || permission.isEmpty() || scope.manager.hasPermission(issuer, permission)) && scope.hasPermission(issuer); -277 } -278 -279 -280 /** -281 * @see #getRequiredPermissions() -282 * @deprecated -283 */ -284 @Deprecated -285 public String getPermission() { -286 if (this.permission == null || this.permission.isEmpty()) { -287 return null; -288 } -289 return ACFPatterns.COMMA.split(this.permission)[0]; -290 } -291 -292 private void computePermissions() { -293 this.permissions.clear(); -294 this.permissions.addAll(this.scope.getRequiredPermissions()); -295 if (this.permission != null && !this.permission.isEmpty()) { -296 this.permissions.addAll(Arrays.asList(ACFPatterns.COMMA.split(this.permission))); -297 } -298 } -299 -300 public Set<String> getRequiredPermissions() { -301 return this.permissions; -302 } -303 -304 public boolean requiresPermission(String permission) { -305 return getRequiredPermissions().contains(permission); -306 } -307 -308 public String getPrefSubCommand() { -309 return prefSubCommand; -310 } -311 -312 public String getSyntaxText() { -313 return syntaxText; -314 } -315 -316 public String getHelpText() { -317 return helpText != null ? helpText : ""; -318 } -319 -320 public boolean isPrivate() { -321 return isPrivate; -322 } -323 -324 public String getCommand() { -325 return command; -326 } -327 -328 public void addSubcommand(String cmd) { -329 this.registeredSubcommands.add(cmd); -330 } -331 -332 public void addSubcommands(Collection<String> cmd) { -333 this.registeredSubcommands.addAll(cmd); -334 } -335 -336 public <T extends Annotation> T getAnnotation(Class<T> annotation) { -337 return method.getAnnotation(annotation); -338 } -339} +262 Set<String> possible = new HashSet<>(); +263 CommandCompletions commandCompletions = this.manager.getCommandCompletions(); +264 for (String s : parameter.getValues()) { +265 if ("*".equals(s) || "@completions".equals(s)) { +266 s = commandCompletions.findDefaultCompletion(this, origArgs); +267 } +268 //noinspection unchecked +269 List<String> check = commandCompletions.getCompletionValues(this, sender, s, origArgs, opContext.isAsync()); +270 if (!check.isEmpty()) { +271 possible.addAll(check.stream().map(String::toLowerCase).collect(Collectors.toList())); +272 } else { +273 possible.add(s.toLowerCase()); +274 } +275 } +276 if (!possible.contains(arg.toLowerCase())) { +277 throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, +278 "{valid}", ACFUtil.join(possible, ", ")); +279 } +280 } +281 +282 Object paramValue = resolver.getContext(context); +283 +284 //noinspection unchecked +285 this.manager.conditions.validateConditions(context, paramValue); +286 passedArgs.put(parameterName, paramValue); +287 } +288 return passedArgs; +289 } +290 +291 boolean hasPermission(CommandIssuer issuer) { +292 return this.manager.hasPermission(issuer, getRequiredPermissions()); +293 } +294 +295 /** +296 * @see #getRequiredPermissions() +297 * @deprecated +298 */ +299 @Deprecated +300 public String getPermission() { +301 if (this.permission == null || this.permission.isEmpty()) { +302 return null; +303 } +304 return ACFPatterns.COMMA.split(this.permission)[0]; +305 } +306 +307 private void computePermissions() { +308 this.permissions.clear(); +309 this.permissions.addAll(this.scope.getRequiredPermissions()); +310 if (this.permission != null && !this.permission.isEmpty()) { +311 this.permissions.addAll(Arrays.asList(ACFPatterns.COMMA.split(this.permission))); +312 } +313 } +314 +315 public Set<String> getRequiredPermissions() { +316 return this.permissions; +317 } +318 +319 public boolean requiresPermission(String permission) { +320 return getRequiredPermissions().contains(permission); +321 } +322 +323 public String getPrefSubCommand() { +324 return prefSubCommand; +325 } +326 +327 public String getSyntaxText() { +328 return syntaxText; +329 } +330 +331 public String getHelpText() { +332 return helpText != null ? helpText : ""; +333 } +334 +335 public boolean isPrivate() { +336 return isPrivate; +337 } +338 +339 public String getCommand() { +340 return command; +341 } +342 +343 public void addSubcommand(String cmd) { +344 this.registeredSubcommands.add(cmd); +345 } +346 +347 public void addSubcommands(Collection<String> cmd) { +348 this.registeredSubcommands.addAll(cmd); +349 } +350 +351 public <T extends Annotation> T getAnnotation(Class<T> annotation) { +352 return method.getAnnotation(annotation); +353 } +354} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/CommandPermission.html b/docs/acf-core/src-html/co/aikar/commands/annotation/CommandPermission.html index ed90fee8..a4f456c7 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/CommandPermission.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/CommandPermission.html @@ -38,11 +38,11 @@ 030 031/** 032 * Sets the permission required to perform this command. -033 * +033 * <p> 034 * Permission format will vary based on implementation platform 035 */ 036@Retention(RetentionPolicy.RUNTIME) -037@Target({ElementType.METHOD, ElementType.TYPE}) +037@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER}) 038public @interface CommandPermission { 039 String value(); 040} diff --git a/docs/acf-jda/co/aikar/commands/JDACommandCompletions.html b/docs/acf-jda/co/aikar/commands/JDACommandCompletions.html index a9ffd403..dab8c4cf 100644 --- a/docs/acf-jda/co/aikar/commands/JDACommandCompletions.html +++ b/docs/acf-jda/co/aikar/commands/JDACommandCompletions.html @@ -181,7 +181,7 @@ extends co.aikar.commands.CommandCompletions<co.aikar.commands.CommandComplet

    Methods inherited from class co.aikar.commands.CommandCompletions

    -registerStaticCompletion, registerStaticCompletion, registerStaticCompletion, registerStaticCompletion
  • +registerStaticCompletion, registerStaticCompletion, registerStaticCompletion, registerStaticCompletion, setDefaultCompletion
    • diff --git a/docs/acf-paper/co/aikar/commands/PaperCommandManager.html b/docs/acf-paper/co/aikar/commands/PaperCommandManager.html index 1d64225e..21d016af 100644 --- a/docs/acf-paper/co/aikar/commands/PaperCommandManager.html +++ b/docs/acf-paper/co/aikar/commands/PaperCommandManager.html @@ -197,7 +197,7 @@ extends co.aikar.commands.BukkitCommandManager

      Methods inherited from class co.aikar.commands.CommandManager

      -addSupportedLanguage, enableUnstableAPI, formatMessage, generateCommandHelp, generateCommandHelp, generateCommandHelp, generateCommandHelp, getCommandConditions, getCommandReplacements, getCurrentCommandIssuer, getCurrentCommandManager, getCurrentCommandOperationContext, getDefaultExceptionHandler, getDefaultFormatter, getDefaultHelpPerPage, getFormat, getHelpFormatter, getIssuerLocale, getRootCommand, getSupportedLanguages, hasPermission, isLoggingUnhandledExceptions, log, notifyLocaleChange, obtainRootCommand, onLocaleChange, registerDependency, registerDependency, sendMessage, sendMessage, setDefaultExceptionHandler, setDefaultExceptionHandler, setDefaultFormatter, setDefaultHelpPerPage, setFormat, setFormat, setFormat, setHelpFormatter, setIssuerLocale, usePerIssuerLocale, usingPerIssuerLocale
    • +addSupportedLanguage, enableUnstableAPI, formatMessage, generateCommandHelp, generateCommandHelp, generateCommandHelp, generateCommandHelp, getCommandConditions, getCommandReplacements, getCurrentCommandIssuer, getCurrentCommandManager, getCurrentCommandOperationContext, getDefaultExceptionHandler, getDefaultFormatter, getDefaultHelpPerPage, getFormat, getHelpFormatter, getIssuerLocale, getRootCommand, getSupportedLanguages, hasPermission, hasPermission, isLoggingUnhandledExceptions, log, notifyLocaleChange, obtainRootCommand, onLocaleChange, registerDependency, registerDependency, sendMessage, sendMessage, setDefaultExceptionHandler, setDefaultExceptionHandler, setDefaultFormatter, setDefaultHelpPerPage, setFormat, setFormat, setFormat, setHelpFormatter, setIssuerLocale, usePerIssuerLocale, usingPerIssuerLocale