Skip to content

Commit 6de39f8

Browse files
committed
support Twig lexer changes in PhpStorm 2017.3.2 #1123 #1125
1 parent f5b4780 commit 6de39f8

11 files changed

+65
-60
lines changed

.travis.yml

+2-3
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@ before_script:
1313
- chmod +x travis.sh
1414

1515
env:
16-
- PHPSTORM_ENV=2017.2
17-
- PHPSTORM_ENV=2017.2.4
16+
#- PHPSTORM_ENV=2017.2 # unsupported api
17+
#- PHPSTORM_ENV=2017.2.4 # unsupported api
1818
- PHPSTORM_ENV=2017.3.2
1919
#- PHPSTORM_ENV=eap # disabled never used
2020

2121
matrix:
2222
allow_failures:
2323
- env: PHPSTORM_ENV=eap
24-
- env: PHPSTORM_ENV=2017.3.2

src/fr/adrienbrault/idea/symfony2plugin/templating/BlockGotoCompletionRegistrar.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
public class BlockGotoCompletionRegistrar implements GotoCompletionRegistrar {
2424
public void register(@NotNull GotoCompletionRegistrarParameter registrar) {
2525
// {{ block('foo_block') }}
26-
registrar.register(TwigPattern.getPrintBlockFunctionPattern("block"), psiElement -> {
26+
registrar.register(TwigPattern.getPrintBlockOrTagFunctionPattern("block"), psiElement -> {
2727
if (!Symfony2ProjectComponent.isEnabled(psiElement)) {
2828
return null;
2929
}

src/fr/adrienbrault/idea/symfony2plugin/templating/TwigLineMarkerProvider.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public void collectSlowLineMarkers(@NotNull List<PsiElement> psiElements, @NotNu
6969
if(overwrites != null) {
7070
results.add(overwrites);
7171
}
72-
} else if (TwigPattern.getBlockTagPattern().accepts(psiElement) || TwigPattern.getPrintBlockFunctionPattern("block").accepts(psiElement)) {
72+
} else if (TwigPattern.getBlockTagPattern().accepts(psiElement) || TwigPattern.getPrintBlockOrTagFunctionPattern("block").accepts(psiElement)) {
7373
// blocks: {% block 'foobar' %}, {{ block('foobar') }}
7474

7575
VirtualFile virtualFile = psiElement.getContainingFile().getVirtualFile();

src/fr/adrienbrault/idea/symfony2plugin/templating/TwigPattern.java

+13-27
Original file line numberDiff line numberDiff line change
@@ -93,31 +93,6 @@ public static ElementPattern<PsiElement> getTranslationTokenTagFromPattern() {
9393
);
9494
}
9595

96-
/**
97-
* Check for {{ include('|') }}
98-
*
99-
* @param functionName twig function name
100-
*/
101-
public static ElementPattern<PsiElement> getPrintBlockFunctionPattern(String... functionName) {
102-
//noinspection unchecked
103-
return PlatformPatterns
104-
.psiElement(TwigTokenTypes.STRING_TEXT)
105-
.withParent(
106-
PlatformPatterns.psiElement(TwigElementTypes.PRINT_BLOCK)
107-
)
108-
.afterLeafSkipping(
109-
PlatformPatterns.or(
110-
PlatformPatterns.psiElement(TwigTokenTypes.LBRACE),
111-
PlatformPatterns.psiElement(PsiWhiteSpace.class),
112-
PlatformPatterns.psiElement(TwigTokenTypes.WHITE_SPACE),
113-
PlatformPatterns.psiElement(TwigTokenTypes.SINGLE_QUOTE),
114-
PlatformPatterns.psiElement(TwigTokenTypes.DOUBLE_QUOTE)
115-
),
116-
PlatformPatterns.psiElement(TwigTokenTypes.IDENTIFIER).withText(PlatformPatterns.string().oneOf(functionName))
117-
)
118-
.withLanguage(TwigLanguage.INSTANCE);
119-
}
120-
12196
/**
12297
* {% include ['', ~ '', ''] %}
12398
*/
@@ -184,12 +159,18 @@ public static ElementPattern<PsiElement> getPrintBlockOrTagFunctionPattern(Strin
184159
.psiElement(TwigTokenTypes.STRING_TEXT)
185160
.withParent(
186161
PlatformPatterns.or(
162+
163+
// old and inconsistently implementations of FUNCTION_CALL:
164+
// eg {% if asset('') %} does not provide a FUNCTION_CALL whereas a print block does
187165
PlatformPatterns.psiElement(TwigElementTypes.PRINT_BLOCK),
188166
PlatformPatterns.psiElement(TwigElementTypes.TAG),
189167
PlatformPatterns.psiElement(TwigElementTypes.IF_TAG),
190168
PlatformPatterns.psiElement(TwigElementTypes.SET_TAG),
191169
PlatformPatterns.psiElement(TwigElementTypes.ELSE_TAG),
192-
PlatformPatterns.psiElement(TwigElementTypes.ELSEIF_TAG)
170+
PlatformPatterns.psiElement(TwigElementTypes.ELSEIF_TAG),
171+
172+
// PhpStorm 2017.3.2: {{ asset('') }}
173+
PlatformPatterns.psiElement(TwigElementTypes.FUNCTION_CALL)
193174
)
194175
)
195176
.afterLeafSkipping(
@@ -587,7 +568,12 @@ public static ElementPattern<PsiElement> getEmbedPattern() {
587568
}
588569

589570
public static ElementPattern<PsiElement> getPrintBlockFunctionPattern() {
590-
return PlatformPatterns.psiElement().withParent(PlatformPatterns.psiElement(TwigElementTypes.PRINT_BLOCK)).withLanguage(TwigLanguage.INSTANCE);
571+
return PlatformPatterns.psiElement().withParent(PlatformPatterns.or(
572+
PlatformPatterns.psiElement(TwigElementTypes.PRINT_BLOCK),
573+
574+
// PhpStorm 2017.3.2
575+
PlatformPatterns.psiElement(TwigElementTypes.FUNCTION_CALL)
576+
)).withLanguage(TwigLanguage.INSTANCE);
591577
}
592578

593579
/**

src/fr/adrienbrault/idea/symfony2plugin/templating/TwigTemplateCompletionContributor.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public TwigTemplateCompletionContributor() {
6767

6868
// all file template "include" pattern
6969
extend(CompletionType.BASIC, PlatformPatterns.or(
70-
TwigPattern.getPrintBlockFunctionPattern("include", "source"),
70+
TwigPattern.getPrintBlockOrTagFunctionPattern("include", "source"),
7171
TwigPattern.getIncludeTagArrayPattern(),
7272
TwigPattern.getTagTernaryPattern(TwigElementTypes.INCLUDE_TAG)
7373
), new TemplateCompletionProvider());

src/fr/adrienbrault/idea/symfony2plugin/templating/TwigTemplateGoToDeclarationHandler.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public PsiElement[] getGotoDeclarationTargets(PsiElement psiElement, int offset,
6363
targets.addAll(getRouteParameterGoTo(psiElement));
6464
}
6565

66-
if(TwigPattern.getTemplateFileReferenceTagPattern().accepts(psiElement) || TwigPattern.getPrintBlockFunctionPattern("include", "source").accepts(psiElement)) {
66+
if(TwigPattern.getTemplateFileReferenceTagPattern().accepts(psiElement) || TwigPattern.getPrintBlockOrTagFunctionPattern("include", "source").accepts(psiElement)) {
6767
// support: {% include() %}, {{ include() }}
6868
targets.addAll(getTwigFiles(psiElement, offset));
6969
} else if (PlatformPatterns.psiElement(TwigTokenTypes.STRING_TEXT).withText(PlatformPatterns.string().endsWith(".twig")).accepts(psiElement)) {
@@ -140,7 +140,9 @@ public PsiElement[] getGotoDeclarationTargets(PsiElement psiElement, int offset,
140140
.psiElement(TwigTokenTypes.IDENTIFIER)
141141
.withParent(PlatformPatterns.or(
142142
PlatformPatterns.psiElement(TwigElementTypes.PRINT_BLOCK),
143-
PlatformPatterns.psiElement(TwigElementTypes.SET_TAG)
143+
PlatformPatterns.psiElement(TwigElementTypes.SET_TAG),
144+
145+
PlatformPatterns.psiElement(TwigElementTypes.FUNCTION_CALL)
144146
)).withLanguage(TwigLanguage.INSTANCE).accepts(psiElement)) {
145147

146148
targets.addAll(this.getFunctions(psiElement));

src/fr/adrienbrault/idea/symfony2plugin/templating/inspection/TwigTemplateMissingInspection.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public PsiElementVisitor buildVisitor(final @NotNull ProblemsHolder holder, bool
3131
return new PsiElementVisitor() {
3232
@Override
3333
public void visitElement(PsiElement element) {
34-
if((TwigPattern.getTemplateFileReferenceTagPattern().accepts(element) || TwigPattern.getPrintBlockFunctionPattern("include", "source").accepts(element)) && TwigUtil.isValidStringWithoutInterpolatedOrConcat(element)) {
34+
if((TwigPattern.getTemplateFileReferenceTagPattern().accepts(element) || TwigPattern.getPrintBlockOrTagFunctionPattern("include", "source").accepts(element)) && TwigUtil.isValidStringWithoutInterpolatedOrConcat(element)) {
3535
invoke(element, holder);
3636
}
3737

src/fr/adrienbrault/idea/symfony2plugin/templating/util/TwigUtil.java

+36-20
Original file line numberDiff line numberDiff line change
@@ -233,14 +233,17 @@ public static Map<String, Collection<PsiElement>> getTemplateAnnotationFilesWith
233233
public static String getTransDefaultDomainOnScope(@NotNull PsiElement position) {
234234
// {% embed 'foo.html.twig' with { foo: '<caret>'|trans } %}
235235
PsiElement parent = position.getParent();
236-
if(parent != null && parent.getNode().getElementType() == TwigElementTypes.EMBED_TAG) {
237-
PsiElement firstParent = PsiTreeUtil.findFirstParent(position, true, psiElement -> {
238-
IElementType elementType = psiElement.getNode().getElementType();
239-
return elementType != TwigElementTypes.EMBED_TAG && elementType != TwigElementTypes.EMBED_STATEMENT;
240-
});
236+
if(parent != null && parent.getNode().getElementType() == TwigElementTypes.LITERAL) {
237+
PsiElement parent2 = parent.getParent();
238+
if(parent2 != null && parent2.getNode().getElementType() == TwigElementTypes.EMBED_TAG) {
239+
PsiElement firstParent = PsiTreeUtil.findFirstParent(parent, true, psiElement -> {
240+
IElementType elementType = psiElement.getNode().getElementType();
241+
return elementType != TwigElementTypes.EMBED_TAG && elementType != TwigElementTypes.EMBED_STATEMENT;
242+
});
241243

242-
if(firstParent != null) {
243-
position = firstParent;
244+
if(firstParent != null) {
245+
position = firstParent;
246+
}
244247
}
245248
}
246249

@@ -1556,23 +1559,27 @@ public static Collection<String> getIncludeTagStrings(@NotNull TwigTagWithFileRe
15561559

15571560
/**
15581561
* Visit string values of given array start brace
1559-
* ["foobar"]
1562+
*
1563+
* ["foobar", "foobar"]
1564+
* {"foobar", "foobar"}
15601565
*/
1561-
public static void visitStringInArray(@NotNull PsiElement arrayStartBrace, @NotNull Consumer<Pair<String, PsiElement>> pair) {
1566+
private static void visitStringInArray(@NotNull PsiElement arrayStartBrace, @NotNull Consumer<Pair<String, PsiElement>> pair) {
15621567
// match: "([,)''(,])"
15631568
Collection<PsiElement> questString = PsiElementUtils.getNextSiblingOfTypes(arrayStartBrace, PlatformPatterns.psiElement(TwigTokenTypes.STRING_TEXT)
15641569
.afterLeafSkipping(
15651570
TwigPattern.STRING_WRAP_PATTERN,
15661571
PlatformPatterns.or(
15671572
PlatformPatterns.psiElement(TwigTokenTypes.COMMA),
1568-
PlatformPatterns.psiElement(TwigTokenTypes.LBRACE_SQ)
1569-
)
1573+
PlatformPatterns.psiElement(TwigTokenTypes.LBRACE_SQ),
1574+
PlatformPatterns.psiElement(TwigTokenTypes.LBRACE_CURL)
1575+
)
15701576
)
15711577
.beforeLeafSkipping(
15721578
TwigPattern.STRING_WRAP_PATTERN,
15731579
PlatformPatterns.or(
15741580
PlatformPatterns.psiElement(TwigTokenTypes.COMMA),
1575-
PlatformPatterns.psiElement(TwigTokenTypes.RBRACE_SQ)
1581+
PlatformPatterns.psiElement(TwigTokenTypes.RBRACE_SQ),
1582+
PlatformPatterns.psiElement(TwigTokenTypes.RBRACE_CURL)
15761583
)
15771584
)
15781585
);
@@ -1620,7 +1627,7 @@ public void visitElement(PsiElement element) {
16201627
psiElement.acceptChildren(new PsiRecursiveElementVisitor() {
16211628
@Override
16221629
public void visitElement(PsiElement element) {
1623-
if(target[0] == null && TwigPattern.getPrintBlockFunctionPattern("block").accepts(element)) {
1630+
if(target[0] == null && TwigPattern.getPrintBlockOrTagFunctionPattern("block").accepts(element)) {
16241631
target[0] = element;
16251632
}
16261633
super.visitElement(element);
@@ -2213,7 +2220,12 @@ public static void visitTemplateIncludes(@NotNull TwigFile twigFile, @NotNull Co
22132220
visitTemplateIncludes(
22142221
twigFile,
22152222
consumer,
2216-
TemplateInclude.TYPE.EMBED, TemplateInclude.TYPE.INCLUDE, TemplateInclude.TYPE.INCLUDE_FUNCTION, TemplateInclude.TYPE.FROM, TemplateInclude.TYPE.IMPORT, TemplateInclude.TYPE.FORM_THEME
2223+
TemplateInclude.TYPE.EMBED,
2224+
TemplateInclude.TYPE.INCLUDE,
2225+
TemplateInclude.TYPE.INCLUDE_FUNCTION,
2226+
TemplateInclude.TYPE.FROM,
2227+
TemplateInclude.TYPE.IMPORT,
2228+
TemplateInclude.TYPE.FORM_THEME
22172229
);
22182230
}
22192231

@@ -2262,7 +2274,7 @@ private static void visitTemplateIncludes(@NotNull TwigFile twigFile, @NotNull C
22622274
// {{ include() }}
22632275
// {{ source() }}
22642276
if(myTypes.contains(TemplateInclude.TYPE.INCLUDE_FUNCTION)) {
2265-
PsiElement includeTag = PsiElementUtils.getChildrenOfType(psiElement, TwigPattern.getPrintBlockFunctionPattern("include", "source"));
2277+
PsiElement includeTag = PsiElementUtils.getChildrenOfType(psiElement, TwigPattern.getPrintBlockOrTagFunctionPattern("include", "source"));
22662278
if(includeTag != null) {
22672279
String templateName = includeTag.getText();
22682280
if(StringUtils.isNotBlank(templateName)) {
@@ -2299,17 +2311,21 @@ private static void visitTemplateIncludes(@NotNull TwigFile twigFile, @NotNull C
22992311
}
23002312
}
23012313

2302-
// {% form_theme form.child 'form/fields_child.html.twig' %}
2314+
// {% form_theme form.child with ['form/fields_child.html.twig'] %}
23032315
PsiElement withElement = PsiElementUtils.getNextSiblingOfType(tagElement, PlatformPatterns.psiElement().withElementType(TwigTokenTypes.IDENTIFIER).withText("with"));
23042316
if(withElement != null) {
2305-
PsiElement arrayStart = PsiElementUtils.getNextSiblingAndSkip(tagElement, TwigTokenTypes.LBRACE_SQ,
2317+
// find LITERAL "[", "{"
2318+
PsiElement arrayStart = PsiElementUtils.getNextSiblingAndSkip(tagElement, TwigElementTypes.LITERAL,
23062319
TwigTokenTypes.IDENTIFIER, TwigTokenTypes.SINGLE_QUOTE, TwigTokenTypes.DOUBLE_QUOTE, TwigTokenTypes.DOT
23072320
);
23082321

23092322
if(arrayStart != null) {
2310-
visitStringInArray(arrayStart, pair ->
2311-
consumer.consume(new TemplateInclude(psiElement, pair.getFirst(), TemplateInclude.TYPE.FORM_THEME))
2312-
);
2323+
PsiElement firstChild = arrayStart.getFirstChild();
2324+
if(firstChild != null) {
2325+
visitStringInArray(firstChild, pair ->
2326+
consumer.consume(new TemplateInclude(psiElement, pair.getFirst(), TemplateInclude.TYPE.FORM_THEME))
2327+
);
2328+
}
23132329
}
23142330
}
23152331
}

src/fr/adrienbrault/idea/symfony2plugin/templating/variable/collector/IncludeVariableCollector.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ public void visitElement(PsiElement element) {
208208

209209
if(element instanceof TwigCompositeElement) {
210210
// {{ include('template.html') }}
211-
PsiElement includeTag = PsiElementUtils.getChildrenOfType(element, TwigPattern.getPrintBlockFunctionPattern("include"));
211+
PsiElement includeTag = PsiElementUtils.getChildrenOfType(element, TwigPattern.getPrintBlockOrTagFunctionPattern("include"));
212212
if(includeTag != null) {
213213
collectContextVars(TwigTokenTypes.IDENTIFIER, element, includeTag);
214214
}

tests/fr/adrienbrault/idea/symfony2plugin/tests/templating/TwigTemplateCompletionContributorTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ public void testThatConstantProvidesCompletionForClassAndDefine() {
8383
}
8484

8585
public void testCompletionForRoutingParameter() {
86-
assertCompletionContains(TwigFileType.INSTANCE, "{{ path('xml_route', {'<caret>']) }}", "slug");
87-
assertNavigationMatch(TwigFileType.INSTANCE, "{{ path('xml_route', {'sl<caret>ug']) }}", PlatformPatterns.psiElement());
86+
assertCompletionContains(TwigFileType.INSTANCE, "{{ path('xml_route', {'<caret>'}) }}", "slug");
87+
assertNavigationMatch(TwigFileType.INSTANCE, "{{ path('xml_route', {'sl<caret>ug'}) }}", PlatformPatterns.psiElement());
8888
}
8989

9090
public void testInsertHandlerForTwigFunctionWithStringParameter() {

tests/fr/adrienbrault/idea/symfony2plugin/tests/templating/util/TwigUtilTest.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -274,14 +274,16 @@ public void testVisitTemplateIncludes() {
274274
PsiFile fileFromText = PsiFileFactory.getInstance(getProject()).createFileFromText(TwigLanguage.INSTANCE,
275275
"{% form_theme form ':Foobar:fields.html.twig' %}" +
276276
"{% form_theme form.foobar \":Foobar:fields_foobar.html.twig\" %}" +
277-
"{% form_theme form.foobar with [\":Foobar:fields_foobar_1.html.twig\"] %}"
277+
"{% form_theme form.foobar with [\":Foobar:fields_foobar_1.html.twig\"] %}" +
278+
"{% form_theme form.foobar with {\":Foobar:fields_foobar_2.html.twig\", \":Foobar:fields_foobar_3.html.twig\", \":Foobar:fields_foobar_4.html.twig\"} %}"
278279
);
279280

280281
TwigUtil.visitTemplateIncludes((TwigFile) fileFromText, templateInclude ->
281282
includes.add(templateInclude.getTemplateName())
282283
);
283284

284285
assertContainsElements(includes, ":Foobar:fields.html.twig", ":Foobar:fields_foobar.html.twig", ":Foobar:fields_foobar_1.html.twig");
286+
assertContainsElements(includes, ":Foobar:fields_foobar_2.html.twig", ":Foobar:fields_foobar_3.html.twig", ":Foobar:fields_foobar_4.html.twig");
285287
}
286288

287289
/**

0 commit comments

Comments
 (0)