Skip to content

Commit e8edda5

Browse files
authored
GH-378 GH-459 Support literal arguments. Support collections types for OptionalArg (#458)
* Support literal arguments. * Add support for OptionalArg with a collection.
1 parent 1cfccf1 commit e8edda5

File tree

17 files changed

+421
-29
lines changed

17 files changed

+421
-29
lines changed

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package dev.rollczi.litecommands.annotations;
22

3+
import dev.rollczi.litecommands.annotations.argument.Arg;
34
import dev.rollczi.litecommands.annotations.argument.KeyAnnotationResolver;
4-
import dev.rollczi.litecommands.annotations.argument.collection.ArgCollectionArgumentProcessor;
5+
import dev.rollczi.litecommands.annotations.optional.OptionalArg;
6+
import dev.rollczi.litecommands.annotations.varargs.VarargsAnyArgumentProcessor;
57
import dev.rollczi.litecommands.annotations.argument.nullable.NullableArgumentProcessor;
68
import dev.rollczi.litecommands.annotations.async.AsyncAnnotationResolver;
79
import dev.rollczi.litecommands.annotations.command.CommandAnnotationProcessor;
@@ -11,6 +13,7 @@
1113
import dev.rollczi.litecommands.annotations.execute.ExecuteAnnotationResolver;
1214
import dev.rollczi.litecommands.annotations.flag.FlagAnnotationProcessor;
1315
import dev.rollczi.litecommands.annotations.join.JoinArgumentProcessor;
16+
import dev.rollczi.litecommands.annotations.literal.LiteralArgumentProcessor;
1417
import dev.rollczi.litecommands.annotations.meta.MarkMetaAnnotationResolver;
1518
import dev.rollczi.litecommands.annotations.optional.OptionalArgArgumentProcessor;
1619
import dev.rollczi.litecommands.annotations.permission.PermissionAnnotationResolver;
@@ -66,7 +69,9 @@ public static <SENDER> AnnotationProcessorService<SENDER> defaultService() {
6669
// profile processors (they apply profiles to arguments)
6770
.register(new FlagAnnotationProcessor<>())
6871
.register(new VarargsArgumentProcessor<>())
69-
.register(new ArgCollectionArgumentProcessor<>())
72+
.register(new VarargsAnyArgumentProcessor<>(Arg.class))
73+
.register(new VarargsAnyArgumentProcessor<>(OptionalArg.class))
74+
.register(new LiteralArgumentProcessor<>())
7075
.register(new JoinArgumentProcessor<>())
7176
.register(new QuotedAnnotationProcessor<>())
7277
.register(new NullableArgumentProcessor<>())
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package dev.rollczi.litecommands.annotations.literal;
2+
3+
import dev.rollczi.litecommands.annotations.requirement.RequirementDefinition;
4+
import java.lang.annotation.ElementType;
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.RetentionPolicy;
7+
import java.lang.annotation.Target;
8+
import org.jetbrains.annotations.ApiStatus;
9+
10+
@Target({ ElementType.PARAMETER })
11+
@Retention(RetentionPolicy.RUNTIME)
12+
@RequirementDefinition(type = RequirementDefinition.Type.ARGUMENT, nameProviders = { "value" })
13+
@ApiStatus.Experimental
14+
public @interface Literal {
15+
16+
String[] value();
17+
18+
boolean ignoreCase() default false;
19+
20+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package dev.rollczi.litecommands.annotations.literal;
2+
3+
import dev.rollczi.litecommands.annotations.argument.profile.ProfileAnnotationProcessor;
4+
import dev.rollczi.litecommands.argument.Argument;
5+
import dev.rollczi.litecommands.literal.LiteralProfile;
6+
import java.lang.reflect.Parameter;
7+
8+
public class LiteralArgumentProcessor<SENDER> extends ProfileAnnotationProcessor<SENDER, Literal, LiteralProfile> {
9+
10+
public LiteralArgumentProcessor() {
11+
super(Literal.class);
12+
}
13+
14+
@Override
15+
protected LiteralProfile createProfile(Parameter parameter, Literal annotation, Argument<?> argument) {
16+
return new LiteralProfile(annotation.value(), annotation.ignoreCase());
17+
}
18+
19+
}

litecommands-annotations/src/dev/rollczi/litecommands/annotations/requirement/RequirementDefinitionProcessor.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.lang.reflect.Method;
2020
import java.lang.reflect.Parameter;
2121
import java.util.Optional;
22+
import org.jetbrains.annotations.NotNull;
2223

2324
/**
2425
* Universal annotation processor for requirements such as {@link Argument}, {@link ContextRequirement} and {@link BindRequirement}.
@@ -63,13 +64,7 @@ private String getName(RequirementDefinition definition, Parameter parameter, An
6364
for (String attributeName : definition.nameProviders()) {
6465
try {
6566
Method attributeMethod = annotation.annotationType().getDeclaredMethod(attributeName);
66-
Object object = attributeMethod.invoke(annotation);
67-
68-
if (!(object instanceof String)) {
69-
throw new LiteCommandsReflectException("Attribute " + attributeName + " in annotation " + annotation.annotationType().getSimpleName() + " must return a String");
70-
}
71-
72-
String nameCandidate = (String) object;
67+
String nameCandidate = getPrimaryName(annotation, attributeName, attributeMethod);
7368

7469
if (!nameCandidate.isEmpty()) {
7570
return nameCandidate;
@@ -83,4 +78,24 @@ private String getName(RequirementDefinition definition, Parameter parameter, An
8378
return parameter.getName();
8479
}
8580

81+
private static @NotNull String getPrimaryName(Annotation annotation, String attributeName, Method attributeMethod) throws IllegalAccessException, InvocationTargetException {
82+
Object object = attributeMethod.invoke(annotation);
83+
84+
if (object instanceof String[]) {
85+
String[] array = (String[]) object;
86+
87+
if (array.length == 0) {
88+
return "";
89+
}
90+
91+
return array[0];
92+
}
93+
94+
if (object instanceof String) {
95+
return (String) object;
96+
}
97+
98+
throw new LiteCommandsReflectException("Attribute " + attributeName + " in annotation " + annotation.annotationType().getSimpleName() + " must return a String");
99+
}
100+
86101
}
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
package dev.rollczi.litecommands.annotations.argument.collection;
1+
package dev.rollczi.litecommands.annotations.varargs;
22

3-
import dev.rollczi.litecommands.annotations.argument.Arg;
43
import dev.rollczi.litecommands.annotations.argument.profile.ProfileAnnotationProcessor;
54
import dev.rollczi.litecommands.argument.Argument;
65
import dev.rollczi.litecommands.argument.resolver.collector.VarargsProfile;
76
import dev.rollczi.litecommands.input.raw.RawCommand;
87
import dev.rollczi.litecommands.reflect.type.TypeToken;
8+
import java.lang.annotation.Annotation;
99
import java.lang.reflect.Parameter;
1010
import java.util.Collection;
1111

12-
public class ArgCollectionArgumentProcessor<SENDER> extends ProfileAnnotationProcessor<SENDER, Arg, VarargsProfile> {
12+
public class VarargsAnyArgumentProcessor<SENDER, A extends Annotation> extends ProfileAnnotationProcessor<SENDER, A, VarargsProfile> {
1313

14-
public ArgCollectionArgumentProcessor() {
15-
super(Arg.class);
14+
public VarargsAnyArgumentProcessor(Class<A> annotationClass) {
15+
super(annotationClass);
1616
}
1717

1818
@Override
19-
protected VarargsProfile createProfile(Parameter parameter, Arg annotation, Argument<?> argument) {
19+
protected VarargsProfile createProfile(Parameter parameter, A annotation, Argument<?> argument) {
2020
TypeToken<?> collectorType = TypeToken.ofParameter(parameter);
2121

2222
if (collectorType.isArray()) {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package dev.rollczi.litecommands.annotations.argument.resolver.collector;import dev.rollczi.litecommands.annotations.argument.Arg;
2+
import dev.rollczi.litecommands.annotations.command.Command;
3+
import dev.rollczi.litecommands.annotations.execute.Execute;
4+
import dev.rollczi.litecommands.annotations.optional.OptionalArg;
5+
import dev.rollczi.litecommands.unit.annotations.LiteTestSpec;
6+
import java.util.List;
7+
import org.junit.jupiter.api.DisplayName;
8+
import org.junit.jupiter.api.Test;
9+
10+
class OptionalCollectionTest extends LiteTestSpec {
11+
12+
@Command(name = "test")
13+
static class OptionalCollectionTestCommand {
14+
@Execute
15+
String test(@OptionalArg List<String> names) {
16+
if (names == null) {
17+
return "null";
18+
}
19+
20+
return String.join(", ", names);
21+
}
22+
}
23+
24+
@Test
25+
@DisplayName("Should always return not null collection")
26+
void testOptionalCollectionExecute() {
27+
platform.execute("test")
28+
.assertSuccess("");
29+
30+
platform.execute("test name1 name2 name3")
31+
.assertSuccess("name1, name2, name3");
32+
}
33+
34+
@Test
35+
void testOptionalCollectionSuggest() {
36+
platform.suggest("test ")
37+
.assertSuggest("<names>");
38+
39+
platform.suggest("test name1 name2 ")
40+
.assertSuggest("<names>");
41+
}
42+
43+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package dev.rollczi.litecommands.annotations.literal;import dev.rollczi.litecommands.annotations.argument.Arg;
2+
import dev.rollczi.litecommands.annotations.command.Command;
3+
import dev.rollczi.litecommands.annotations.execute.Execute;
4+
import dev.rollczi.litecommands.annotations.join.Join;
5+
import dev.rollczi.litecommands.unit.annotations.LiteTestSpec;
6+
import org.junit.jupiter.api.Test;
7+
8+
class LiteralTest extends LiteTestSpec {
9+
10+
@Command(name = "user")
11+
static class LiteralTestCommand {
12+
@Execute
13+
String setGroup(@Arg String name, @Literal("group set") String literal, @Arg String group) {
14+
return name + " " + literal + " " + group;
15+
}
16+
17+
@Execute
18+
String ban(@Arg String name, @Literal("ban") String ban, @Join String reason) {
19+
return name + " " + ban + " " + reason;
20+
}
21+
@Execute
22+
String getName(@Arg String name, @Literal("get name") String literal) {
23+
return name + " " + literal;
24+
}
25+
26+
@Execute
27+
String getUuid(@Arg String name, @Literal("get uuid") String literal) {
28+
return name + " " + literal;
29+
}
30+
31+
}
32+
33+
@Test
34+
void testLiteralExecute() {
35+
platform.execute("user Rollczi group set Admin")
36+
.assertSuccess("Rollczi group set Admin");
37+
38+
platform.execute("user Rollczi get name")
39+
.assertSuccess("Rollczi get name");
40+
41+
platform.execute("user Rollczi get uuid")
42+
.assertSuccess("Rollczi get uuid");
43+
44+
platform.execute("user Rollczi ban test reason")
45+
.assertSuccess("Rollczi ban test reason");
46+
}
47+
48+
@Test
49+
void testLiteralSuggest() {
50+
platform.suggest("user Rollczi ")
51+
.assertSuggest("group set", "get name", "get uuid", "ban");
52+
53+
platform.suggest("user Rollczi group set ")
54+
.assertSuggest("<group>");
55+
56+
platform.suggest("user Rollczi ban ")
57+
.assertSuggest("<reason>");
58+
59+
platform.suggest("user Rollczi get name ")
60+
.assertSuggest();
61+
62+
platform.suggest("user Rollczi get uuid ")
63+
.assertSuggest();
64+
65+
platform.suggest("user Rollczi get ")
66+
.assertSuggest("name", "uuid");
67+
}
68+
69+
}

litecommands-core/src/dev/rollczi/litecommands/argument/profile/ProfileNamespaces.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import dev.rollczi.litecommands.argument.resolver.nullable.NullableProfile;
55
import dev.rollczi.litecommands.flag.FlagProfile;
66
import dev.rollczi.litecommands.join.JoinProfile;
7+
import dev.rollczi.litecommands.literal.LiteralProfile;
78
import dev.rollczi.litecommands.quoted.QuotedProfile;
89
import org.jetbrains.annotations.ApiStatus;
910

@@ -17,6 +18,13 @@ public final class ProfileNamespaces {
1718
private ProfileNamespaces() {
1819
}
1920

21+
/**
22+
* Literal profile allows
23+
* parsing static values such as {@code /user Rollczi group Admin} where {@code group} is a literal.
24+
* @since 3.8.0
25+
*/
26+
public static final ArgumentProfileNamespace<LiteralProfile> LITERAL = LiteralProfile.NAMESPACE;
27+
2028
/**
2129
* Join profile allows joining multiple arguments into one.
2230
* @since 3.7.0

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import dev.rollczi.litecommands.argument.profile.ArgumentProfileNamespace;
55
import dev.rollczi.litecommands.meta.MetaKey;
66
import dev.rollczi.litecommands.meta.MetaType;
7+
import dev.rollczi.litecommands.priority.PriorityLevel;
78
import dev.rollczi.litecommands.reflect.type.TypeToken;
89

910
public class VarargsProfile implements ArgumentProfile<VarargsProfile> {
@@ -32,4 +33,8 @@ public ArgumentProfileNamespace<VarargsProfile> getNamespace() {
3233
return NAMESPACE;
3334
}
3435

36+
@Override
37+
public PriorityLevel getPriority() {
38+
return PriorityLevel.HIGH;
39+
}
3540
}

litecommands-core/src/dev/rollczi/litecommands/literal/Literal.java

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)