Skip to content

Commit 3aa43aa

Browse files
committed
Expression Language Injection (raw impl.)
1 parent aa23718 commit 3aa43aa

File tree

4 files changed

+547
-60
lines changed

4 files changed

+547
-60
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package fr.adrienbrault.idea.symfony2plugin.config.xml;
2+
3+
import com.intellij.lang.injection.MultiHostInjector;
4+
import com.intellij.lang.injection.MultiHostRegistrar;
5+
import com.intellij.patterns.PlatformPatterns;
6+
import com.intellij.patterns.XmlElementPattern;
7+
import com.intellij.patterns.XmlPatterns;
8+
import com.intellij.psi.ElementManipulators;
9+
import com.intellij.psi.PsiElement;
10+
import com.intellij.psi.PsiLanguageInjectionHost;
11+
import com.intellij.psi.xml.XmlText;
12+
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
13+
import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.ExpressionLanguage;
14+
import org.jetbrains.annotations.NotNull;
15+
16+
import java.util.Collections;
17+
import java.util.List;
18+
19+
public class XmlLanguageInjector implements MultiHostInjector {
20+
21+
@Override
22+
public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
23+
if (!Symfony2ProjectComponent.isEnabled(context.getProject())) {
24+
return;
25+
}
26+
27+
if (isExpressionLanguageString(context)) {
28+
registrar
29+
.startInjecting(ExpressionLanguage.INSTANCE)
30+
.addPlace(null, null, (PsiLanguageInjectionHost) context, ElementManipulators.getValueTextRange(context))
31+
.doneInjecting();
32+
}
33+
}
34+
35+
@Override
36+
public @NotNull List<? extends Class<? extends PsiElement>> elementsToInjectIn() {
37+
return Collections.singletonList(XmlText.class);
38+
}
39+
40+
private boolean isExpressionLanguageString(@NotNull PsiElement element) {
41+
return PlatformPatterns.or(
42+
getExpressionArgumentPattern(),
43+
getRouteConditionPattern()
44+
).accepts(element);
45+
}
46+
47+
/**
48+
* <argument type="expression">container.get('service_id')</argument>
49+
*/
50+
private XmlElementPattern.XmlTextPattern getExpressionArgumentPattern() {
51+
return XmlPatterns
52+
.xmlText()
53+
.withParent(XmlPatterns
54+
.xmlTag()
55+
.withName("argument")
56+
.withAttributeValue("type", "expression")
57+
)
58+
.inside(
59+
XmlHelper.getInsideTagPattern("services")
60+
).inFile(XmlHelper.getXmlFilePattern());
61+
}
62+
63+
/**
64+
* <routes ...>
65+
* <route ...>
66+
* <condition>context.getMethod() in ['GET', 'HEAD']</condition>
67+
* </route>
68+
* </routes>
69+
*/
70+
private XmlElementPattern.XmlTextPattern getRouteConditionPattern() {
71+
return XmlPatterns
72+
.xmlText()
73+
.withParent(XmlPatterns
74+
.xmlTag()
75+
.withName("condition")
76+
.withParent(XmlPatterns
77+
.xmlTag()
78+
.withName("route")
79+
.withParent(XmlPatterns
80+
.xmlTag()
81+
.withName("routes")
82+
)
83+
)
84+
)
85+
.inFile(XmlHelper.getXmlFilePattern());
86+
}
87+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package fr.adrienbrault.idea.symfony2plugin.config.yaml;
2+
3+
import com.intellij.lang.injection.MultiHostInjector;
4+
import com.intellij.lang.injection.MultiHostRegistrar;
5+
import com.intellij.openapi.util.TextRange;
6+
import com.intellij.patterns.PlatformPatterns;
7+
import com.intellij.psi.ElementManipulators;
8+
import com.intellij.psi.PsiElement;
9+
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
10+
import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.ExpressionLanguage;
11+
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper;
12+
import org.jetbrains.annotations.NotNull;
13+
import org.jetbrains.yaml.psi.YAMLPsiElement;
14+
import org.jetbrains.yaml.psi.YAMLQuotedText;
15+
16+
import java.util.Collections;
17+
import java.util.List;
18+
19+
public class YamlLanguageInjector implements MultiHostInjector {
20+
21+
private static final String EXPRESSION_LANGUAGE_PREFIX = "@=";
22+
23+
@Override
24+
public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
25+
if (!Symfony2ProjectComponent.isEnabled(context.getProject())) {
26+
return;
27+
}
28+
29+
if (!(context instanceof YAMLQuotedText)) {
30+
return;
31+
}
32+
33+
var file = context.getContainingFile();
34+
var element = (YAMLQuotedText) context;
35+
var value = element.getTextValue();
36+
37+
if (YamlHelper.isServicesFile(file) && isExpressionLanguageString(value) && isExpressionLanguageStringAllowed(element)) {
38+
registrar
39+
.startInjecting(ExpressionLanguage.INSTANCE)
40+
.addPlace(null, null, element, getExpressionLanguageTextRange(value))
41+
.doneInjecting();
42+
} else if (YamlHelper.isRoutingFile(file) && isInsideRouteConditionKey(element)) {
43+
registrar
44+
.startInjecting(ExpressionLanguage.INSTANCE)
45+
.addPlace(null, null, element, ElementManipulators.getValueTextRange(element))
46+
.doneInjecting();
47+
}
48+
}
49+
50+
@NotNull
51+
@Override
52+
public List<? extends Class<? extends PsiElement>> elementsToInjectIn() {
53+
return Collections.singletonList(YAMLQuotedText.class);
54+
}
55+
56+
private boolean isExpressionLanguageString(@NotNull String str) {
57+
return str.startsWith(EXPRESSION_LANGUAGE_PREFIX) && str.length() > EXPRESSION_LANGUAGE_PREFIX.length();
58+
}
59+
60+
private boolean isExpressionLanguageStringAllowed(@NotNull YAMLPsiElement element) {
61+
return PlatformPatterns.and(
62+
YamlElementPatternHelper.getInsideKeyValue("services"),
63+
YamlElementPatternHelper.getInsideKeyValue("arguments", "properties", "calls", "configurator")
64+
).accepts(element);
65+
}
66+
67+
@NotNull
68+
private TextRange getExpressionLanguageTextRange(@NotNull String str) {
69+
return new TextRange(EXPRESSION_LANGUAGE_PREFIX.length() + 1, str.length() + 1);
70+
}
71+
72+
private boolean isInsideRouteConditionKey(@NotNull YAMLPsiElement element) {
73+
return YamlElementPatternHelper.getInsideKeyValue("condition").accepts(element);
74+
}
75+
}

0 commit comments

Comments
 (0)