Skip to content

Commit aba4290

Browse files
Clean up SuggestionProvider hierarchy (#567)
* Initial pass at cleaning up SuggestionProvider hierarchy * Fix examples * Add helper methods * Remove DelegatingSuggestionProvider * Fix selector suggestion permission bypass with dumb hack * Add constant suggestion helpers * feat: don't make `ArgumentParser` implement `SuggestionProvider` * remove `NoSuggestions` * Clean up CommandComponent diff * Improve SuggestionProvider docs * a * missed these * Move BlockingSuggestionProvider to own file --------- Co-authored-by: Alexander Söderberg <alexander.soderberg@incendo.org>
1 parent bd727ec commit aba4290

54 files changed

Lines changed: 434 additions & 302 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

build-logic/src/main/kotlin/cloud.base-conventions.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ tasks {
3333
"EqualsGetClass",
3434
"CatchAndPrintStackTrace",
3535
"InlineMeSuggester",
36-
"InlineTrivialConstant"
36+
"InlineTrivialConstant",
37+
"FunctionalInterfaceMethodChanged"
3738
)
3839
disableWarningsInGeneratedCode.set(true)
3940
}

cloud-annotations/src/main/java/cloud/commandframework/annotations/AnnotationParser.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ private <T> void parseParsers(final @NonNull T instance) {
796796
final String suggestions = this.processString(parser.suggestions());
797797
final SuggestionProvider<C> suggestionProvider;
798798
if (suggestions.isEmpty()) {
799-
suggestionProvider = (context, input) -> Collections.emptyList();
799+
suggestionProvider = SuggestionProvider.noSuggestions();
800800
} else {
801801
suggestionProvider = this.manager.parserRegistry().getSuggestionProvider(suggestions)
802802
.orElseThrow(() -> new NullPointerException(
@@ -864,7 +864,10 @@ private <T> void parseParsers(final @NonNull T instance) {
864864
builder = decorator.decorate(builder);
865865
}
866866

867-
final Collection<ArgumentDescriptor> arguments = this.argumentExtractor.extractArguments(commandDescriptor.syntax(), method);
867+
final Collection<ArgumentDescriptor> arguments = this.argumentExtractor.extractArguments(
868+
commandDescriptor.syntax(),
869+
method
870+
);
868871
final Collection<FlagDescriptor> flagDescriptors = this.flagExtractor.extractFlags(method);
869872
final Collection<CommandFlag<?>> flags = flagDescriptors.stream()
870873
.map(this.flagAssembler()::assembleFlag)
@@ -953,8 +956,7 @@ private <T> void parseParsers(final @NonNull T instance) {
953956
/* Apply builder modifiers */
954957
for (final Annotation annotation
955958
: AnnotationAccessor.of(classAnnotations, AnnotationAccessor.of(method)).annotations()) {
956-
@SuppressWarnings("rawtypes")
957-
final BuilderModifier builderModifier = this.builderModifiers.get(
959+
@SuppressWarnings("rawtypes") final BuilderModifier builderModifier = this.builderModifiers.get(
958960
annotation.annotationType()
959961
);
960962
if (builderModifier == null) {

cloud-annotations/src/main/java/cloud/commandframework/annotations/ArgumentAssemblerImpl.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ final class ArgumentAssemblerImpl<C> implements ArgumentAssembler<C> {
6666
parser = this.annotationParser.manager().parserRegistry()
6767
.createParser(token, parameters)
6868
.orElseThrow(() -> new IllegalArgumentException(
69-
String.format("Parameter '%s' "
69+
String.format(
70+
"Parameter '%s' "
7071
+ "has parser '%s' but no parser exists "
7172
+ "for that type",
7273
parameter.getName(),
@@ -76,7 +77,8 @@ final class ArgumentAssemblerImpl<C> implements ArgumentAssembler<C> {
7677
parser = this.annotationParser.manager().parserRegistry()
7778
.createParser(this.annotationParser.processString(descriptor.parserName()), parameters)
7879
.orElseThrow(() -> new IllegalArgumentException(
79-
String.format("Parameter '%s' "
80+
String.format(
81+
"Parameter '%s' "
8082
+ "has parser '%s' but no parser exists "
8183
+ "for that type",
8284
parameter.getName(),
@@ -90,8 +92,7 @@ final class ArgumentAssemblerImpl<C> implements ArgumentAssembler<C> {
9092
"Invalid command argument '%s': Missing syntax mapping", argumentName));
9193
}
9294

93-
@SuppressWarnings("rawtypes")
94-
final CommandComponent.Builder componentBuilder = CommandComponent.builder();
95+
@SuppressWarnings("rawtypes") final CommandComponent.Builder componentBuilder = CommandComponent.builder();
9596
componentBuilder.commandManager(this.annotationParser.manager())
9697
.valueType(parameter.getType())
9798
.name(argumentName)
@@ -104,7 +105,7 @@ final class ArgumentAssemblerImpl<C> implements ArgumentAssembler<C> {
104105
final List<Suggestion> suggestions = Arrays.stream(
105106
completions.value().replace(" ", "").split(",")
106107
).map(Suggestion::simple).collect(Collectors.toList());
107-
componentBuilder.suggestionProvider((commandContext, input) -> suggestions);
108+
componentBuilder.suggestionProvider(SuggestionProvider.suggesting(suggestions));
108109
} else if (descriptor.suggestions() != null) {
109110
final String suggestionProviderName = this.annotationParser.processString(descriptor.suggestions());
110111
final Optional<SuggestionProvider<C>> suggestionsFunction =

cloud-annotations/src/main/java/cloud/commandframework/annotations/parsers/MethodArgumentParser.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,12 @@
2525

2626
import cloud.commandframework.arguments.parser.ArgumentParseResult;
2727
import cloud.commandframework.arguments.parser.ArgumentParser;
28-
import cloud.commandframework.arguments.suggestion.Suggestion;
2928
import cloud.commandframework.arguments.suggestion.SuggestionProvider;
3029
import cloud.commandframework.context.CommandContext;
3130
import cloud.commandframework.context.CommandInput;
3231
import java.lang.invoke.MethodHandle;
3332
import java.lang.invoke.MethodHandles;
3433
import java.lang.reflect.Method;
35-
import java.util.List;
3634
import org.checkerframework.checker.nullness.qual.NonNull;
3735

3836
/**
@@ -80,10 +78,7 @@ public MethodArgumentParser(
8078
}
8179

8280
@Override
83-
public @NonNull List<@NonNull Suggestion> suggestions(
84-
final @NonNull CommandContext<C> commandContext,
85-
final @NonNull String input
86-
) {
87-
return this.suggestionProvider.suggestions(commandContext, input);
81+
public @NonNull SuggestionProvider<C> suggestionProvider() {
82+
return this.suggestionProvider;
8883
}
8984
}

cloud-annotations/src/main/java/cloud/commandframework/annotations/suggestions/MethodSuggestionProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
* @param <C> Command sender type
4545
* @since 1.3.0
4646
*/
47-
public final class MethodSuggestionProvider<C> implements SuggestionProvider.FutureSuggestionProvider<C> {
47+
public final class MethodSuggestionProvider<C> implements SuggestionProvider<C> {
4848

4949
private final MethodHandle methodHandle;
5050

cloud-annotations/src/test/java/cloud/commandframework/annotations/AnnotationParserTest.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
import java.util.ArrayList;
4848
import java.util.Arrays;
4949
import java.util.Collection;
50-
import java.util.Collections;
5150
import java.util.List;
5251
import java.util.concurrent.CompletionException;
5352
import java.util.stream.Collectors;
@@ -62,7 +61,8 @@
6261
class AnnotationParserTest {
6362

6463
private static final List<Suggestion> NAMED_SUGGESTIONS = Arrays.asList("Dancing-Queen", "Gimme!-Gimme!-Gimme!",
65-
"Waterloo").stream().map(Suggestion::simple).collect(Collectors.toList());
64+
"Waterloo"
65+
).stream().map(Suggestion::simple).collect(Collectors.toList());
6666

6767
private CommandManager<TestCommandSender> manager;
6868
private AnnotationParser<TestCommandSender> annotationParser;
@@ -76,7 +76,7 @@ void setup() {
7676
/* Register a suggestion provider */
7777
manager.parserRegistry().registerSuggestionProvider(
7878
"some-name",
79-
(context, input) -> NAMED_SUGGESTIONS
79+
SuggestionProvider.suggesting(NAMED_SUGGESTIONS)
8080
);
8181
/* Register a parameter injector */
8282
annotationParser.getParameterInjectorRegistry().registerInjector(
@@ -160,7 +160,9 @@ void testAnnotatedSuggestionProviders() {
160160
final SuggestionProvider<TestCommandSender> suggestionProvider =
161161
this.manager.parserRegistry().getSuggestionProvider("cows").orElse(null);
162162
Assertions.assertNotNull(suggestionProvider);
163-
Assertions.assertTrue(suggestionProvider.suggestions(new CommandContext<>(new TestCommandSender(), manager), "")
163+
Assertions.assertTrue(suggestionProvider
164+
.suggestionsFuture(new CommandContext<>(new TestCommandSender(), manager), "")
165+
.join()
164166
.contains(Suggestion.simple("Stella")));
165167
}
166168

@@ -178,10 +180,10 @@ void testAnnotatedArgumentParser() {
178180
context,
179181
CommandInput.empty()
180182
).getParsedValue().orElse(new CustomType("")).toString());
181-
Assertions.assertTrue(parser.suggestions(
183+
Assertions.assertTrue(parser.suggestionProvider().suggestionsFuture(
182184
context,
183185
""
184-
).contains(Suggestion.simple("Stella")));
186+
).join().contains(Suggestion.simple("Stella")));
185187
}
186188

187189
@Test

cloud-annotations/src/test/java/cloud/commandframework/annotations/feature/MethodSuggestionProviderTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ void testSuggestions(final @NonNull Object instance) {
7474
this.commandManager.parserRegistry()
7575
.getSuggestionProvider("suggestions")
7676
.orElseThrow(NullPointerException::new)
77-
.suggestions(context, "");
77+
.suggestionsFuture(context, "")
78+
.join();
7879

7980
// Assert
8081
assertThat(suggestions).containsExactly(Suggestion.simple("foo"));

cloud-core/src/main/java/cloud/commandframework/CommandComponent.java

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,10 @@ public class CommandComponent<C> implements Comparable<CommandComponent<C>>, Pre
8686
/**
8787
* Creates a new mutable builder.
8888
*
89-
* @param <C> the command sender type
90-
* @param <T> the component value type
89+
* @param <C> the command sender type
90+
* @param <T> the component value type
9191
* @param clazz the type of the component
92-
* @param name the name of the component
92+
* @param name the name of the component
9393
* @return the builder
9494
* @since 2.0.0
9595
*/
@@ -102,14 +102,14 @@ public class CommandComponent<C> implements Comparable<CommandComponent<C>>, Pre
102102
}
103103

104104
CommandComponent(
105-
final @NonNull String name,
106-
final @NonNull ArgumentParser<C, ?> parser,
107-
final @NonNull TypeToken<?> valueType,
108-
final @NonNull Description description,
109-
final @NonNull ComponentType componentType,
110-
final @Nullable DefaultValue<C, ?> defaultValue,
111-
final @NonNull SuggestionProvider<C> suggestionProvider,
112-
final @NonNull Collection<@NonNull ComponentPreprocessor<C>> componentPreprocessors
105+
final @NonNull String name,
106+
final @NonNull ArgumentParser<C, ?> parser,
107+
final @NonNull TypeToken<?> valueType,
108+
final @NonNull Description description,
109+
final @NonNull ComponentType componentType,
110+
final @Nullable DefaultValue<C, ?> defaultValue,
111+
final @NonNull SuggestionProvider<C> suggestionProvider,
112+
final @NonNull Collection<@NonNull ComponentPreprocessor<C>> componentPreprocessors
113113
) {
114114
this.name = name;
115115
this.parser = parser;
@@ -601,13 +601,13 @@ public static class Builder<C, T> {
601601
if (this.parser != null) {
602602
parser = this.parser;
603603
} else if (this.commandManager != null) {
604-
parser = this.commandManager.parserRegistry()
605-
.createParser(this.valueType, ParserParameters.empty())
606-
.orElse(null);
604+
parser = this.commandManager.parserRegistry()
605+
.createParser(this.valueType, ParserParameters.empty())
606+
.orElse(null);
607607
}
608608
if (parser == null) {
609-
parser = (c, i) -> ArgumentParseResult
610-
.failure(new UnsupportedOperationException("No parser was specified"));
609+
parser = (ctx, input) -> ArgumentParseResult.failure(
610+
new UnsupportedOperationException("No parser was specified"));
611611
}
612612

613613
final ComponentType componentType;
@@ -623,7 +623,7 @@ public static class Builder<C, T> {
623623

624624
final SuggestionProvider<C> suggestionProvider;
625625
if (this.suggestionProvider == null) {
626-
suggestionProvider = parser;
626+
suggestionProvider = parser.suggestionProvider();
627627
} else {
628628
suggestionProvider = this.suggestionProvider;
629629
}

cloud-core/src/main/java/cloud/commandframework/arguments/LiteralParser.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import cloud.commandframework.arguments.parser.ArgumentParseResult;
2727
import cloud.commandframework.arguments.parser.ArgumentParser;
2828
import cloud.commandframework.arguments.parser.ParserDescriptor;
29+
import cloud.commandframework.arguments.suggestion.BlockingSuggestionProvider;
2930
import cloud.commandframework.context.CommandContext;
3031
import cloud.commandframework.context.CommandInput;
3132
import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
@@ -39,7 +40,7 @@
3940
import org.apiguardian.api.API;
4041
import org.checkerframework.checker.nullness.qual.NonNull;
4142

42-
public final class LiteralParser<C> implements ArgumentParser<C, String> {
43+
public final class LiteralParser<C> implements ArgumentParser<C, String>, BlockingSuggestionProvider.Strings<C> {
4344

4445
/**
4546
* Creates a new literal parser that accepts the given {@code name} and {@code aliases}.
@@ -54,7 +55,7 @@ public final class LiteralParser<C> implements ArgumentParser<C, String> {
5455
public static <C> @NonNull ParserDescriptor<C, String> literal(
5556
final @NonNull String name,
5657
final @NonNull String @NonNull... aliases
57-
) {
58+
) {
5859
return ParserDescriptor.of(new LiteralParser<>(name, aliases), String.class);
5960
}
6061

cloud-core/src/main/java/cloud/commandframework/arguments/aggregate/AggregateCommandParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import cloud.commandframework.arguments.parser.ArgumentParser;
2828
import cloud.commandframework.arguments.parser.ParserDescriptor;
2929
import cloud.commandframework.arguments.suggestion.Suggestion;
30+
import cloud.commandframework.arguments.suggestion.SuggestionProvider;
3031
import cloud.commandframework.context.CommandContext;
3132
import cloud.commandframework.context.CommandInput;
3233
import cloud.commandframework.keys.CloudKey;
@@ -56,7 +57,8 @@
5657
* @since 2.0.0
5758
*/
5859
@API(status = API.Status.STABLE, since = "2.0.0")
59-
public interface AggregateCommandParser<C, O> extends ArgumentParser.FutureArgumentParser<C, O>, ParserDescriptor<C, O> {
60+
public interface AggregateCommandParser<C, O> extends ArgumentParser.FutureArgumentParser<C, O>, ParserDescriptor<C, O>,
61+
SuggestionProvider<C> {
6062

6163
/**
6264
* Returns a new aggregate command parser builder. The builder is immutable, and each method returns

0 commit comments

Comments
 (0)