1
1
package dev .rollczi .litecommands .intellijplugin .api .psijava ;
2
2
3
+ import com .intellij .lang .jvm .annotation .JvmAnnotationConstantValue ;
4
+ import com .intellij .psi .PsiAnnotation ;
5
+ import com .intellij .psi .PsiClass ;
3
6
import com .intellij .psi .PsiMethod ;
4
7
import com .intellij .psi .PsiParameter ;
5
8
import dev .rollczi .litecommands .annotations .argument .Arg ;
9
12
import dev .rollczi .litecommands .annotations .literal .Literal ;
10
13
import dev .rollczi .litecommands .annotations .optional .OptionalArg ;
11
14
import dev .rollczi .litecommands .annotations .quoted .Quoted ;
15
+ import dev .rollczi .litecommands .annotations .requirement .RequirementDefinition ;
12
16
import dev .rollczi .litecommands .intellijplugin .api .Argument ;
13
17
import dev .rollczi .litecommands .intellijplugin .api .CommandNode ;
14
18
import dev .rollczi .litecommands .intellijplugin .api .ExecutorNode ;
17
21
import dev .rollczi .litecommands .intellijplugin .util .LiteTypeChecks ;
18
22
import java .util .ArrayList ;
19
23
import java .util .List ;
24
+ import java .util .Objects ;
20
25
import java .util .Optional ;
21
26
import static java .util .Optional .*;
27
+ import java .util .stream .Stream ;
22
28
23
29
public class PsiJavaExecutorNode extends PsiJavaAbstractNode implements ExecutorNode {
24
30
25
-
26
-
27
31
private final static List <ArgumentMapper > ARGUMENTS_MAPPERS = List .of (
28
32
// Array or Collection
29
- (node , parameter ) -> {
33
+ (node , parameter , annotation ) -> {
30
34
if (LiteTypeChecks .isArrayWrapper (parameter .getType (), parameter .getProject ())) {
31
- Optional <Argument > psiJavaArgument = AnnotationFactory .from (Arg .class , parameter ).stream ()
32
- .findFirst ()
35
+ Optional <Argument > psiJavaArgument = AnnotationFactory .from (Arg .class , annotation )
33
36
.map (holder -> new PsiJavaArgument (node , parameter , holder .asAnnotation ().value (), PsiJavaArgument .ARRAY ));
34
37
35
38
if (psiJavaArgument .isPresent ()) {
36
39
return psiJavaArgument ;
37
40
}
38
41
39
- return AnnotationFactory .from (OptionalArg .class , parameter ).stream ()
40
- .findFirst ()
42
+ return AnnotationFactory .from (OptionalArg .class , annotation )
41
43
.map (holder -> new PsiJavaArgument (node , parameter , holder .asAnnotation ().value (), PsiJavaArgument .ARRAY ));
42
44
}
43
45
44
46
return empty ();
45
47
},
46
48
47
49
// Optional wrapper
48
- (node , parameter ) -> {
50
+ (node , parameter , annotation ) -> {
49
51
if (LiteTypeChecks .isOptionalWrapper (parameter .getType ())) {
50
- return AnnotationFactory .from (Arg .class , parameter ).stream ()
51
- .findFirst ()
52
+ return AnnotationFactory .from (Arg .class , annotation )
52
53
.map (holder -> new PsiJavaArgument (node , parameter , holder .asAnnotation ().value (), PsiJavaArgument .OPTIONAL ));
53
54
}
54
55
55
56
return empty ();
56
57
},
57
58
// Optional (nullable)
58
- (node , parameter ) -> AnnotationFactory .from (OptionalArg .class , parameter ).stream ()
59
- .findFirst ()
59
+ (node , parameter , annotation ) -> AnnotationFactory .from (OptionalArg .class , annotation )
60
60
.map (holder -> new PsiJavaArgument (node , parameter , holder .asAnnotation ().value (), PsiJavaArgument .OPTIONAL )),
61
61
62
62
// Quoted
63
- (node , parameter ) -> {
63
+ (node , parameter , annotation ) -> {
64
64
if (parameter .getAnnotation (Quoted .class .getName ()) == null ) {
65
65
return empty ();
66
66
}
67
67
68
- return AnnotationFactory .from (Arg .class , parameter ).stream ()
69
- .findFirst ()
68
+ return AnnotationFactory .from (Arg .class , annotation )
70
69
.map (holder -> new PsiJavaArgument (node , parameter , holder .asAnnotation ().value (), PsiJavaArgument .JOIN ));
71
70
},
72
71
// Joined
73
- (node , parameter ) -> AnnotationFactory .from (Join .class , parameter ).stream ()
74
- .findFirst ()
72
+ (node , parameter , annotation ) -> AnnotationFactory .from (Join .class , annotation )
75
73
.map (holder -> new PsiJavaArgument (node , parameter , holder .asAnnotation ().value (), PsiJavaArgument .JOIN )),
76
74
77
75
// Arg
78
- (node , parameter ) -> AnnotationFactory .from (Arg .class , parameter ).stream ()
79
- .findFirst ()
76
+ (node , parameter , annotation ) -> AnnotationFactory .from (Arg .class , annotation )
80
77
.map (holder -> new PsiJavaArgument (node , parameter , holder .asAnnotation ().value (), PsiJavaArgument .ARG )),
81
78
82
79
// Flag
83
- (node , parameter ) -> AnnotationFactory .from (Flag .class , parameter ).stream ()
84
- .findFirst ()
80
+ (node , parameter , annotation ) -> AnnotationFactory .from (Flag .class , annotation )
85
81
.map (holder -> new PsiJavaArgument (node , parameter , holder .asAnnotation ().value (), PsiJavaArgument .STATIC_VALUE )),
86
82
87
- ( node , parameter ) -> AnnotationFactory . from ( Literal . class , parameter ). stream ()
88
- . findFirst ( )
83
+ // Literal
84
+ ( node , parameter , annotation ) -> AnnotationFactory . from ( Literal . class , annotation )
89
85
.map (holder -> {
90
86
String [] values = holder .asAnnotation ().value ();
91
87
return new PsiJavaArgument (node , parameter , values .length == 0 ? "" : values [0 ], PsiJavaArgument .STATIC_VALUE );
92
- })
88
+ }),
89
+
90
+ // Any
91
+ (node , parameter , annotation ) -> {
92
+ boolean isArray = LiteTypeChecks .isArrayWrapper (parameter .getType (), parameter .getProject ());
93
+ Optional <RequirementDefinition > definition = extractArgumentDefinition (annotation );
94
+ if (definition .isPresent ()) {
95
+ RequirementDefinition requirementDefinition = definition .get ();
96
+ Optional <String > string = extractName (requirementDefinition , annotation );
97
+
98
+ return of (new PsiJavaArgument (node , parameter , string .orElse ("" ), isArray ? PsiJavaArgument .ARRAY : PsiJavaArgument .ARG ));
99
+ }
100
+
101
+ return empty ();
102
+ }
93
103
);
94
104
105
+ private static Optional <String > extractName (RequirementDefinition definition , PsiAnnotation annotation ) {
106
+ return Stream .of (definition .nameProviders ())
107
+ .map (nameProvider -> annotation .findAttribute (nameProvider ))
108
+ .filter (Objects ::nonNull )
109
+ .map (jvmAnnotationAttribute -> jvmAnnotationAttribute .getAttributeValue ())
110
+ .filter (Objects ::nonNull )
111
+ .filter (jvmAnnotationAttributeValue -> jvmAnnotationAttributeValue instanceof JvmAnnotationConstantValue )
112
+ .map (jvmAnnotationAttributeValue -> ((JvmAnnotationConstantValue ) jvmAnnotationAttributeValue ).getConstantValue ())
113
+ .filter (Objects ::nonNull )
114
+ .filter (value -> value instanceof String text && !text .isBlank ())
115
+ .map (value -> (String ) value )
116
+ .findFirst ();
117
+ }
118
+
119
+ private static Optional <RequirementDefinition > extractArgumentDefinition (PsiAnnotation annotation ) {
120
+ PsiClass type = annotation .resolveAnnotationType ();
121
+ if (type == null ) {
122
+ return Optional .empty ();
123
+ }
124
+
125
+ Optional <RequirementDefinition > definition = AnnotationFactory .fromAsAnnotation (RequirementDefinition .class , type );
126
+ if (definition .isEmpty ()) {
127
+ return Optional .empty ();
128
+ }
129
+
130
+ if (definition .get ().type () == RequirementDefinition .Type .ARGUMENT ) {
131
+ return definition ;
132
+ }
133
+
134
+ return Optional .empty ();
135
+ }
136
+
95
137
private final PsiJavaCommandNode parent ;
96
138
private final PsiMethod psiMethod ;
97
139
@@ -111,12 +153,13 @@ public List<Argument> arguments() {
111
153
List <Argument > arguments = new ArrayList <>();
112
154
113
155
for (PsiParameter parameter : psiMethod .getParameterList ().getParameters ()) {
114
- for (ArgumentMapper mapper : ARGUMENTS_MAPPERS ) {
115
- Optional <Argument > optional = mapper .map (this , parameter );
116
-
117
- if (optional .isPresent ()) {
118
- arguments .add (optional .get ());
119
- break ;
156
+ for (PsiAnnotation annotation : parameter .getAnnotations ()) {
157
+ for (ArgumentMapper mapper : ARGUMENTS_MAPPERS ) {
158
+ Optional <Argument > optional = mapper .map (this , parameter , annotation );
159
+ if (optional .isPresent ()) {
160
+ arguments .add (optional .get ());
161
+ break ;
162
+ }
120
163
}
121
164
}
122
165
}
@@ -130,7 +173,7 @@ public NavigatableReference navigatable() {
130
173
}
131
174
132
175
interface ArgumentMapper {
133
- Optional <Argument > map (PsiJavaExecutorNode node , PsiParameter parameter );
176
+ Optional <Argument > map (PsiJavaExecutorNode node , PsiParameter parameter , PsiAnnotation annotation );
134
177
}
135
178
136
179
}
0 commit comments