✨ Allow for use of named suggestion providers in @Flag annotated command method parameters, add methods to FlagContext to work with flag values as optionals
This commit is contained in:
parent
6d0301d9dd
commit
fc1a613463
10 changed files with 104 additions and 30 deletions
|
|
@ -8,10 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Added access to the CloudBrigadierManager from Brigadier-enabled command managers
|
- Added access to the CloudBrigadierManager from Brigadier-enabled command managers
|
||||||
- Added parameter injectors
|
- Added parameter injectors (cloud-annotations)
|
||||||
- Store currently parsing command argument in the command context
|
- Store currently parsing command argument in the command context
|
||||||
- Added a method to CloudBrigadierManager to enable or disable Brigadier native suggestions for specific argument types
|
- Added a method to CloudBrigadierManager to enable or disable Brigadier native suggestions for specific argument types
|
||||||
- Added a method to get the failure reason of SelectorParseExceptions
|
- Added a method to get the failure reason of SelectorParseExceptions
|
||||||
|
- Added some methods to FlagContext to work with flag values as optionals
|
||||||
|
- Allow for use of named suggestion providers with `@Flag`s (cloud-annotations)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Allow for use of `@Completions` annotation with argument types other than String
|
- Allow for use of `@Completions` annotation with argument types other than String
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@
|
||||||
//
|
//
|
||||||
package cloud.commandframework.annotations;
|
package cloud.commandframework.annotations;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
@ -41,14 +43,14 @@ public @interface Argument {
|
||||||
*
|
*
|
||||||
* @return Argument name
|
* @return Argument name
|
||||||
*/
|
*/
|
||||||
String value();
|
@NonNull String value();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the argument parser
|
* Name of the argument parser
|
||||||
*
|
*
|
||||||
* @return Argument name
|
* @return Argument name
|
||||||
*/
|
*/
|
||||||
String parserName() default "";
|
@NonNull String parserName() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the suggestions provider to use. If the string is left empty, the default
|
* Name of the suggestions provider to use. If the string is left empty, the default
|
||||||
|
|
@ -64,20 +66,20 @@ public @interface Argument {
|
||||||
* should be used instead
|
* should be used instead
|
||||||
* @since 1.1.0
|
* @since 1.1.0
|
||||||
*/
|
*/
|
||||||
String suggestions() default "";
|
@NonNull String suggestions() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the default value
|
* Get the default value
|
||||||
*
|
*
|
||||||
* @return Default value
|
* @return Default value
|
||||||
*/
|
*/
|
||||||
String defaultValue() default "";
|
@NonNull String defaultValue() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The argument description
|
* The argument description
|
||||||
*
|
*
|
||||||
* @return Argument description
|
* @return Argument description
|
||||||
*/
|
*/
|
||||||
String description() default "";
|
@NonNull String description() default "";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
package cloud.commandframework.annotations;
|
package cloud.commandframework.annotations;
|
||||||
|
|
||||||
import cloud.commandframework.arguments.parser.StandardParameters;
|
import cloud.commandframework.arguments.parser.StandardParameters;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
|
|
@ -42,6 +43,6 @@ public @interface CommandDescription {
|
||||||
*
|
*
|
||||||
* @return Command syntax
|
* @return Command syntax
|
||||||
*/
|
*/
|
||||||
String value() default "";
|
@NonNull String value() default "";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@
|
||||||
//
|
//
|
||||||
package cloud.commandframework.annotations;
|
package cloud.commandframework.annotations;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
@ -40,13 +42,13 @@ public @interface CommandMethod {
|
||||||
*
|
*
|
||||||
* @return Command syntax
|
* @return Command syntax
|
||||||
*/
|
*/
|
||||||
String value();
|
@NonNull String value();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The required sender
|
* The required sender
|
||||||
*
|
*
|
||||||
* @return Required sender
|
* @return Required sender
|
||||||
*/
|
*/
|
||||||
Class<?> requiredSender() default Object.class;
|
@NonNull Class<?> requiredSender() default Object.class;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@
|
||||||
//
|
//
|
||||||
package cloud.commandframework.annotations;
|
package cloud.commandframework.annotations;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
@ -40,6 +42,6 @@ public @interface CommandPermission {
|
||||||
*
|
*
|
||||||
* @return Command permission
|
* @return Command permission
|
||||||
*/
|
*/
|
||||||
String value() default "";
|
@NonNull String value() default "";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,15 +23,21 @@
|
||||||
//
|
//
|
||||||
package cloud.commandframework.annotations;
|
package cloud.commandframework.annotations;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that the parameter should be treated like a {@link cloud.commandframework.arguments.flags.CommandFlag}.
|
* Indicates that the parameter should be treated like a {@link cloud.commandframework.arguments.flags.CommandFlag}.
|
||||||
* If the parameter is a {@code boolean} then a presence flag will be created, else a value flag will be created
|
* <ul>
|
||||||
* and the parser will be resolved the same way as it would for a {@link Argument}
|
* <li>If the parameter is a {@code boolean}, a presence flag will be created</li>
|
||||||
|
* <li>If the parameter is of any other type, a value flag will be created and the parser
|
||||||
|
* will resolve it in the same way that it would for an {@link Argument}</li>
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@Target(ElementType.PARAMETER)
|
@Target(ElementType.PARAMETER)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
@ -42,14 +48,14 @@ public @interface Flag {
|
||||||
*
|
*
|
||||||
* @return Flag name
|
* @return Flag name
|
||||||
*/
|
*/
|
||||||
String value();
|
@NonNull String value();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag aliases
|
* Flag aliases
|
||||||
*
|
*
|
||||||
* @return Aliases
|
* @return Aliases
|
||||||
*/
|
*/
|
||||||
String[] aliases() default "";
|
@NonNull String[] aliases() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the parser. Leave empty to use
|
* Name of the parser. Leave empty to use
|
||||||
|
|
@ -57,13 +63,29 @@ public @interface Flag {
|
||||||
*
|
*
|
||||||
* @return Parser name
|
* @return Parser name
|
||||||
*/
|
*/
|
||||||
String parserName() default "";
|
@NonNull String parserName() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the suggestions provider to use. If the string is left empty, the default
|
||||||
|
* provider for the argument parser will be used. Otherwise,
|
||||||
|
* the {@link cloud.commandframework.arguments.parser.ParserRegistry} instance in the
|
||||||
|
* {@link cloud.commandframework.CommandManager} will be queried for a matching suggestion provider.
|
||||||
|
* <p>
|
||||||
|
* For this to work, the suggestion needs to be registered in the parser registry. To do this, use
|
||||||
|
* {@link cloud.commandframework.arguments.parser.ParserRegistry#registerSuggestionProvider(String, BiFunction)}.
|
||||||
|
* The registry instance can be retrieved using {@link cloud.commandframework.CommandManager#getParserRegistry()}.
|
||||||
|
*
|
||||||
|
* @return The name of the suggestion provider, or {@code ""} if the default suggestion provider for the argument parser
|
||||||
|
* should be used instead
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
@NonNull String suggestions() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The argument description
|
* The argument description
|
||||||
*
|
*
|
||||||
* @return Argument description
|
* @return Argument description
|
||||||
*/
|
*/
|
||||||
String description() default "";
|
@NonNull String description() default "";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@ import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Parameter;
|
import java.lang.reflect.Parameter;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
final class FlagExtractor implements Function<@NonNull Method, Collection<@NonNull CommandFlag<?>>> {
|
final class FlagExtractor implements Function<@NonNull Method, Collection<@NonNull CommandFlag<?>>> {
|
||||||
|
|
@ -78,14 +80,25 @@ final class FlagExtractor implements Function<@NonNull Method, Collection<@NonNu
|
||||||
parameter.getType().getCanonicalName(), flag.value(), method.getName()
|
parameter.getType().getCanonicalName(), flag.value(), method.getName()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
final CommandArgument.Builder argumentBuilder = CommandArgument.ofType(
|
final BiFunction<?, @NonNull String, @NonNull List<String>> suggestionProvider;
|
||||||
|
if (!flag.suggestions().isEmpty()) {
|
||||||
|
suggestionProvider = registry.getSuggestionProvider(flag.suggestions()).orElse(null);
|
||||||
|
} else {
|
||||||
|
suggestionProvider = null;
|
||||||
|
}
|
||||||
|
final CommandArgument.Builder argumentBuilder0 = CommandArgument.ofType(
|
||||||
parameter.getType(),
|
parameter.getType(),
|
||||||
flag.value()
|
flag.value()
|
||||||
);
|
);
|
||||||
final CommandArgument argument = argumentBuilder.asRequired()
|
final CommandArgument.Builder argumentBuilder = argumentBuilder0.asRequired()
|
||||||
.manager(this.commandManager)
|
.manager(this.commandManager)
|
||||||
.withParser(parser)
|
.withParser(parser);
|
||||||
.build();
|
final CommandArgument argument;
|
||||||
|
if (suggestionProvider != null) {
|
||||||
|
argument = argumentBuilder.withSuggestionsProvider(suggestionProvider).build();
|
||||||
|
} else {
|
||||||
|
argument = argumentBuilder.build();
|
||||||
|
}
|
||||||
flags.add(builder.withArgument(argument).build());
|
flags.add(builder.withArgument(argument).build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag value mappings
|
* Flag value mappings
|
||||||
|
|
@ -78,11 +79,11 @@ public final class FlagContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether or not a flag is present. This will return {@code false}
|
* Check whether a presence flag is present. This will return {@code false}
|
||||||
* for all value flags.
|
* for all value flags.
|
||||||
*
|
*
|
||||||
* @param flag Flag name
|
* @param flag Flag name
|
||||||
* @return {@code true} if the flag is presence and the flag is a presence flag,
|
* @return {@code true} if the flag is a presence flag and is present,
|
||||||
* else {@code false}
|
* else {@code false}
|
||||||
*/
|
*/
|
||||||
public boolean isPresent(final @NonNull String flag) {
|
public boolean isPresent(final @NonNull String flag) {
|
||||||
|
|
@ -90,6 +91,25 @@ public final class FlagContext {
|
||||||
return FLAG_PRESENCE_VALUE.equals(value);
|
return FLAG_PRESENCE_VALUE.equals(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a flag value as an optional. Will be empty if the value is not present.
|
||||||
|
*
|
||||||
|
* @param name Flag name
|
||||||
|
* @param <T> Value type
|
||||||
|
* @return Optional containing stored value if present
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public <T> @NonNull Optional<T> getValue(
|
||||||
|
final @NonNull String name
|
||||||
|
) {
|
||||||
|
final Object value = this.flagValues.get(name);
|
||||||
|
if (value == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
@SuppressWarnings("unchecked") final T casted = (T) value;
|
||||||
|
return Optional.of(casted);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a flag value
|
* Get a flag value
|
||||||
*
|
*
|
||||||
|
|
@ -102,12 +122,22 @@ public final class FlagContext {
|
||||||
final @NonNull String name,
|
final @NonNull String name,
|
||||||
final @Nullable T defaultValue
|
final @Nullable T defaultValue
|
||||||
) {
|
) {
|
||||||
final Object value = this.flagValues.get(name);
|
return this.<T>getValue(name).orElse(defaultValue);
|
||||||
if (value == null) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
}
|
||||||
@SuppressWarnings("unchecked") final T casted = (T) value;
|
|
||||||
return casted;
|
/**
|
||||||
|
* Check whether a flag is present. This will return {@code true} if the flag
|
||||||
|
* is a presence flag and is present, or if the flag is a value flag and has
|
||||||
|
* a value provided.
|
||||||
|
*
|
||||||
|
* @param name Flag name
|
||||||
|
* @return {@code true} if the flag is present, else {@code false}
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public boolean hasFlag(
|
||||||
|
final @NonNull String name
|
||||||
|
) {
|
||||||
|
return this.getValue(name).isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ public interface ParserRegistry<C> {
|
||||||
* Get a named suggestion provider, if a suggestion provider with the given name exists in the registry
|
* Get a named suggestion provider, if a suggestion provider with the given name exists in the registry
|
||||||
*
|
*
|
||||||
* @param name Suggestion provider name. The name is case independent.
|
* @param name Suggestion provider name. The name is case independent.
|
||||||
* @return Optional that either contains the suggestion provider name, or nothing ({@link Optional#empty()}) if no
|
* @return Optional that either contains the suggestion provider, or is empty if no
|
||||||
* suggestion provider is registered with the given name
|
* suggestion provider is registered with the given name
|
||||||
* @see #registerSuggestionProvider(String, BiFunction) Register a suggestion provider
|
* @see #registerSuggestionProvider(String, BiFunction) Register a suggestion provider
|
||||||
* @since 1.1.0
|
* @since 1.1.0
|
||||||
|
|
|
||||||
|
|
@ -253,7 +253,7 @@ public final class MinecraftExceptionHandler<C> {
|
||||||
*/
|
*/
|
||||||
INVALID_SENDER,
|
INVALID_SENDER,
|
||||||
/**
|
/**
|
||||||
* The sender does not have permission to execute the command (@{@link NoPermissionException})
|
* The sender does not have permission to execute the command ({@link NoPermissionException})
|
||||||
*/
|
*/
|
||||||
NO_PERMISSION,
|
NO_PERMISSION,
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue