Skip to content

Commit

Permalink
support Twig lexer changes in PhpStorm 2017.3.2 #1123 #1125
Browse files Browse the repository at this point in the history
  • Loading branch information
Haehnchen committed Dec 26, 2017
1 parent d8b679c commit dbcbe62
Show file tree
Hide file tree
Showing 17 changed files with 106 additions and 72 deletions.
5 changes: 2 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@ before_script:
- chmod +x travis.sh

env:
- PHPSTORM_ENV=2017.2
- PHPSTORM_ENV=2017.2.4
#- PHPSTORM_ENV=2017.2 # unsupported api
#- PHPSTORM_ENV=2017.2.4 # unsupported api
- PHPSTORM_ENV=2017.3.2
#- PHPSTORM_ENV=eap # disabled never used

matrix:
allow_failures:
- env: PHPSTORM_ENV=eap
- env: PHPSTORM_ENV=2017.3.2
4 changes: 2 additions & 2 deletions META-INF/plugin.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<idea-plugin url="https://github.com/Haehnchen/idea-php-symfony2-plugin">
<id>fr.adrienbrault.idea.symfony2plugin</id>
<name>Symfony Plugin</name>
<version>0.15.163</version>
<version>0.16.163</version>
<vendor email="daniel@espendiller.net" url="http://espend.de">Daniel Espendiller</vendor>

<description><![CDATA[
Expand Down Expand Up @@ -115,7 +115,7 @@
</change-notes>

<!-- please see http://confluence.jetbrains.net/display/IDEADEV/Build+Number+Ranges for description -->
<idea-version since-build="172.3317"/>
<idea-version since-build="173.4127"/>

<extensions defaultExtensionNs="com.jetbrains.php">
<typeProvider3 implementation="fr.adrienbrault.idea.symfony2plugin.dic.SymfonyContainerTypeProvider"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
public class BlockGotoCompletionRegistrar implements GotoCompletionRegistrar {
public void register(@NotNull GotoCompletionRegistrarParameter registrar) {
// {{ block('foo_block') }}
registrar.register(TwigPattern.getPrintBlockFunctionPattern("block"), psiElement -> {
registrar.register(TwigPattern.getPrintBlockOrTagFunctionPattern("block"), psiElement -> {
if (!Symfony2ProjectComponent.isEnabled(psiElement)) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void collectSlowLineMarkers(@NotNull List<PsiElement> psiElements, @NotNu
if(overwrites != null) {
results.add(overwrites);
}
} else if (TwigPattern.getBlockTagPattern().accepts(psiElement) || TwigPattern.getPrintBlockFunctionPattern("block").accepts(psiElement)) {
} else if (TwigPattern.getBlockTagPattern().accepts(psiElement) || TwigPattern.getPrintBlockOrTagFunctionPattern("block").accepts(psiElement)) {
// blocks: {% block 'foobar' %}, {{ block('foobar') }}

VirtualFile virtualFile = psiElement.getContainingFile().getVirtualFile();
Expand Down Expand Up @@ -240,7 +240,7 @@ protected Collection<? extends PsiElement> compute() {
}

@Nullable
private LineMarkerInfo attachBlockOverwrites(PsiElement psiElement, @NotNull FileOverwritesLazyLoader loader) {
private LineMarkerInfo attachBlockOverwrites(@NotNull PsiElement psiElement, @NotNull FileOverwritesLazyLoader loader) {
if(!TwigBlockUtil.hasBlockOverwrites(psiElement, loader)) {
return null;
}
Expand Down
50 changes: 22 additions & 28 deletions src/fr/adrienbrault/idea/symfony2plugin/templating/TwigPattern.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,31 +93,6 @@ public static ElementPattern<PsiElement> getTranslationTokenTagFromPattern() {
);
}

/**
* Check for {{ include('|') }}
*
* @param functionName twig function name
*/
public static ElementPattern<PsiElement> getPrintBlockFunctionPattern(String... functionName) {
//noinspection unchecked
return PlatformPatterns
.psiElement(TwigTokenTypes.STRING_TEXT)
.withParent(
PlatformPatterns.psiElement(TwigElementTypes.PRINT_BLOCK)
)
.afterLeafSkipping(
PlatformPatterns.or(
PlatformPatterns.psiElement(TwigTokenTypes.LBRACE),
PlatformPatterns.psiElement(PsiWhiteSpace.class),
PlatformPatterns.psiElement(TwigTokenTypes.WHITE_SPACE),
PlatformPatterns.psiElement(TwigTokenTypes.SINGLE_QUOTE),
PlatformPatterns.psiElement(TwigTokenTypes.DOUBLE_QUOTE)
),
PlatformPatterns.psiElement(TwigTokenTypes.IDENTIFIER).withText(PlatformPatterns.string().oneOf(functionName))
)
.withLanguage(TwigLanguage.INSTANCE);
}

/**
* {% include ['', ~ '', ''] %}
*/
Expand Down Expand Up @@ -184,12 +159,18 @@ public static ElementPattern<PsiElement> getPrintBlockOrTagFunctionPattern(Strin
.psiElement(TwigTokenTypes.STRING_TEXT)
.withParent(
PlatformPatterns.or(

// old and inconsistently implementations of FUNCTION_CALL:
// eg {% if asset('') %} does not provide a FUNCTION_CALL whereas a print block does
PlatformPatterns.psiElement(TwigElementTypes.PRINT_BLOCK),
PlatformPatterns.psiElement(TwigElementTypes.TAG),
PlatformPatterns.psiElement(TwigElementTypes.IF_TAG),
PlatformPatterns.psiElement(TwigElementTypes.SET_TAG),
PlatformPatterns.psiElement(TwigElementTypes.ELSE_TAG),
PlatformPatterns.psiElement(TwigElementTypes.ELSEIF_TAG)
PlatformPatterns.psiElement(TwigElementTypes.ELSEIF_TAG),

// PhpStorm 2017.3.2: {{ asset('') }}
PlatformPatterns.psiElement(TwigElementTypes.FUNCTION_CALL)
)
)
.afterLeafSkipping(
Expand Down Expand Up @@ -587,7 +568,12 @@ public static ElementPattern<PsiElement> getEmbedPattern() {
}

public static ElementPattern<PsiElement> getPrintBlockFunctionPattern() {
return PlatformPatterns.psiElement().withParent(PlatformPatterns.psiElement(TwigElementTypes.PRINT_BLOCK)).withLanguage(TwigLanguage.INSTANCE);
return PlatformPatterns.psiElement().withParent(PlatformPatterns.or(
PlatformPatterns.psiElement(TwigElementTypes.PRINT_BLOCK),

// PhpStorm 2017.3.2
PlatformPatterns.psiElement(TwigElementTypes.FUNCTION_CALL)
)).withLanguage(TwigLanguage.INSTANCE);
}

/**
Expand Down Expand Up @@ -951,7 +937,15 @@ public static ElementPattern<PsiElement> getAutocompletableAssetPattern() {
;
}

public static ElementPattern<PsiElement> getTranslationPattern(String... type) {
/**
* Pattern to match given string before "filter" with given function name
*
* {{ 'foo<caret>bar'|trans }}
* {{ 'foo<caret>bar'|trans() }}
* {{ 'foo<caret>bar'|transchoice() }}
*/
@NotNull
public static ElementPattern<PsiElement> getTranslationKeyPattern(@NotNull String... type) {
//noinspection unchecked
return
PlatformPatterns
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public TwigTemplateCompletionContributor() {

// all file template "include" pattern
extend(CompletionType.BASIC, PlatformPatterns.or(
TwigPattern.getPrintBlockFunctionPattern("include", "source"),
TwigPattern.getPrintBlockOrTagFunctionPattern("include", "source"),
TwigPattern.getIncludeTagArrayPattern(),
TwigPattern.getTagTernaryPattern(TwigElementTypes.INCLUDE_TAG)
), new TemplateCompletionProvider());
Expand All @@ -76,7 +76,7 @@ public TwigTemplateCompletionContributor() {
// provides support for 'a<xxx>'|transchoice(2, {'%foo%' : bar|default}, 'Domain')
extend(
CompletionType.BASIC,
TwigPattern.getTranslationPattern("trans", "transchoice"),
TwigPattern.getTranslationKeyPattern("trans", "transchoice"),
new CompletionProvider<CompletionParameters>() {
public void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet resultSet) {
if(!Symfony2ProjectComponent.isEnabled(parameters.getPosition())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public PsiElement[] getGotoDeclarationTargets(PsiElement psiElement, int offset,
targets.addAll(getRouteParameterGoTo(psiElement));
}

if(TwigPattern.getTemplateFileReferenceTagPattern().accepts(psiElement) || TwigPattern.getPrintBlockFunctionPattern("include", "source").accepts(psiElement)) {
if(TwigPattern.getTemplateFileReferenceTagPattern().accepts(psiElement) || TwigPattern.getPrintBlockOrTagFunctionPattern("include", "source").accepts(psiElement)) {
// support: {% include() %}, {{ include() }}
targets.addAll(getTwigFiles(psiElement, offset));
} else if (PlatformPatterns.psiElement(TwigTokenTypes.STRING_TEXT).withText(PlatformPatterns.string().endsWith(".twig")).accepts(psiElement)) {
Expand Down Expand Up @@ -91,7 +91,7 @@ public PsiElement[] getGotoDeclarationTargets(PsiElement psiElement, int offset,
targets.addAll(getTranslationDomainGoto(psiElement));
}

if (TwigPattern.getTranslationPattern("trans", "transchoice").accepts(psiElement)) {
if (TwigPattern.getTranslationKeyPattern("trans", "transchoice").accepts(psiElement)) {
targets.addAll(getTranslationKeyGoTo(psiElement));
}

Expand Down Expand Up @@ -140,7 +140,9 @@ public PsiElement[] getGotoDeclarationTargets(PsiElement psiElement, int offset,
.psiElement(TwigTokenTypes.IDENTIFIER)
.withParent(PlatformPatterns.or(
PlatformPatterns.psiElement(TwigElementTypes.PRINT_BLOCK),
PlatformPatterns.psiElement(TwigElementTypes.SET_TAG)
PlatformPatterns.psiElement(TwigElementTypes.SET_TAG),

PlatformPatterns.psiElement(TwigElementTypes.FUNCTION_CALL)
)).withLanguage(TwigLanguage.INSTANCE).accepts(psiElement)) {

targets.addAll(this.getFunctions(psiElement));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public PsiElementVisitor buildVisitor(final @NotNull ProblemsHolder holder, bool
return new PsiElementVisitor() {
@Override
public void visitElement(PsiElement element) {
if((TwigPattern.getTemplateFileReferenceTagPattern().accepts(element) || TwigPattern.getPrintBlockFunctionPattern("include", "source").accepts(element)) && TwigUtil.isValidStringWithoutInterpolatedOrConcat(element)) {
if((TwigPattern.getTemplateFileReferenceTagPattern().accepts(element) || TwigPattern.getPrintBlockOrTagFunctionPattern("include", "source").accepts(element)) && TwigUtil.isValidStringWithoutInterpolatedOrConcat(element)) {
invoke(element, holder);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,14 +233,17 @@ public static Map<String, Collection<PsiElement>> getTemplateAnnotationFilesWith
public static String getTransDefaultDomainOnScope(@NotNull PsiElement position) {
// {% embed 'foo.html.twig' with { foo: '<caret>'|trans } %}
PsiElement parent = position.getParent();
if(parent != null && parent.getNode().getElementType() == TwigElementTypes.EMBED_TAG) {
PsiElement firstParent = PsiTreeUtil.findFirstParent(position, true, psiElement -> {
IElementType elementType = psiElement.getNode().getElementType();
return elementType != TwigElementTypes.EMBED_TAG && elementType != TwigElementTypes.EMBED_STATEMENT;
});
if(parent != null && parent.getNode().getElementType() == TwigElementTypes.LITERAL) {
PsiElement parent2 = parent.getParent();
if(parent2 != null && parent2.getNode().getElementType() == TwigElementTypes.EMBED_TAG) {
PsiElement firstParent = PsiTreeUtil.findFirstParent(parent, true, psiElement -> {
IElementType elementType = psiElement.getNode().getElementType();
return elementType != TwigElementTypes.EMBED_TAG && elementType != TwigElementTypes.EMBED_STATEMENT;
});

if(firstParent != null) {
position = firstParent;
if(firstParent != null) {
position = firstParent;
}
}
}

Expand Down Expand Up @@ -1555,23 +1558,27 @@ public static Collection<String> getIncludeTagStrings(@NotNull TwigTagWithFileRe

/**
* Visit string values of given array start brace
* ["foobar"]
*
* ["foobar", "foobar"]
* {"foobar", "foobar"}
*/
public static void visitStringInArray(@NotNull PsiElement arrayStartBrace, @NotNull Consumer<Pair<String, PsiElement>> pair) {
private static void visitStringInArray(@NotNull PsiElement arrayStartBrace, @NotNull Consumer<Pair<String, PsiElement>> pair) {
// match: "([,)''(,])"
Collection<PsiElement> questString = PsiElementUtils.getNextSiblingOfTypes(arrayStartBrace, PlatformPatterns.psiElement(TwigTokenTypes.STRING_TEXT)
.afterLeafSkipping(
TwigPattern.STRING_WRAP_PATTERN,
PlatformPatterns.or(
PlatformPatterns.psiElement(TwigTokenTypes.COMMA),
PlatformPatterns.psiElement(TwigTokenTypes.LBRACE_SQ)
)
PlatformPatterns.psiElement(TwigTokenTypes.LBRACE_SQ),
PlatformPatterns.psiElement(TwigTokenTypes.LBRACE_CURL)
)
)
.beforeLeafSkipping(
TwigPattern.STRING_WRAP_PATTERN,
PlatformPatterns.or(
PlatformPatterns.psiElement(TwigTokenTypes.COMMA),
PlatformPatterns.psiElement(TwigTokenTypes.RBRACE_SQ)
PlatformPatterns.psiElement(TwigTokenTypes.RBRACE_SQ),
PlatformPatterns.psiElement(TwigTokenTypes.RBRACE_CURL)
)
)
);
Expand Down Expand Up @@ -1619,7 +1626,7 @@ public void visitElement(PsiElement element) {
psiElement.acceptChildren(new PsiRecursiveElementVisitor() {
@Override
public void visitElement(PsiElement element) {
if(target[0] == null && TwigPattern.getPrintBlockFunctionPattern("block").accepts(element)) {
if(target[0] == null && TwigPattern.getPrintBlockOrTagFunctionPattern("block").accepts(element)) {
target[0] = element;
}
super.visitElement(element);
Expand Down Expand Up @@ -2212,7 +2219,12 @@ public static void visitTemplateIncludes(@NotNull TwigFile twigFile, @NotNull Co
visitTemplateIncludes(
twigFile,
consumer,
TemplateInclude.TYPE.EMBED, TemplateInclude.TYPE.INCLUDE, TemplateInclude.TYPE.INCLUDE_FUNCTION, TemplateInclude.TYPE.FROM, TemplateInclude.TYPE.IMPORT, TemplateInclude.TYPE.FORM_THEME
TemplateInclude.TYPE.EMBED,
TemplateInclude.TYPE.INCLUDE,
TemplateInclude.TYPE.INCLUDE_FUNCTION,
TemplateInclude.TYPE.FROM,
TemplateInclude.TYPE.IMPORT,
TemplateInclude.TYPE.FORM_THEME
);
}

Expand Down Expand Up @@ -2261,7 +2273,7 @@ private static void visitTemplateIncludes(@NotNull TwigFile twigFile, @NotNull C
// {{ include() }}
// {{ source() }}
if(myTypes.contains(TemplateInclude.TYPE.INCLUDE_FUNCTION)) {
PsiElement includeTag = PsiElementUtils.getChildrenOfType(psiElement, TwigPattern.getPrintBlockFunctionPattern("include", "source"));
PsiElement includeTag = PsiElementUtils.getChildrenOfType(psiElement, TwigPattern.getPrintBlockOrTagFunctionPattern("include", "source"));
if(includeTag != null) {
String templateName = includeTag.getText();
if(StringUtils.isNotBlank(templateName)) {
Expand Down Expand Up @@ -2298,17 +2310,21 @@ private static void visitTemplateIncludes(@NotNull TwigFile twigFile, @NotNull C
}
}

// {% form_theme form.child 'form/fields_child.html.twig' %}
// {% form_theme form.child with ['form/fields_child.html.twig'] %}
PsiElement withElement = PsiElementUtils.getNextSiblingOfType(tagElement, PlatformPatterns.psiElement().withElementType(TwigTokenTypes.IDENTIFIER).withText("with"));
if(withElement != null) {
PsiElement arrayStart = PsiElementUtils.getNextSiblingAndSkip(tagElement, TwigTokenTypes.LBRACE_SQ,
// find LITERAL "[", "{"
PsiElement arrayStart = PsiElementUtils.getNextSiblingAndSkip(tagElement, TwigElementTypes.LITERAL,
TwigTokenTypes.IDENTIFIER, TwigTokenTypes.SINGLE_QUOTE, TwigTokenTypes.DOUBLE_QUOTE, TwigTokenTypes.DOT
);

if(arrayStart != null) {
visitStringInArray(arrayStart, pair ->
consumer.consume(new TemplateInclude(psiElement, pair.getFirst(), TemplateInclude.TYPE.FORM_THEME))
);
PsiElement firstChild = arrayStart.getFirstChild();
if(firstChild != null) {
visitStringInArray(firstChild, pair ->
consumer.consume(new TemplateInclude(psiElement, pair.getFirst(), TemplateInclude.TYPE.FORM_THEME))
);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ public void visitElement(PsiElement element) {

if(element instanceof TwigCompositeElement) {
// {{ include('template.html') }}
PsiElement includeTag = PsiElementUtils.getChildrenOfType(element, TwigPattern.getPrintBlockFunctionPattern("include"));
PsiElement includeTag = PsiElementUtils.getChildrenOfType(element, TwigPattern.getPrintBlockOrTagFunctionPattern("include"));
if(includeTag != null) {
collectContextVars(TwigTokenTypes.IDENTIFIER, element, includeTag);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ public GotoCompletionProvider getProvider(@NotNull PsiElement psiElement) {
}
}

/**
* {{ 'symfony.great'|trans({'fo<caret>f'}, 'symfony')) }}
*/
private static class MyTwigTransFilterCompletionContributor implements GotoCompletionContributor {
@NotNull
private final String filter;
Expand All @@ -146,7 +149,13 @@ public GotoCompletionProvider getProvider(@NotNull PsiElement psiElement) {
return null;
}

PsiElement function = PsiElementUtils.getPrevSiblingOfType(parent, TwigPattern.getTranslationPattern(this.filter));
PsiElement functionCall = parent.getParent();
if(functionCall.getNode().getElementType() != TwigElementTypes.FUNCTION_CALL) {
return null;
}

// find translation key: 'symfony.great'
PsiElement function = PsiElementUtils.getPrevSiblingOfType(functionCall, TwigPattern.getTranslationKeyPattern(this.filter));
if(function == null) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ private static class MyTranslationKeyPsiElementVisitor extends PsiElementVisitor

@Override
public void visitElement(PsiElement psiElement) {
if(!TwigPattern.getTranslationPattern("trans", "transchoice").accepts(psiElement)) {
if(!TwigPattern.getTranslationKeyPattern("trans", "transchoice").accepts(psiElement)) {
super.visitElement(psiElement);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public String getText() {

@Nullable
private Pair<String, String> getKeyAndDomain(@NotNull PsiElement psiElement) {
if(!TwigPattern.getTranslationPattern("trans", "transchoice").accepts(psiElement)) {
if(!TwigPattern.getTranslationKeyPattern("trans", "transchoice").accepts(psiElement)) {
return null;
}

Expand Down
Loading

0 comments on commit dbcbe62

Please sign in to comment.