11package fr .adrienbrault .idea .symfony2plugin .config .yaml ;
22
3+ import com .intellij .openapi .util .TextRange ;
4+ import com .intellij .patterns .PatternCondition ;
35import com .intellij .patterns .PlatformPatterns ;
46import com .intellij .patterns .StandardPatterns ;
57import com .intellij .psi .*;
68import com .intellij .util .ProcessingContext ;
79import fr .adrienbrault .idea .symfony2plugin .Symfony2ProjectComponent ;
810import org .jetbrains .annotations .NotNull ;
9- import org .jetbrains .yaml .psi .YAMLScalar ;
11+ import org .jetbrains .yaml .psi .* ;
1012
1113public class YamlReferenceContributor extends PsiReferenceContributor {
1214 private static final String TAG_PHP_CONST = "!php/const" ;
@@ -26,7 +28,7 @@ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar)
2628 return PsiReference .EMPTY_ARRAY ;
2729 }
2830
29- var scalar = (YAMLScalar )element ;
31+ var scalar = (YAMLScalar ) element ;
3032 if (scalar .getTextValue ().isEmpty ()) {
3133 return PsiReference .EMPTY_ARRAY ;
3234 }
@@ -37,5 +39,245 @@ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar)
3739 }
3840 }
3941 );
42+
43+ // services:
44+ // app.service.foo:
45+ // arguments:
46+ // - '@app.service.bar<caret>'
47+ registrar .registerReferenceProvider (
48+ PlatformPatterns
49+ .psiElement (YAMLScalar .class )
50+ .withParent (
51+ PlatformPatterns
52+ .psiElement (YAMLSequenceItem .class )
53+ .withParent (
54+ PlatformPatterns
55+ .psiElement (YAMLSequence .class )
56+ .withParent (
57+ PlatformPatterns .psiElement (YAMLKeyValue .class ).withName ("arguments" )
58+ )
59+ )
60+ ),
61+ new YAMLScalarServiceReferenceProvider ()
62+ );
63+
64+ // services:
65+ // app.service.foo:
66+ // arguments:
67+ // $bar: '@app.service.bar'
68+
69+ // services:
70+ // app.service.foo:
71+ // properties:
72+ // bar: '@app.service.bar'
73+
74+ registrar .registerReferenceProvider (
75+ PlatformPatterns
76+ .psiElement (YAMLScalar .class )
77+ .withParent (
78+ PlatformPatterns
79+ .psiElement (YAMLKeyValue .class )
80+ .withParent (
81+ PlatformPatterns
82+ .psiElement (YAMLMapping .class )
83+ .withParent (
84+ PlatformPatterns
85+ .psiElement (YAMLKeyValue .class )
86+ .withName ("arguments" , "properties" )
87+ )
88+ )
89+ ),
90+ new YAMLScalarServiceReferenceProvider ()
91+ );
92+
93+ // services:
94+ // app.service.foo:
95+ // alias: app.service.bar
96+
97+ // services:
98+ // app.service.foo_decorator:
99+ // decorates: app.service.foo
100+
101+ // services:
102+ // app.service.foo:
103+ // parent: app.service.foo_parent
104+
105+ registrar .registerReferenceProvider (
106+ PlatformPatterns
107+ .psiElement (YAMLScalar .class )
108+ .withParent (
109+ PlatformPatterns
110+ .psiElement (YAMLKeyValue .class )
111+ .withName ("alias" , "decorates" , "parent" )
112+ ),
113+ new YAMLScalarServiceReferenceProvider (false )
114+ );
115+
116+ // services:
117+ // app.service.foo:
118+ // configurator: @app.service.foo_configurator
119+
120+ // services:
121+ // app.service.foo:
122+ // factory: @app.service.foo_factory
123+
124+ registrar .registerReferenceProvider (
125+ PlatformPatterns
126+ .psiElement (YAMLScalar .class )
127+ .withParent (
128+ PlatformPatterns
129+ .psiElement (YAMLKeyValue .class )
130+ .withName ("configurator" , "factory" )
131+ ),
132+ new YAMLScalarServiceReferenceProvider ()
133+ );
134+
135+ // services:
136+ // app.service.foo:
137+ // factory: ['@app.service.foo_factory', 'create']
138+
139+ // services:
140+ // app.service.foo:
141+ // configurator: ['@app.service.foo_configurator', 'configure']
142+
143+ registrar .registerReferenceProvider (
144+ PlatformPatterns
145+ .psiElement (YAMLScalar .class )
146+ .withParent (
147+ PlatformPatterns
148+ .psiElement (YAMLSequenceItem .class )
149+ .with (new PatternCondition <>("is first sequence item" ) {
150+ @ Override
151+ public boolean accepts (@ NotNull YAMLSequenceItem element , ProcessingContext context ) {
152+ return element .getItemIndex () == 0 ;
153+ }
154+ })
155+ .withParent (
156+ PlatformPatterns
157+ .psiElement (YAMLSequence .class )
158+ .withParent (
159+ PlatformPatterns .psiElement (YAMLKeyValue .class ).withName ("factory" , "configurator" )
160+ )
161+ )
162+ ),
163+ new YAMLScalarServiceReferenceProvider ()
164+ );
165+
166+ // services:
167+ // app.service.foo: '@app.service.bar'
168+ registrar .registerReferenceProvider (
169+ PlatformPatterns
170+ .psiElement (YAMLScalar .class )
171+ .withParent (
172+ PlatformPatterns
173+ .psiElement (YAMLKeyValue .class )
174+ .withParent (
175+ PlatformPatterns
176+ .psiElement (YAMLMapping .class )
177+ .withParent (
178+ PlatformPatterns
179+ .psiElement (YAMLKeyValue .class )
180+ .withName ("services" )
181+ )
182+ )
183+ ),
184+ new YAMLScalarServiceReferenceProvider ()
185+ );
186+
187+ // services:
188+ // app.service.foo:
189+ // calls:
190+ // - setBar: [ '@app.service.bar' ]
191+ registrar .registerReferenceProvider (
192+ PlatformPatterns
193+ .psiElement (YAMLScalar .class )
194+ .withParent (
195+ PlatformPatterns
196+ .psiElement (YAMLSequenceItem .class )
197+ .withParent (
198+ PlatformPatterns
199+ .psiElement (YAMLSequence .class )
200+ .withParent (
201+ PlatformPatterns
202+ .psiElement (YAMLKeyValue .class )
203+ .withParent (
204+ PlatformPatterns
205+ .psiElement (YAMLMapping .class )
206+ .withParent (
207+ PlatformPatterns
208+ .psiElement (YAMLSequenceItem .class )
209+ .withParent (
210+ PlatformPatterns
211+ .psiElement (YAMLSequence .class )
212+ .withParent (
213+ PlatformPatterns
214+ .psiElement (YAMLKeyValue .class )
215+ .withName ("calls" )
216+ )
217+ )
218+ )
219+ )
220+
221+ )
222+ )
223+ ),
224+ new YAMLScalarServiceReferenceProvider ()
225+ );
226+ }
227+
228+ private static class YAMLScalarServiceReferenceProvider extends PsiReferenceProvider {
229+
230+ private static final String PREFIX = "@" ;
231+ private static final String ESCAPED_PREFIX = "@@" ;
232+
233+ /**
234+ * Flag indicating whenever YAMLScalar value start with `@` prefix
235+ */
236+ private boolean isPrefixed = true ;
237+
238+ public YAMLScalarServiceReferenceProvider () {
239+ }
240+
241+ public YAMLScalarServiceReferenceProvider (boolean isPrefixed ) {
242+ this .isPrefixed = isPrefixed ;
243+ }
244+
245+ @ Override
246+ public PsiReference @ NotNull [] getReferencesByElement (@ NotNull PsiElement element , @ NotNull ProcessingContext context ) {
247+ if (!Symfony2ProjectComponent .isEnabled (element )) {
248+ return PsiReference .EMPTY_ARRAY ;
249+ }
250+
251+ if (element instanceof YAMLScalar ) {
252+ var serviceName = ((YAMLScalar ) element ).getTextValue ();
253+ if (serviceName .isEmpty ()) {
254+ return PsiReference .EMPTY_ARRAY ;
255+ }
256+
257+ if (!isPrefixed ) {
258+ return new PsiReference []{
259+ new ServiceYamlReference (element , serviceName )
260+ };
261+ }
262+
263+ if (isValidServiceNameWithPrefix (serviceName )) {
264+ var range = TextRange .from (serviceName .indexOf (PREFIX ) + 1 , serviceName .length () - 1 );
265+ if (element instanceof YAMLQuotedText ) {
266+ // Skip quotes
267+ range = range .shiftRight (1 );
268+ }
269+
270+ return new PsiReference []{
271+ new ServiceYamlReference (element , range , serviceName .substring (1 ))
272+ };
273+ }
274+ }
275+
276+ return PsiReference .EMPTY_ARRAY ;
277+ }
278+
279+ private boolean isValidServiceNameWithPrefix (@ NotNull String serviceName ) {
280+ return serviceName .length () > 1 && serviceName .startsWith (PREFIX ) && !serviceName .startsWith (ESCAPED_PREFIX );
281+ }
40282 }
41283}
0 commit comments