From 6cc3a2161958a9e3429077da6a3ee81a7b6e23cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Fri, 18 Dec 2020 12:54:11 +0100 Subject: [PATCH] :sparkles: Allow default suggestion providers in `@Parser` --- .../annotations/AnnotationParser.java | 14 ++++++++++++++ .../parsers/MethodArgumentParser.java | 18 ++++++++++++++++-- .../annotations/parsers/Parser.java | 15 +++++++++++++++ .../annotations/AnnotationParserTest.java | 15 ++++++++++----- 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/cloud-annotations/src/main/java/cloud/commandframework/annotations/AnnotationParser.java b/cloud-annotations/src/main/java/cloud/commandframework/annotations/AnnotationParser.java index f3e70d8f..d4bd060f 100644 --- a/cloud-annotations/src/main/java/cloud/commandframework/annotations/AnnotationParser.java +++ b/cloud-annotations/src/main/java/cloud/commandframework/annotations/AnnotationParser.java @@ -58,6 +58,7 @@ import java.lang.reflect.Parameter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -317,7 +318,20 @@ public final class AnnotationParser { )); } try { + final BiFunction, String, List> suggestionsProvider; + if (parser.suggestions().isEmpty()) { + suggestionsProvider = (context, input) -> Collections.emptyList(); + } else { + suggestionsProvider = this.manager.getParserRegistry().getSuggestionProvider(parser.suggestions()) + .orElseThrow(() -> new NullPointerException( + String.format( + "Cannot find the suggestions provider with name '%s'", + parser.suggestions() + ) + )); + } final MethodArgumentParser methodArgumentParser = new MethodArgumentParser<>( + suggestionsProvider, instance, method ); diff --git a/cloud-annotations/src/main/java/cloud/commandframework/annotations/parsers/MethodArgumentParser.java b/cloud-annotations/src/main/java/cloud/commandframework/annotations/parsers/MethodArgumentParser.java index fe824408..ec9417ce 100644 --- a/cloud-annotations/src/main/java/cloud/commandframework/annotations/parsers/MethodArgumentParser.java +++ b/cloud-annotations/src/main/java/cloud/commandframework/annotations/parsers/MethodArgumentParser.java @@ -31,7 +31,9 @@ import org.checkerframework.checker.nullness.qual.NonNull; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; +import java.util.List; import java.util.Queue; +import java.util.function.BiFunction; /** * Represents a method annotated with {@link Parser} @@ -42,19 +44,23 @@ import java.util.Queue; */ public class MethodArgumentParser implements ArgumentParser { + private final BiFunction, String, List> suggestionProvider; private final MethodHandle methodHandle; /** * Create a new parser * - * @param instance Instance that owns the method - * @param method The annotated method + * @param suggestionProvider Suggestion provider + * @param instance Instance that owns the method + * @param method The annotated method * @throws Exception If the method lookup fails */ public MethodArgumentParser( + final @NonNull BiFunction, String, List> suggestionProvider, final @NonNull Object instance, final @NonNull Method method ) throws Exception { + this.suggestionProvider = suggestionProvider; this.methodHandle = MethodHandles.lookup().unreflect(method).bindTo(instance); } @@ -73,4 +79,12 @@ public class MethodArgumentParser implements ArgumentParser { } } + @Override + public @NonNull List<@NonNull String> suggestions( + final @NonNull CommandContext commandContext, + final @NonNull String input + ) { + return this.suggestionProvider.apply(commandContext, input); + } + } diff --git a/cloud-annotations/src/main/java/cloud/commandframework/annotations/parsers/Parser.java b/cloud-annotations/src/main/java/cloud/commandframework/annotations/parsers/Parser.java index 3cf2559e..9ead20cd 100644 --- a/cloud-annotations/src/main/java/cloud/commandframework/annotations/parsers/Parser.java +++ b/cloud-annotations/src/main/java/cloud/commandframework/annotations/parsers/Parser.java @@ -27,6 +27,7 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.function.BiFunction; /** * This annotation allows you to create annotated methods that behave like argument parsers. @@ -52,4 +53,18 @@ public @interface Parser { */ String name() default ""; + /** + * Name of the suggestions provider to use. If the string is left empty, the default + * provider for the {@link cloud.commandframework.annotations.Argument} 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. + *

+ * 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 ""} + */ + String suggestions() default ""; + } diff --git a/cloud-annotations/src/test/java/cloud/commandframework/annotations/AnnotationParserTest.java b/cloud-annotations/src/test/java/cloud/commandframework/annotations/AnnotationParserTest.java index f2ba9024..5a3c49ce 100644 --- a/cloud-annotations/src/test/java/cloud/commandframework/annotations/AnnotationParserTest.java +++ b/cloud-annotations/src/test/java/cloud/commandframework/annotations/AnnotationParserTest.java @@ -153,13 +153,18 @@ class AnnotationParserTest { TypeToken.get(CustomType.class), ParserParameters.empty() ).orElseThrow(() -> new NullPointerException("Could not find CustomType parser")); + final CommandContext context = new CommandContext<>( + new TestCommandSender(), + this.manager + ); Assertions.assertEquals("yay", parser.parse( - new CommandContext<>( - new TestCommandSender(), - this.manager - ), + context, new LinkedList<>() ).getParsedValue().orElse(new CustomType("")).toString()); + Assertions.assertTrue(parser.suggestions( + context, + "" + ).contains("Stella")); } @Suggestions("cows") @@ -167,7 +172,7 @@ class AnnotationParserTest { return Arrays.asList("Stella", "Bella", "Agda"); } - @Parser + @Parser(suggestions = "cows") public CustomType customTypeParser(final CommandContext context, final Queue input) { return new CustomType("yay"); }