diff --git a/docs/acf-bukkit/co/aikar/commands/BukkitCommandContexts.html b/docs/acf-bukkit/co/aikar/commands/BukkitCommandContexts.html index 4c317c1b..8fa83e6f 100644 --- a/docs/acf-bukkit/co/aikar/commands/BukkitCommandContexts.html +++ b/docs/acf-bukkit/co/aikar/commands/BukkitCommandContexts.html @@ -107,7 +107,7 @@


  • -
    public class BukkitCommandContexts
    +
    public class BukkitCommandContexts
     extends co.aikar.commands.CommandContexts<BukkitCommandExecutionContext>
  • @@ -187,7 +187,7 @@ extends co.aikar.commands.CommandContexts<
  • BukkitCommandContexts

    -
    public BukkitCommandContexts(BukkitCommandManager manager)
    +
    public BukkitCommandContexts(BukkitCommandManager manager)
  • diff --git a/docs/acf-bukkit/co/aikar/commands/MinecraftMessageKeys.html b/docs/acf-bukkit/co/aikar/commands/MinecraftMessageKeys.html index a2be9e6f..fdf186fe 100644 --- a/docs/acf-bukkit/co/aikar/commands/MinecraftMessageKeys.html +++ b/docs/acf-bukkit/co/aikar/commands/MinecraftMessageKeys.html @@ -159,15 +159,18 @@ implements co.aikar.locales.MessageKeyProvider NO_PLAYER_FOUND  +NO_PLAYER_FOUND_OFFLINE  + + NO_PLAYER_FOUND_SERVER  - + PLAYER_IS_VANISHED_CONFIRM  - + USERNAME_TOO_SHORT  - + YOU_MUST_BE_HOLDING_ITEM  @@ -294,13 +297,22 @@ the order they are declared.
    public static final MinecraftMessageKeys NO_PLAYER_FOUND_SERVER
    + + + + @@ -309,7 +321,7 @@ the order they are declared. @@ -318,7 +330,7 @@ the order they are declared. @@ -327,7 +339,7 @@ the order they are declared. @@ -386,7 +398,7 @@ not permitted.) @@ -222,7 +222,7 @@ extends
  • contextMap

    -
    protected final Map<Class<?>,ContextResolver<?,R extends CommandExecutionContext<?,? extends CommandIssuer>>> contextMap
    +
    protected final Map<Class<?>,ContextResolver<?,R extends CommandExecutionContext<?,? extends CommandIssuer>>> contextMap
  • @@ -231,7 +231,7 @@ extends
  • manager

    -
    protected final CommandManager manager
    +
    protected final CommandManager manager
  • @@ -249,7 +249,7 @@ extends

    registerSenderAwareContext

    @Deprecated
    -public <T> void registerSenderAwareContext(Class<T> context,
    +public <T> void registerSenderAwareContext(Class<T> context,
                                                            IssuerAwareContextResolver<T,R> supplier)
    Deprecated. Please switch to registerIssuerAwareContext(Class, IssuerAwareContextResolver) as the core wants to use the platform agnostic term of "Issuer" instead of Sender
    @@ -265,7 +265,7 @@ public <T> void 
  • registerIssuerAwareContext

    -
    public <T> void registerIssuerAwareContext(Class<T> context,
    +
    public <T> void registerIssuerAwareContext(Class<T> context,
                                                IssuerAwareContextResolver<T,R> supplier)
    Registers a context resolver that may conditionally consume input, falling back to using the context of the issuer to potentially fulfill this context. @@ -279,7 +279,7 @@ public <T> void 
  • registerIssuerOnlyContext

    -
    public <T> void registerIssuerOnlyContext(Class<T> context,
    +
    public <T> void registerIssuerOnlyContext(Class<T> context,
                                               IssuerOnlyContextResolver<T,R> supplier)
    Registers a context resolver that will never consume input. It will always satisfy its context based on the issuer of the command, so it will not appear in syntax strings.
    @@ -291,7 +291,7 @@ public <T> void 
  • registerOptionalContext

    -
    public <T> void registerOptionalContext(Class<T> context,
    +
    public <T> void registerOptionalContext(Class<T> context,
                                             OptionalContextResolver<T,R> supplier)
    Registers a context that can safely accept a null input from the command issuer to resolve. This resolver should always call CommandExecutionContext.popFirstArg()
    @@ -303,7 +303,7 @@ public <T> void 
  • registerContext

    -
    public <T> void registerContext(Class<T> context,
    +
    public <T> void registerContext(Class<T> context,
                                     ContextResolver<T,R> supplier)
    Registers a context that requires input from the command issuer to resolve. This resolver should always call CommandExecutionContext.popFirstArg()
    @@ -315,7 +315,7 @@ public <T> void 
  • getResolver

    -
    public ContextResolver<?,RgetResolver(Class<?> type)
    +
    public ContextResolver<?,RgetResolver(Class<?> type)
  • diff --git a/docs/acf-core/co/aikar/commands/MessageKeys.html b/docs/acf-core/co/aikar/commands/MessageKeys.html index b438deed..62bb7511 100644 --- a/docs/acf-core/co/aikar/commands/MessageKeys.html +++ b/docs/acf-core/co/aikar/commands/MessageKeys.html @@ -184,9 +184,12 @@ implements co.aikar.locales.MessageKeyProvider
    PERMISSION_DENIED  -PLEASE_SPECIFY_ONE_OF  +PLEASE_SPECIFY_AT_MOST  +PLEASE_SPECIFY_ONE_OF  + + UNKNOWN_COMMAND  @@ -349,13 +352,22 @@ the order they are declared.
  • public static final MessageKeys MUST_BE_MAX_LENGTH
  • + + + + @@ -364,7 +376,7 @@ the order they are declared. @@ -373,7 +385,7 @@ the order they are declared. @@ -382,7 +394,7 @@ the order they are declared. @@ -391,7 +403,7 @@ the order they are declared. @@ -400,7 +412,7 @@ the order they are declared. @@ -459,7 +471,7 @@ not permitted.) @@ -240,7 +240,7 @@ public 
  • requiresPermission

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

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

    -
    public String getSyntaxText()
    +
    public String getSyntaxText()
  • @@ -267,7 +267,7 @@ public 
  • getCommand

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

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

    -
    public void addSubcommands(Collection<String> cmd)
    +
    public void addSubcommands(Collection<String> cmd)
  • 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 6f6e758c..3031c16c 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandContexts.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandContexts.html @@ -39,213 +39,266 @@ 031import co.aikar.commands.contexts.IssuerOnlyContextResolver; 032import co.aikar.commands.contexts.OptionalContextResolver; 033import com.google.common.collect.Maps; -034 -035import java.util.List; -036import java.util.Map; -037 -038@SuppressWarnings("WeakerAccess") -039public class CommandContexts <R extends CommandExecutionContext<?, ? extends CommandIssuer>> { -040 protected final Map<Class<?>, ContextResolver<?, R>> contextMap = Maps.newHashMap(); -041 protected final CommandManager manager; -042 -043 CommandContexts(CommandManager manager) { -044 this.manager = manager; -045 registerContext(Integer.class, (c) -> { -046 try { -047 return ACFUtil.parseNumber(c.popFirstArg(), c.hasFlag("suffixes")).intValue(); -048 } catch (NumberFormatException e) { -049 throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); -050 } -051 }); -052 registerContext(Long.class, (c) -> { -053 try { -054 return ACFUtil.parseNumber(c.popFirstArg(), c.hasFlag("suffixes")).longValue(); -055 } catch (NumberFormatException e) { -056 throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); -057 } -058 +034import org.jetbrains.annotations.NotNull; +035 +036import java.util.List; +037import java.util.Map; +038 +039@SuppressWarnings("WeakerAccess") +040public class CommandContexts <R extends CommandExecutionContext<?, ? extends CommandIssuer>> { +041 protected final Map<Class<?>, ContextResolver<?, R>> contextMap = Maps.newHashMap(); +042 protected final CommandManager manager; +043 +044 CommandContexts(CommandManager manager) { +045 this.manager = manager; +046 registerContext(Short.class, (c) -> { +047 try { +048 return parseAndValudateNumber(c, Short.MAX_VALUE).shortValue(); +049 } catch (NumberFormatException e) { +050 throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); +051 } +052 }); +053 registerContext(short.class, (c) -> { +054 try { +055 return parseAndValudateNumber(c, Short.MAX_VALUE).shortValue(); +056 } catch (NumberFormatException e) { +057 throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); +058 } 059 }); -060 registerContext(Float.class, (c) -> { +060 registerContext(Integer.class, (c) -> { 061 try { -062 return ACFUtil.parseNumber(c.popFirstArg(), c.hasFlag("suffixes")).floatValue(); +062 return parseAndValudateNumber(c, Integer.MAX_VALUE).intValue(); 063 } catch (NumberFormatException e) { 064 throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); 065 } 066 }); -067 registerContext(Double.class, (c) -> { +067 registerContext(int.class, (c) -> { 068 try { -069 return ACFUtil.parseNumber(c.popFirstArg(), c.hasFlag("suffixes")).doubleValue(); +069 return parseAndValudateNumber(c, Integer.MAX_VALUE).intValue(); 070 } catch (NumberFormatException e) { 071 throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); 072 } 073 }); -074 registerContext(Number.class, (c) -> { +074 registerContext(Long.class, (c) -> { 075 try { -076 return ACFUtil.parseNumber(c.popFirstArg(), c.hasFlag("suffixes")); +076 return parseAndValudateNumber(c, Long.MAX_VALUE).longValue(); 077 } catch (NumberFormatException e) { 078 throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); 079 } 080 }); -081 registerContext(Boolean.class, (c) -> { -082 String test = c.popFirstArg(); -083 if (test == null) { -084 return null; -085 } -086 return ACFUtil.isTruthy(test); +081 registerContext(long.class, (c) -> { +082 try { +083 return parseAndValudateNumber(c, Long.MAX_VALUE).longValue(); +084 } catch (NumberFormatException e) { +085 throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); +086 } 087 }); -088 registerContext(String.class, (c) -> { -089 final Values values = c.getParam().getAnnotation(Values.class); -090 if (values != null) { -091 return c.popFirstArg(); -092 } -093 String ret = (c.isLastArg() && c.getParam().getAnnotation(Single.class) == null) ? -094 ACFUtil.join(c.getArgs()) -095 : -096 c.popFirstArg(); -097 -098 Integer minLen = c.getFlagValue("minlen", (Integer) null); -099 Integer maxLen = c.getFlagValue("maxlen", (Integer) null); -100 if (minLen != null) { -101 if (ret.length() < minLen) { -102 throw new InvalidCommandArgument(MessageKeys.MUST_BE_MIN_LENGTH, "{min}", String.valueOf(minLen)); -103 } -104 } -105 if (maxLen != null) { -106 if (ret.length() > maxLen) { -107 throw new InvalidCommandArgument(MessageKeys.MUST_BE_MAX_LENGTH, "{max}", String.valueOf(maxLen)); -108 } -109 } -110 -111 return ret; -112 }); -113 registerContext(String[].class, (c) -> { -114 String val; -115 // Go home IDEA, you're drunk -116 //noinspection unchecked -117 List<String> args = c.getArgs(); -118 if (c.isLastArg() && c.getParam().getAnnotation(Single.class) == null) { -119 val = ACFUtil.join(args); -120 } else { -121 val = c.popFirstArg(); -122 } -123 Split split = c.getParam().getAnnotation(Split.class); -124 if (split != null) { -125 if (val.isEmpty()) { -126 throw new InvalidCommandArgument(); -127 } -128 return ACFPatterns.getPattern(split.value()).split(val); -129 } else if (!c.isLastArg()) { -130 ACFUtil.sneaky(new IllegalStateException("Weird Command signature... String[] should be last or @Split")); -131 } -132 -133 String[] result = args.toArray(new String[args.size()]); -134 args.clear(); -135 return result; -136 }); -137 -138 registerContext(Enum.class, (c) -> { -139 final String first = c.popFirstArg(); -140 //noinspection unchecked -141 Class<? extends Enum<?>> enumCls = (Class<? extends Enum<?>>) c.getParam().getType(); -142 Enum<?> match = ACFUtil.simpleMatch(enumCls, first); -143 if (match == null) { -144 List<String> names = ACFUtil.enumNames(enumCls); -145 throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, "{valid}", ACFUtil.join(names)); -146 } -147 return match; -148 }); -149 registerOptionalContext(CommandHelp.class, (c) -> { -150 String first = c.getFirstArg(); -151 String last = c.getLastArg(); -152 int page = 1; -153 List<String> search = null; -154 if (last != null && ACFUtil.isInteger(last)) { -155 c.popLastArg(); -156 page = ACFUtil.parseInt(last); -157 if (!c.getArgs().isEmpty()) { -158 search = c.getArgs(); -159 } -160 } else if (first != null && ACFUtil.isInteger(first)) { -161 c.popFirstArg(); -162 page = ACFUtil.parseInt(first); -163 if (!c.getArgs().isEmpty()) { -164 search = c.getArgs(); -165 } -166 } else if (!c.getArgs().isEmpty()) { -167 search = c.getArgs(); -168 } -169 CommandHelp commandHelp = manager.generateCommandHelp(); -170 commandHelp.setPage(page); -171 Integer perPage = c.getFlagValue("perpage", (Integer) null); -172 if (perPage != null) { -173 commandHelp.setPerPage(perPage); -174 } -175 commandHelp.setSearch(search); -176 return commandHelp; -177 }); -178 } -179 -180 /** -181 * @deprecated Please switch to {@link #registerIssuerAwareContext(Class, IssuerAwareContextResolver)} -182 * as the core wants to use the platform agnostic term of "Issuer" instead of Sender -183 * @see #registerIssuerAwareContext(Class, IssuerAwareContextResolver) -184 */ -185 @Deprecated -186 public <T> void registerSenderAwareContext(Class<T> context, IssuerAwareContextResolver<T, R> supplier) { -187 contextMap.put(context, supplier); -188 } -189 -190 /** -191 * Registers a context resolver that may conditionally consume input, falling back to using the context of the -192 * issuer to potentially fulfill this context. -193 * You may call {@link CommandExecutionContext#getFirstArg()} and then conditionally call {@link CommandExecutionContext#popFirstArg()} -194 * if you want to consume that input. -195 */ -196 public <T> void registerIssuerAwareContext(Class<T> context, IssuerAwareContextResolver<T, R> supplier) { -197 contextMap.put(context, supplier); -198 } -199 -200 /** -201 * Registers a context resolver that will never consume input. It will always satisfy its context based on the -202 * issuer of the command, so it will not appear in syntax strings. -203 */ -204 public <T> void registerIssuerOnlyContext(Class<T> context, IssuerOnlyContextResolver<T, R> supplier) { -205 contextMap.put(context, supplier); -206 } -207 -208 /** -209 * Registers a context that can safely accept a null input from the command issuer to resolve. This resolver should always -210 * call {@link CommandExecutionContext#popFirstArg()} -211 */ -212 public <T> void registerOptionalContext(Class<T> context, OptionalContextResolver<T, R> supplier) { -213 contextMap.put(context, supplier); -214 } -215 -216 /** -217 * Registers a context that requires input from the command issuer to resolve. This resolver should always -218 * call {@link CommandExecutionContext#popFirstArg()} -219 */ -220 public <T> void registerContext(Class<T> context, ContextResolver<T, R> supplier) { -221 contextMap.put(context, supplier); +088 registerContext(Float.class, (c) -> { +089 try { +090 return parseAndValudateNumber(c, Float.MAX_VALUE).floatValue(); +091 } catch (NumberFormatException e) { +092 throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); +093 } +094 }); +095 registerContext(float.class, (c) -> { +096 try { +097 return parseAndValudateNumber(c, Float.MAX_VALUE).floatValue(); +098 } catch (NumberFormatException e) { +099 throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); +100 } +101 }); +102 registerContext(Double.class, (c) -> { +103 try { +104 return parseAndValudateNumber(c, Double.MAX_VALUE).doubleValue(); +105 } catch (NumberFormatException e) { +106 throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); +107 } +108 }); +109 registerContext(double.class, (c) -> { +110 try { +111 return parseAndValudateNumber(c, Double.MAX_VALUE).doubleValue(); +112 } catch (NumberFormatException e) { +113 throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); +114 } +115 }); +116 registerContext(Number.class, (c) -> { +117 try { +118 return parseAndValudateNumber(c, Double.MAX_VALUE); +119 } catch (NumberFormatException e) { +120 throw new InvalidCommandArgument(MessageKeys.MUST_BE_A_NUMBER); +121 } +122 }); +123 registerContext(Boolean.class, (c) -> ACFUtil.isTruthy(c.popFirstArg())); +124 registerContext(boolean.class, (c) -> ACFUtil.isTruthy(c.popFirstArg())); +125 registerContext(char.class, c -> { +126 String s = c.popFirstArg(); +127 if (s.length() > 1) { +128 throw new InvalidCommandArgument(MessageKeys.MUST_BE_MAX_LENGTH, "{max}", String.valueOf(1)); +129 } +130 return s.charAt(0); +131 }); +132 registerContext(String.class, (c) -> { +133 final Values values = c.getParam().getAnnotation(Values.class); +134 if (values != null) { +135 return c.popFirstArg(); +136 } +137 String ret = (c.isLastArg() && c.getParam().getAnnotation(Single.class) == null) ? +138 ACFUtil.join(c.getArgs()) +139 : +140 c.popFirstArg(); +141 +142 Integer minLen = c.getFlagValue("minlen", (Integer) null); +143 Integer maxLen = c.getFlagValue("maxlen", (Integer) null); +144 if (minLen != null) { +145 if (ret.length() < minLen) { +146 throw new InvalidCommandArgument(MessageKeys.MUST_BE_MIN_LENGTH, "{min}", String.valueOf(minLen)); +147 } +148 } +149 if (maxLen != null) { +150 if (ret.length() > maxLen) { +151 throw new InvalidCommandArgument(MessageKeys.MUST_BE_MAX_LENGTH, "{max}", String.valueOf(maxLen)); +152 } +153 } +154 +155 return ret; +156 }); +157 registerContext(String[].class, (c) -> { +158 String val; +159 // Go home IDEA, you're drunk +160 //noinspection unchecked +161 List<String> args = c.getArgs(); +162 if (c.isLastArg() && c.getParam().getAnnotation(Single.class) == null) { +163 val = ACFUtil.join(args); +164 } else { +165 val = c.popFirstArg(); +166 } +167 Split split = c.getParam().getAnnotation(Split.class); +168 if (split != null) { +169 if (val.isEmpty()) { +170 throw new InvalidCommandArgument(); +171 } +172 return ACFPatterns.getPattern(split.value()).split(val); +173 } else if (!c.isLastArg()) { +174 ACFUtil.sneaky(new IllegalStateException("Weird Command signature... String[] should be last or @Split")); +175 } +176 +177 String[] result = args.toArray(new String[args.size()]); +178 args.clear(); +179 return result; +180 }); +181 +182 registerContext(Enum.class, (c) -> { +183 final String first = c.popFirstArg(); +184 //noinspection unchecked +185 Class<? extends Enum<?>> enumCls = (Class<? extends Enum<?>>) c.getParam().getType(); +186 Enum<?> match = ACFUtil.simpleMatch(enumCls, first); +187 if (match == null) { +188 List<String> names = ACFUtil.enumNames(enumCls); +189 throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, "{valid}", ACFUtil.join(names)); +190 } +191 return match; +192 }); +193 registerOptionalContext(CommandHelp.class, (c) -> { +194 String first = c.getFirstArg(); +195 String last = c.getLastArg(); +196 int page = 1; +197 List<String> search = null; +198 if (last != null && ACFUtil.isInteger(last)) { +199 c.popLastArg(); +200 page = ACFUtil.parseInt(last); +201 if (!c.getArgs().isEmpty()) { +202 search = c.getArgs(); +203 } +204 } else if (first != null && ACFUtil.isInteger(first)) { +205 c.popFirstArg(); +206 page = ACFUtil.parseInt(first); +207 if (!c.getArgs().isEmpty()) { +208 search = c.getArgs(); +209 } +210 } else if (!c.getArgs().isEmpty()) { +211 search = c.getArgs(); +212 } +213 CommandHelp commandHelp = manager.generateCommandHelp(); +214 commandHelp.setPage(page); +215 Integer perPage = c.getFlagValue("perpage", (Integer) null); +216 if (perPage != null) { +217 commandHelp.setPerPage(perPage); +218 } +219 commandHelp.setSearch(search); +220 return commandHelp; +221 }); 222 } 223 -224 public ContextResolver<?, R> getResolver(Class<?> type) { -225 Class<?> rootType = type; -226 do { -227 if (type == Object.class) { -228 break; -229 } -230 -231 final ContextResolver<?, R> resolver = contextMap.get(type); -232 if (resolver != null) { -233 return resolver; -234 } -235 } while ((type = type.getSuperclass()) != null); -236 -237 this.manager.log(LogLevel.ERROR, "Could not find context resolver", new IllegalStateException("No context resolver defined for " + rootType.getName())); -238 return null; -239 } -240} +224 @NotNull +225 private Number parseAndValudateNumber(R c, Number maxValue) throws InvalidCommandArgument { +226 Number val = ACFUtil.parseNumber(c.popFirstArg(), c.hasFlag("suffixes")); +227 if (maxValue != null && val.doubleValue() > maxValue.doubleValue()) { +228 throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_AT_MOST, "{max}", String.valueOf(maxValue)); +229 } +230 return val; +231 } +232 +233 /** +234 * @deprecated Please switch to {@link #registerIssuerAwareContext(Class, IssuerAwareContextResolver)} +235 * as the core wants to use the platform agnostic term of "Issuer" instead of Sender +236 * @see #registerIssuerAwareContext(Class, IssuerAwareContextResolver) +237 */ +238 @Deprecated +239 public <T> void registerSenderAwareContext(Class<T> context, IssuerAwareContextResolver<T, R> supplier) { +240 contextMap.put(context, supplier); +241 } +242 +243 /** +244 * Registers a context resolver that may conditionally consume input, falling back to using the context of the +245 * issuer to potentially fulfill this context. +246 * You may call {@link CommandExecutionContext#getFirstArg()} and then conditionally call {@link CommandExecutionContext#popFirstArg()} +247 * if you want to consume that input. +248 */ +249 public <T> void registerIssuerAwareContext(Class<T> context, IssuerAwareContextResolver<T, R> supplier) { +250 contextMap.put(context, supplier); +251 } +252 +253 /** +254 * Registers a context resolver that will never consume input. It will always satisfy its context based on the +255 * issuer of the command, so it will not appear in syntax strings. +256 */ +257 public <T> void registerIssuerOnlyContext(Class<T> context, IssuerOnlyContextResolver<T, R> supplier) { +258 contextMap.put(context, supplier); +259 } +260 +261 /** +262 * Registers a context that can safely accept a null input from the command issuer to resolve. This resolver should always +263 * call {@link CommandExecutionContext#popFirstArg()} +264 */ +265 public <T> void registerOptionalContext(Class<T> context, OptionalContextResolver<T, R> supplier) { +266 contextMap.put(context, supplier); +267 } +268 +269 /** +270 * Registers a context that requires input from the command issuer to resolve. This resolver should always +271 * call {@link CommandExecutionContext#popFirstArg()} +272 */ +273 public <T> void registerContext(Class<T> context, ContextResolver<T, R> supplier) { +274 contextMap.put(context, supplier); +275 } +276 +277 public ContextResolver<?, R> getResolver(Class<?> type) { +278 Class<?> rootType = type; +279 do { +280 if (type == Object.class) { +281 break; +282 } +283 +284 final ContextResolver<?, R> resolver = contextMap.get(type); +285 if (resolver != null) { +286 return resolver; +287 } +288 } while ((type = type.getSuperclass()) != null); +289 +290 this.manager.log(LogLevel.ERROR, "Could not find context resolver", new IllegalStateException("No context resolver defined for " + rootType.getName())); +291 return null; +292 } +293} 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 4d987662..448634da 100644 --- a/docs/acf-core/src-html/co/aikar/commands/MessageKeys.html +++ b/docs/acf-core/src-html/co/aikar/commands/MessageKeys.html @@ -50,19 +50,20 @@ 042 MUST_BE_A_NUMBER, 043 MUST_BE_MIN_LENGTH, 044 MUST_BE_MAX_LENGTH, -045 NOT_ALLOWED_ON_CONSOLE, -046 COULD_NOT_FIND_PLAYER, -047 HELP_FORMAT, -048 NO_COMMAND_MATCHED_SEARCH, -049 HELP_PAGE_INFORMATION, -050 HELP_NO_RESULTS -051 ; -052 -053 private final MessageKey key = MessageKey.of("acf-core." + this.name().toLowerCase()); -054 public MessageKey getMessageKey() { -055 return key; -056 } -057} +045 PLEASE_SPECIFY_AT_MOST, +046 NOT_ALLOWED_ON_CONSOLE, +047 COULD_NOT_FIND_PLAYER, +048 HELP_FORMAT, +049 NO_COMMAND_MATCHED_SEARCH, +050 HELP_PAGE_INFORMATION, +051 HELP_NO_RESULTS +052 ; +053 +054 private final MessageKey key = MessageKey.of("acf-core." + this.name().toLowerCase()); +055 public MessageKey getMessageKey() { +056 return key; +057 } +058} 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 50347a8a..afaed805 100644 --- a/docs/acf-core/src-html/co/aikar/commands/RegisteredCommand.html +++ b/docs/acf-core/src-html/co/aikar/commands/RegisteredCommand.html @@ -224,86 +224,90 @@ 216 if (allowOptional && def != null) { 217 args.add(scope.manager.getCommandReplacements().replace(def.value())); 218 } else if (allowOptional && opt != null) { -219 passedArgs.put(parameterName, isOptionalResolver(resolver) ? resolver.getContext(context) : null); -220 //noinspection UnnecessaryContinue -221 continue; -222 } else if (!isOptionalResolver) { -223 scope.showSyntax(sender, this); -224 return null; -225 } -226 } -227 final Values values = parameter.getAnnotation(Values.class); -228 if (values != null) { -229 String arg = !args.isEmpty() ? args.get(0) : ""; -230 -231 final String[] split = ACFPatterns.PIPE.split(scope.manager.getCommandReplacements().replace(values.value())); -232 Set<String> possible = Sets.newHashSet(); -233 for (String s : split) { -234 List<String> check = this.manager.getCommandCompletions().getCompletionValues(this, sender, s, origArgs, opContext.isAsync()); -235 if (!check.isEmpty()) { -236 possible.addAll(check.stream().map(String::toLowerCase).collect(Collectors.toList())); -237 } else { -238 possible.add(s.toLowerCase()); -239 } -240 } -241 -242 if (!possible.contains(arg.toLowerCase())) { -243 throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, -244 "{valid}", ACFUtil.join(possible, ", ")); -245 } -246 } -247 passedArgs.put(parameterName, resolver.getContext(context)); -248 } -249 return passedArgs; -250 } -251 -252 boolean hasPermission(CommandIssuer issuer) { -253 return (permission == null || permission.isEmpty() || scope.manager.hasPermission(issuer, permission)) && scope.hasPermission(issuer); +219 Object value = isOptionalResolver(resolver) ? resolver.getContext(context) : null; +220 if (value == null && parameter.getClass().isPrimitive()) { +221 throw new IllegalStateException("Parameter " + parameter.getName() + " is primitive and does not support Optional."); +222 } +223 passedArgs.put(parameterName, value); +224 //noinspection UnnecessaryContinue +225 continue; +226 } else if (!isOptionalResolver) { +227 scope.showSyntax(sender, this); +228 return null; +229 } +230 } +231 final Values values = parameter.getAnnotation(Values.class); +232 if (values != null) { +233 String arg = !args.isEmpty() ? args.get(0) : ""; +234 +235 final String[] split = ACFPatterns.PIPE.split(scope.manager.getCommandReplacements().replace(values.value())); +236 Set<String> possible = Sets.newHashSet(); +237 for (String s : split) { +238 List<String> check = this.manager.getCommandCompletions().getCompletionValues(this, sender, s, origArgs, opContext.isAsync()); +239 if (!check.isEmpty()) { +240 possible.addAll(check.stream().map(String::toLowerCase).collect(Collectors.toList())); +241 } else { +242 possible.add(s.toLowerCase()); +243 } +244 } +245 +246 if (!possible.contains(arg.toLowerCase())) { +247 throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, +248 "{valid}", ACFUtil.join(possible, ", ")); +249 } +250 } +251 passedArgs.put(parameterName, resolver.getContext(context)); +252 } +253 return passedArgs; 254 } 255 -256 -257 /** -258 * @see #getRequiredPermissions() -259 * @deprecated -260 */ -261 @Deprecated -262 public String getPermission() { -263 if (this.permission == null || this.permission.isEmpty()) { -264 return null; -265 } -266 return ACFPatterns.COMMA.split(this.permission)[0]; -267 } -268 -269 public Set<String> getRequiredPermissions() { -270 if (this.permission == null || this.permission.isEmpty()) { -271 return ImmutableSet.of(); -272 } -273 return Sets.newHashSet(ACFPatterns.COMMA.split(this.permission)); -274 } -275 -276 public boolean requiresPermission(String permission) { -277 return getRequiredPermissions().contains(permission) || scope.requiresPermission(permission); +256 boolean hasPermission(CommandIssuer issuer) { +257 return (permission == null || permission.isEmpty() || scope.manager.hasPermission(issuer, permission)) && scope.hasPermission(issuer); +258 } +259 +260 +261 /** +262 * @see #getRequiredPermissions() +263 * @deprecated +264 */ +265 @Deprecated +266 public String getPermission() { +267 if (this.permission == null || this.permission.isEmpty()) { +268 return null; +269 } +270 return ACFPatterns.COMMA.split(this.permission)[0]; +271 } +272 +273 public Set<String> getRequiredPermissions() { +274 if (this.permission == null || this.permission.isEmpty()) { +275 return ImmutableSet.of(); +276 } +277 return Sets.newHashSet(ACFPatterns.COMMA.split(this.permission)); 278 } 279 -280 public String getPrefSubCommand() { -281 return prefSubCommand; +280 public boolean requiresPermission(String permission) { +281 return getRequiredPermissions().contains(permission) || scope.requiresPermission(permission); 282 } 283 -284 public String getSyntaxText() { -285 return syntaxText; +284 public String getPrefSubCommand() { +285 return prefSubCommand; 286 } 287 -288 public String getCommand() { -289 return command; +288 public String getSyntaxText() { +289 return syntaxText; 290 } 291 -292 public void addSubcommand(String cmd) { -293 this.registeredSubcommands.add(cmd); +292 public String getCommand() { +293 return command; 294 } -295 public void addSubcommands(Collection<String> cmd) { -296 this.registeredSubcommands.addAll(cmd); -297 } -298} +295 +296 public void addSubcommand(String cmd) { +297 this.registeredSubcommands.add(cmd); +298 } +299 public void addSubcommands(Collection<String> cmd) { +300 this.registeredSubcommands.addAll(cmd); +301 } +302}