Skip to content

Commit 7dc752b

Browse files
authored
GH-504 Fix nullable argument profiles (#504)
1 parent ef2021d commit 7dc752b

File tree

13 files changed

+131
-30
lines changed

13 files changed

+131
-30
lines changed

litecommands-annotations/src/dev/rollczi/litecommands/annotations/AnnotationProcessorService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ public static <SENDER> AnnotationProcessorService<SENDER> defaultService() {
6262
.register(new PriorityAnnotationResolver<>())
6363
.register(new ValidateAnnotationResolver<>())
6464
.register(new CooldownAnnotationResolver<>())
65-
// argument meta processors
66-
.register(new KeyAnnotationResolver<>())
6765
// universal processor for requirements such as @Arg, @Varargs, @Flag, @Context, @Bind and more
6866
.register(new RequirementDefinitionProcessor<>())
6967
// profile processors (they apply profiles to arguments)
@@ -76,6 +74,8 @@ public static <SENDER> AnnotationProcessorService<SENDER> defaultService() {
7674
.register(new QuotedAnnotationProcessor<>())
7775
.register(new NullableArgumentProcessor<>())
7876
.register(new OptionalArgArgumentProcessor<>())
77+
// argument meta processors
78+
.register(new KeyAnnotationResolver<>())
7979
;
8080
}
8181

litecommands-annotations/test/dev/rollczi/litecommands/annotations/argument/resolver/nullable/NullableTest.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88

99
class NullableTest extends LiteTestSpec {
1010

11-
static LiteTestConfig config = builder -> builder
12-
.advanced();
13-
1411
@Command(name = "nullable")
1512
static class NullableTestCommand {
1613
@Execute
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package dev.rollczi.litecommands.annotations.argument.resolver.nullable;
2+
3+
import dev.rollczi.litecommands.annotations.argument.Arg;
4+
import dev.rollczi.litecommands.annotations.argument.Key;
5+
import dev.rollczi.litecommands.annotations.command.Command;
6+
import dev.rollczi.litecommands.annotations.execute.Execute;
7+
import dev.rollczi.litecommands.annotations.optional.OptionalArg;
8+
import dev.rollczi.litecommands.argument.ArgumentKey;
9+
import dev.rollczi.litecommands.argument.parser.ParseResult;
10+
import dev.rollczi.litecommands.argument.parser.Parser;
11+
import dev.rollczi.litecommands.unit.annotations.LiteTestSpec;
12+
import java.util.Optional;
13+
import org.junit.jupiter.api.Test;
14+
15+
class OptionalTest extends LiteTestSpec {
16+
17+
interface IFaction {}
18+
19+
static class Faction implements IFaction {}
20+
21+
static LiteTestConfig config = builder -> builder
22+
.argumentParser(Faction.class, ArgumentKey.of("faction"), Parser.of((invocation, text) -> ParseResult.success(new Faction())))
23+
.argumentParser(IFaction.class, ArgumentKey.of("ifaction"), Parser.of((invocation, text) -> ParseResult.success(new Faction())))
24+
.advanced();
25+
26+
@Command(name = "optional")
27+
static class OptionalTestCommand {
28+
@Execute
29+
String executeOptional(@Arg("display-faction") @Key("faction") Optional<Faction> faction) {
30+
return faction.isPresent() ? "present" : "not present";
31+
}
32+
33+
@Execute(name = "interface")
34+
String executeInterfaceOptional(@OptionalArg("display-faction") @Key("ifaction") IFaction faction) {
35+
return faction != null ? "interface present" : "interface not present";
36+
}
37+
}
38+
39+
@Test
40+
void testOptionalExecute() {
41+
platform.execute("optional")
42+
.assertSuccess("not present");
43+
44+
platform.execute("optional faction")
45+
.assertSuccess("present");
46+
47+
platform.execute("optional interface")
48+
.assertSuccess("interface not present");
49+
50+
platform.execute("optional interface faction")
51+
.assertSuccess("interface present");
52+
}
53+
54+
}

litecommands-bukkit/src/dev/rollczi/litecommands/bukkit/BukkitPlatform.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,8 @@ class BukkitPlatform extends AbstractPlatform<CommandSender, LiteBukkitSettings>
1717
protected void hook(CommandRoute<CommandSender> commandRoute, PlatformInvocationListener<CommandSender> invocationHook, PlatformSuggestionListener<CommandSender> suggestionHook) {
1818
BukkitCommand bukkitSimpleCommand = new BukkitCommand(settings, commandRoute, invocationHook, suggestionHook);
1919

20-
for (String name : commandRoute.names()) {
21-
this.settings.commandsRegistry().register(name, settings.fallbackPrefix(), bukkitSimpleCommand);
22-
}
2320
this.settings.tabCompleter().register(settings.fallbackPrefix(), bukkitSimpleCommand);
21+
this.settings.commandsRegistry().register(commandRoute.getName(), settings.fallbackPrefix(), bukkitSimpleCommand);
2422
}
2523

2624
@Override

litecommands-core/src/dev/rollczi/litecommands/argument/Argument.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ default Optional<ParseResult<T>> defaultValue() {
3838
@ApiStatus.Experimental
3939
<NEW> Argument<NEW> child(TypeToken<NEW> type);
4040

41+
@ApiStatus.Experimental
42+
Argument<T> withoutProfile(ArgumentProfileNamespace<?> profile);
43+
4144
static <T> Argument<T> of(String name, Class<T> type) {
4245
return new SimpleArgument<>(name, TypeToken.of(type));
4346
}

litecommands-core/src/dev/rollczi/litecommands/argument/SimpleArgument.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,29 @@ public PrioritizedList<ArgumentProfile<?>> getProfiles() {
117117

118118
@Override
119119
public <NEW> Argument<NEW> child(TypeToken<NEW> type) {
120-
return new SimpleArgument<>(name, type, this);
120+
SimpleArgument<NEW> newSimpleArgument = new SimpleArgument<>(name, type, this);
121+
newSimpleArgument.setKey(key.withDefaultNamespace());
122+
newSimpleArgument.meta.putAll(this.meta);
123+
for (ArgumentProfile argumentProfile : profiles) {
124+
newSimpleArgument.addProfile(argumentProfile);
125+
}
126+
return newSimpleArgument;
127+
}
128+
129+
@Override
130+
public Argument<T> withoutProfile(ArgumentProfileNamespace<?> profile) {
131+
SimpleArgument<T> argument = new SimpleArgument<>(name, type, nullable);
132+
argument.setKey(key.withDefaultNamespace());
133+
argument.meta.putAll(this.meta);
134+
for (ArgumentProfile argumentProfile : profiles) {
135+
if (!argumentProfile.getNamespace().equals(profile)) {
136+
argument.addProfile(argumentProfile);
137+
}
138+
else {
139+
argument.meta.remove(profile.asMetaKey());
140+
}
141+
}
142+
return argument;
121143
}
122144

123145
@Override

litecommands-core/src/dev/rollczi/litecommands/argument/parser/Parser.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import dev.rollczi.litecommands.LiteCommandsException;
44
import dev.rollczi.litecommands.argument.Argument;
55
import dev.rollczi.litecommands.argument.matcher.Matcher;
6+
import dev.rollczi.litecommands.argument.resolver.ArgumentResolver;
67
import dev.rollczi.litecommands.input.raw.RawInput;
78
import dev.rollczi.litecommands.invocation.Invocation;
89
import dev.rollczi.litecommands.range.Rangeable;
910
import dev.rollczi.litecommands.requirement.RequirementResult;
11+
import java.util.function.BiFunction;
1012
import org.jetbrains.annotations.ApiStatus;
1113

1214
public interface Parser<SENDER, PARSED> extends Matcher<SENDER, PARSED>, Rangeable<Argument<PARSED>> {
@@ -42,4 +44,14 @@ default boolean match(Invocation<SENDER> invocation, Argument<PARSED> argument,
4244
throw new LiteCommandsException("Async parsers should override Parser#match method! (" + this.getClass().getName() + ")");
4345
}
4446

47+
@ApiStatus.Experimental
48+
static <SENDER, T> Parser<SENDER, T> of(BiFunction<Invocation<SENDER>, String, ParseResult<T>> parser) {
49+
return new ArgumentResolver<SENDER, T>() {
50+
@Override
51+
protected ParseResult<T> parse(Invocation<SENDER> invocation, Argument<T> context, String argument) {
52+
return parser.apply(invocation, argument);
53+
}
54+
};
55+
}
56+
4557
}

litecommands-core/src/dev/rollczi/litecommands/argument/resolver/collector/AbstractCollectorArgumentResolver.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ private <E> boolean match0(Invocation<SENDER> invocation, Argument<COLLECTION> c
7878
}
7979

8080
TypeToken<E> elementType = this.getElementType(collectionArgumentContainer);
81-
Argument<E> argument = collectionArgument.child(elementType);
81+
Argument<E> argument = collectionArgument.child(elementType)
82+
.withoutProfile(VarargsProfile.NAMESPACE);
8283
Parser<SENDER, E> parser = parserRegistry.getParser(argument);
8384
Range range = parser.getRange(argument);
8485

@@ -100,7 +101,8 @@ private <E> boolean match0(Invocation<SENDER> invocation, Argument<COLLECTION> c
100101
}
101102

102103
private <E> ParseResult<List<E>> parseToList(TypeToken<E> componentType, RawInput rawInput, Argument<COLLECTION> collectionArgument, VarargsProfile collectorArgumentHolder, Invocation<SENDER> invocation) {
103-
Argument<E> argument = collectionArgument.child(componentType);
104+
Argument<E> argument = collectionArgument.child(componentType)
105+
.withoutProfile(VarargsProfile.NAMESPACE);
104106

105107
Parser<SENDER, E> parser = parserRegistry.getParser(argument);
106108

@@ -214,7 +216,8 @@ public SuggestionResult suggest(Invocation<SENDER> invocation, Argument<COLLECTI
214216
}
215217

216218
private <T> SuggestionResult suggest(TypeToken<T> componentType, SuggestionContext context, Argument<COLLECTION> collectionArgument, VarargsProfile varargsProfile, Invocation<SENDER> invocation) {
217-
Argument<T> argument = collectionArgument.child(componentType);
219+
Argument<T> argument = collectionArgument.child(componentType)
220+
.withoutProfile(VarargsProfile.NAMESPACE);
218221

219222
Parser<SENDER, T> parser = parserRegistry.getParser(argument);
220223
Suggester<SENDER, T> suggester = suggesterRegistry.getSuggester(componentType.getRawType(), argument.getKey());

litecommands-core/src/dev/rollczi/litecommands/argument/resolver/nullable/NullableArgumentResolver.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import dev.rollczi.litecommands.argument.parser.ParseResult;
55
import dev.rollczi.litecommands.argument.parser.Parser;
66
import dev.rollczi.litecommands.argument.parser.ParserRegistry;
7+
import dev.rollczi.litecommands.argument.profile.ProfileNamespaces;
78
import dev.rollczi.litecommands.argument.profile.ProfiledMultipleArgumentResolver;
89
import dev.rollczi.litecommands.argument.suggester.Suggester;
910
import dev.rollczi.litecommands.argument.suggester.SuggesterRegistry;
@@ -28,13 +29,11 @@ public NullableArgumentResolver(ParserRegistry<SENDER> parserRegistry, Suggester
2829

2930
@Override
3031
protected ParseResult<Object> parse(Invocation<SENDER> invocation, Argument<Object> argument, RawInput rawInput, NullableProfile unused) {
31-
TypeToken<Object> optionalType = argument.getType();
32-
33-
return parseValue(optionalType, invocation, argument, rawInput);
32+
return parseValue(invocation, argument, rawInput);
3433
}
3534

36-
private <E> ParseResult<E> parseValue(TypeToken<E> type, Invocation<SENDER> invocation, Argument<Object> optionalArgument, RawInput input) {
37-
Argument<E> argument = Argument.of(optionalArgument.getName(), type);
35+
private <E> ParseResult<E> parseValue(Invocation<SENDER> invocation, Argument<E> optionalArgument, RawInput input) {
36+
Argument<E> argument = optionalArgument.withoutProfile(ProfileNamespaces.NULLABLE);
3837
Parser<SENDER, E> parser = parserRegistry.getParser(argument);
3938
ParseResult<E> parseResult = parser.parse(invocation, argument, input);
4039

@@ -55,7 +54,15 @@ protected SuggestionResult suggest(Invocation<SENDER> invocation, Argument<Objec
5554

5655
@Override
5756
protected Range getRange(Argument<Object> argument, NullableProfile unused) {
58-
return Range.range(0, 1);
57+
return getRangeTyped(argument);
58+
}
59+
60+
private <T> Range getRangeTyped(Argument<T> optionalArgument) {
61+
Argument<T> argument = optionalArgument.withoutProfile(ProfileNamespaces.NULLABLE);
62+
Parser<SENDER, T> parser = parserRegistry.getParser(argument);
63+
Range range = parser.getRange(argument);
64+
65+
return Range.range(0, range.getMax());
5966
}
6067

6168
}

litecommands-core/src/dev/rollczi/litecommands/argument/resolver/optional/OptionalArgumentResolver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public ParseResult<Optional> parse(Invocation<SENDER> invocation, Argument<Optio
3535

3636
@SuppressWarnings("unchecked")
3737
private <E> ParseResult<Optional> parseValue(TypeToken<E> type, Invocation<SENDER> invocation, Argument<Optional> optionalArgument, RawInput input, ParserChainAccessor<SENDER> chainAccessor) {
38-
Argument<E> argument = Argument.of(optionalArgument.getName(), type);
38+
Argument<E> argument = optionalArgument.child(type);
3939
ParseResult parseResult = chainAccessor.parse(invocation, argument.child(type), input);
4040

4141
return parseResult
@@ -65,7 +65,7 @@ public SuggestionResult suggest(Invocation<SENDER> invocation, Argument<Optional
6565
TypeToken<Optional> optionalType = argument.getType();
6666
TypeToken<?> parameterized = optionalType.getParameterized();
6767

68-
return chainAccessor.suggest(invocation, Argument.of(argument.getName(), parameterized), context);
68+
return chainAccessor.suggest(invocation, argument.child(parameterized), context);
6969
}
7070

7171
}

0 commit comments

Comments
 (0)