From e6f60d747fca6d6d47b04309d9ec277f9d0a9689 Mon Sep 17 00:00:00 2001 From: Alexander Pavlov Date: Fri, 20 Dec 2019 16:15:08 +0100 Subject: [PATCH] Implement {element} and {@state} Partly fixes #172 --- build.gradle | 8 +- src/main/grammars/Soy.bnf | 67 ++- src/main/grammars/Soy.flex | 4 + .../bamboo/soy/SoyFindUsagesProvider.java | 31 +- .../bamboo/soy/elements/AtStateElement.java | 60 +++ .../soy/elements/TemplateBlockElement.java | 13 + .../soy/elements/impl/AtStateMixin.java | 68 +++ .../google/bamboo/soy/format/SoySpacing.java | 3 +- .../bamboo/soy/format/blocks/SoyBlock.java | 2 + .../ClosingBraceSanityAnnotator.java | 4 +- .../completion/SoyCompletionContributor.java | 2 + .../google/bamboo/soy/lang/StateVariable.java | 25 ++ .../bamboo/soy/lexer/SoyTokenTypes.java | 2 + .../bamboo/soy/parser/SoyParserUtil.java | 2 + .../google/bamboo/soy/stubs/AtStateStub.java | 84 ++++ .../google/bamboo/soy/stubs/StubFactory.java | 3 +- .../soy/templates/SoyTemplateProvider.java | 2 +- .../liveTemplates/ClosureTemplates.xml | 15 + .../bamboo/soy/format/SoyFormatterTest.java | 18 +- .../bamboo/soy/insight/SoyCompletionTest.java | 19 +- .../insight/SoyDocumentationProviderTest.java | 10 + .../bamboo/soy/insight/SoyReferenceTest.java | 109 +++-- .../bamboo/soy/parser/SoyParserTest.java | 24 +- .../resources/insight/AtStateReference.soy | 8 + .../insight/AtStateReferenceTrailingDoc.soy | 7 + .../insight/CompletionSourceElement.soy | 22 + ...ource.soy => CompletionSourceTemplate.soy} | 0 src/test/resources/parser/AtParamList.soy | 51 ++- src/test/resources/parser/AtParamList.txt | 395 +++++++++++++++++- 29 files changed, 968 insertions(+), 90 deletions(-) create mode 100644 src/main/java/com/google/bamboo/soy/elements/AtStateElement.java create mode 100644 src/main/java/com/google/bamboo/soy/elements/impl/AtStateMixin.java create mode 100644 src/main/java/com/google/bamboo/soy/lang/StateVariable.java create mode 100644 src/main/java/com/google/bamboo/soy/stubs/AtStateStub.java create mode 100644 src/test/resources/insight/AtStateReference.soy create mode 100644 src/test/resources/insight/AtStateReferenceTrailingDoc.soy create mode 100644 src/test/resources/insight/CompletionSourceElement.soy rename src/test/resources/insight/{CompletionSource.soy => CompletionSourceTemplate.soy} (100%) diff --git a/build.gradle b/build.gradle index 28cf0dc3..4970ad5b 100644 --- a/build.gradle +++ b/build.gradle @@ -2,13 +2,11 @@ buildscript { repositories { maven { url 'https://jitpack.io' } } - dependencies { - classpath "com.github.hurricup:gradle-grammar-kit-plugin:2017.1.1" - } } plugins { - id 'org.jetbrains.intellij' version '0.2.17' + id 'org.jetbrains.grammarkit' version '2019.2' + id 'org.jetbrains.intellij' version '0.4.15' id 'org.jetbrains.kotlin.jvm' version '1.2.10' } @@ -24,7 +22,7 @@ dependencies { } intellij { - version 'IC-2017.1.5' + version 'IC-2019.2' updateSinceUntilBuild false } diff --git a/src/main/grammars/Soy.bnf b/src/main/grammars/Soy.bnf index ae3932e7..b03b0bc4 100644 --- a/src/main/grammars/Soy.bnf +++ b/src/main/grammars/Soy.bnf @@ -14,11 +14,11 @@ elementTypeClass="com.google.bamboo.soy.parser.SoyElementType" tokenTypeClass="com.google.bamboo.soy.lexer.SoyTokenType" - implements("Begin.*|.*Tag|.*Block")="com.google.bamboo.soy.elements.TagElement" + implements("Begin.*|.*Tag|(Namespace|Alias|DelegatePackage)Block")="com.google.bamboo.soy.elements.TagElement" implements("(Css|LetSingle|SpecialCharacter|Xid|Print)Statement") = ["com.google.bamboo.soy.elements.StatementElement" "com.google.bamboo.soy.elements.TagElement"] implements("LiteralStatement") = ["com.google.bamboo.soy.elements.StatementElement"] - implements(".*Statement") + implements("(Call|Choice|For|Foreach|If|LetCompound|Literal|Msg)Statement") = ["com.google.bamboo.soy.elements.StatementElement" "com.google.bamboo.soy.elements.TagBlockElement"] extends(".*Expr|VariableReferenceIdentifier")=Expr @@ -31,6 +31,7 @@ AS = "as" AT_PARAM = "@param" AT_PARAM_OPT = "@param?" + AT_STATE = "@state" AT_INJECT = "@inject" AT_INJECT_OPT = "@inject?" BOOL_LITERAL = "regexp:false|true" @@ -39,6 +40,7 @@ CARRIAGE_RETURN = "\\r" CASE = "case" COLON = ":" + COLON_EQUAL = ":=" COMMA = "," CSS="css" DEFAULT = "default" @@ -48,6 +50,7 @@ DOLLAR = "$" DOT = "." DOT_NULL_CHECK = "?." + ELEMENT = "element" ELSE = "else" ELSEIF = "elseif" EQUAL = "=" @@ -340,13 +343,14 @@ private AliasBody ::= ALIAS NamespaceIdentifier [AS AliasIdentifier] { // Template block -TemplateBlock ::= LocalTemplateBlock | DelegateTemplateBlock { +TemplateBlock ::= LocalTemplateBlock | DelegateTemplateBlock | LocalElementBlock { mixin="com.google.bamboo.soy.elements.impl.TemplateBlockMixin" implements="com.google.bamboo.soy.elements.TemplateBlockElement" stubClass = "com.google.bamboo.soy.stubs.TemplateBlockStub" elementTypeFactory = "com.google.bamboo.soy.stubs.StubFactory.getType" } +private LocalElementBlock ::= <> private LocalTemplateBlock ::= <> private DelegateTemplateBlock ::= <> @@ -358,6 +362,14 @@ private meta AbstractTemplateBlock ::= pin = 1 } +private meta AbstractElementBlock ::= + <>>> + [AtParamOrStateList] + [<>] + <>>> { + pin = 1 +} + meta BeginTemplate ::= <>>>>> { hooks = [wsBinders = "LEADING_COMMENTS_BINDER, TRAILING_COMMENTS_BINDER"] } @@ -369,6 +381,8 @@ private meta BeginTemplateBody ::= <

> (TemplateDefinitionIdentifier [Attribut private AtParamList ::= (AtParamSingle | AtInjectSingle)+ +private AtParamOrStateList ::= (AtParamSingle | AtInjectSingle | AtStateSingle)+ + AtParamSingle ::= <> { implements = "com.google.bamboo.soy.elements.AtParamElement" mixin = "com.google.bamboo.soy.elements.impl.AtParamMixin" @@ -382,6 +396,19 @@ private AtParamBody ::= (AT_PARAM | AT_PARAM_OPT) ParamDefinitionIdentifier COLO recoverWhile = "recoverEndOfTag" } +AtStateSingle ::= <> { + implements = "com.google.bamboo.soy.elements.AtStateElement" + mixin = "com.google.bamboo.soy.elements.impl.AtStateMixin" + stubClass = "com.google.bamboo.soy.stubs.AtStateStub" + elementTypeFactory = "com.google.bamboo.soy.stubs.StubFactory.getType" + hooks = [wsBinders = "LEADING_COMMENTS_BINDER, TRAILING_COMMENTS_BINDER"] +} + +private AtStateBody ::= (AT_STATE) ParamDefinitionIdentifier (COLON TypeExpression EQUAL Expr | COLON_EQUAL Expr) { + pin = 1 + recoverWhile = "recoverEndOfTag" +} + AtInjectSingle ::= <> { implements = "com.google.bamboo.soy.elements.AtInjectElement" mixin = "com.google.bamboo.soy.elements.impl.AtInjectMixin" @@ -430,6 +457,24 @@ private Content ::= OTHER private Statement ::= SingleTagStatement | + BlockTagStatement + | + Content + + +private SingleTagStatement ::= + CssStatement + | + LetSingleStatement + | + SpecialCharacterStatement + | + XidStatement + | + PrintStatement + + +private BlockTagStatement ::= CallStatement | ChoiceStatement @@ -445,20 +490,6 @@ private Statement ::= LiteralStatement | MsgStatement - | - Content - - -private SingleTagStatement ::= - CssStatement - | - LetSingleStatement - | - SpecialCharacterStatement - | - XidStatement - | - PrintStatement // Same as StatementList but cannot empty. @@ -616,7 +647,7 @@ private ParamList ::= recoverWhile = "!(endOfStatementBlock)" } -ParamListElement ::= !<> BlockParamListElement | BeginParamTag { +ParamListElement ::= !(<>) BlockParamListElement | BeginParamTag { implements = "com.google.bamboo.soy.elements.ParamElement" } diff --git a/src/main/grammars/Soy.flex b/src/main/grammars/Soy.flex index 4eac4246..96f510ff 100644 --- a/src/main/grammars/Soy.flex +++ b/src/main/grammars/Soy.flex @@ -115,12 +115,14 @@ NonSemantical=({WhiteSpace}|{DoubleSlashComment}|{DocComment}|{Comment})* "deltemplate"/{NonSemantical}{QualifiedIdentifier} { yybegin(TAG_QUALIFIED_IDENTIFIER); return SoyTypes.DELTEMPLATE; } "namespace"/{NonSemantical}{QualifiedIdentifier} { yybegin(TAG_QUALIFIED_IDENTIFIER); return SoyTypes.NAMESPACE; } "template"/{NonSemantical}{QualifiedIdentifier} { yybegin(TAG_QUALIFIED_IDENTIFIER); return SoyTypes.TEMPLATE; } + "element"/{NonSemantical}{QualifiedIdentifier} { yybegin(TAG_QUALIFIED_IDENTIFIER); return SoyTypes.ELEMENT; } "alias" { return SoyTypes.ALIAS; } "call" { return SoyTypes.CALL; } "delcall" { return SoyTypes.DELCALL; } "delpackage" { return SoyTypes.DELPACKAGE; } "deltemplate" { return SoyTypes.DELTEMPLATE; } + "element" { return SoyTypes.ELEMENT; } "namespace" { return SoyTypes.NAMESPACE; } "template" { return SoyTypes.TEMPLATE; } @@ -136,6 +138,7 @@ NonSemantical=({WhiteSpace}|{DoubleSlashComment}|{DocComment}|{Comment})* "@inject?" { return SoyTypes.AT_INJECT_OPT; } "@param" { return SoyTypes.AT_PARAM; } "@param?" { return SoyTypes.AT_PARAM_OPT; } + "@state" { return SoyTypes.AT_STATE; } "case" { return SoyTypes.CASE; } "default" { return SoyTypes.DEFAULT; } @@ -210,6 +213,7 @@ NonSemantical=({WhiteSpace}|{DoubleSlashComment}|{DocComment}|{Comment})* "=" { return SoyTypes.EQUAL; } ":" { return SoyTypes.COLON; } + ":=" { return SoyTypes.COLON_EQUAL; } "?" { return SoyTypes.QUESTIONMARK; } "?:" { return SoyTypes.TERNARY_COALESCER; } diff --git a/src/main/java/com/google/bamboo/soy/SoyFindUsagesProvider.java b/src/main/java/com/google/bamboo/soy/SoyFindUsagesProvider.java index d6e32c59..0cf59d95 100644 --- a/src/main/java/com/google/bamboo/soy/SoyFindUsagesProvider.java +++ b/src/main/java/com/google/bamboo/soy/SoyFindUsagesProvider.java @@ -15,7 +15,15 @@ package com.google.bamboo.soy; import com.google.bamboo.soy.lexer.SoyLexer; +import com.google.bamboo.soy.parser.SoyAtInjectSingle; +import com.google.bamboo.soy.parser.SoyAtParamSingle; +import com.google.bamboo.soy.parser.SoyAtStateSingle; +import com.google.bamboo.soy.parser.SoyBeginLet; +import com.google.bamboo.soy.parser.SoyBeginTemplate; +import com.google.bamboo.soy.parser.SoyLetSingleStatement; +import com.google.bamboo.soy.parser.SoyNamespaceDeclarationIdentifier; import com.google.bamboo.soy.parser.SoyTypes; +import com.google.bamboo.soy.parser.SoyVariableDefinitionIdentifier; import com.intellij.lang.cacheBuilder.DefaultWordsScanner; import com.intellij.lang.cacheBuilder.WordsScanner; import com.intellij.lang.findUsages.FindUsagesProvider; @@ -26,6 +34,7 @@ import org.jetbrains.annotations.Nullable; public class SoyFindUsagesProvider implements FindUsagesProvider { + @Nullable @Override public WordsScanner getWordsScanner() { @@ -50,6 +59,26 @@ public String getHelpId(@NotNull PsiElement psiElement) { @NotNull @Override public String getType(@NotNull PsiElement psiElement) { + if (psiElement instanceof SoyVariableDefinitionIdentifier) { + return "Variable"; // for/foreach/let + } + PsiElement parent = psiElement.getParent(); + if (parent instanceof SoyAtParamSingle) { + return "Parameter"; + } + if (parent instanceof SoyAtStateSingle) { + return "State param"; + } + if (parent instanceof SoyAtInjectSingle) { + return "Injected param"; + } + if (parent instanceof SoyNamespaceDeclarationIdentifier) { + return "Namespace"; + } + if (parent instanceof SoyBeginTemplate) { + return ((SoyBeginTemplate) parent).getTagNameTokenType() == SoyTypes.ELEMENT + ? "Element" : "Template"; + } return ""; } @@ -62,6 +91,6 @@ public String getDescriptiveName(@NotNull PsiElement psiElement) { @NotNull @Override public String getNodeText(@NotNull PsiElement psiElement, boolean useFullName) { - return ""; + return psiElement.getText(); } } diff --git a/src/main/java/com/google/bamboo/soy/elements/AtStateElement.java b/src/main/java/com/google/bamboo/soy/elements/AtStateElement.java new file mode 100644 index 00000000..b00bd1a8 --- /dev/null +++ b/src/main/java/com/google/bamboo/soy/elements/AtStateElement.java @@ -0,0 +1,60 @@ +// Copyright 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.bamboo.soy.elements; + +import com.google.bamboo.soy.lang.Parameter; +import com.google.bamboo.soy.lang.StateVariable; +import com.google.bamboo.soy.parser.SoyParamDefinitionIdentifier; +import com.google.bamboo.soy.parser.SoyTypeExpression; +import com.google.bamboo.soy.parser.SoyTypes; +import com.google.bamboo.soy.stubs.AtParamStub; +import com.google.bamboo.soy.stubs.AtStateStub; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.StubBasedPsiElement; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface AtStateElement extends StubBasedPsiElement, PsiNamedElement, + TagElement { + + @Nullable + SoyParamDefinitionIdentifier getParamDefinitionIdentifier(); + + @Nullable + SoyTypeExpression getTypeExpression(); + + default PsiElement setName(@NotNull String s) throws IncorrectOperationException { + return null; + } + + @NotNull + default String getType() { + if (getStub() != null) { + return getStub().type; + } + if (getTypeExpression() != null) { + return getTypeExpression().getText(); + } + return ""; + } + + default StateVariable toStateVariable() { + return this.getParamDefinitionIdentifier() == null + ? null + : new StateVariable(getName(), getType(), this.getParamDefinitionIdentifier()); + } +} diff --git a/src/main/java/com/google/bamboo/soy/elements/TemplateBlockElement.java b/src/main/java/com/google/bamboo/soy/elements/TemplateBlockElement.java index be2e1e53..10b12647 100644 --- a/src/main/java/com/google/bamboo/soy/elements/TemplateBlockElement.java +++ b/src/main/java/com/google/bamboo/soy/elements/TemplateBlockElement.java @@ -19,6 +19,7 @@ import com.google.bamboo.soy.lang.Variable; import com.google.bamboo.soy.parser.SoyAtInjectSingle; import com.google.bamboo.soy.parser.SoyAtParamSingle; +import com.google.bamboo.soy.parser.SoyAtStateSingle; import com.google.bamboo.soy.parser.SoyTemplateDefinitionIdentifier; import com.google.bamboo.soy.parser.SoyTypes; import com.google.bamboo.soy.stubs.TemplateBlockStub; @@ -46,6 +47,9 @@ public interface TemplateBlockElement @NotNull List getAtParamSingleList(); + @NotNull + List getAtStateSingleList(); + @Override default PsiElement setName(@NotNull String s) throws IncorrectOperationException { return null; @@ -84,6 +88,7 @@ default List getLocalVariables() { List variables = new ArrayList<>(); variables.addAll(getParameters()); variables.addAll(getInjectedVariables()); + variables.addAll(getStateVariables()); return variables; } @@ -94,4 +99,12 @@ default List getInjectedVariables() { .filter(Objects::nonNull) .collect(Collectors.toList()); } + + default List getStateVariables() { + return getAtStateSingleList() + .stream() + .map(SoyAtStateSingle::toStateVariable) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/com/google/bamboo/soy/elements/impl/AtStateMixin.java b/src/main/java/com/google/bamboo/soy/elements/impl/AtStateMixin.java new file mode 100644 index 00000000..0dd2ed42 --- /dev/null +++ b/src/main/java/com/google/bamboo/soy/elements/impl/AtStateMixin.java @@ -0,0 +1,68 @@ +// Copyright 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.bamboo.soy.elements.impl; + +import com.google.bamboo.soy.elements.AtParamElement; +import com.google.bamboo.soy.elements.AtStateElement; +import com.google.bamboo.soy.parser.SoyParamDefinitionIdentifier; +import com.google.bamboo.soy.parser.SoyTypeExpression; +import com.google.bamboo.soy.stubs.AtParamStub; +import com.google.bamboo.soy.stubs.AtStateStub; +import com.intellij.lang.ASTNode; +import com.intellij.psi.stubs.IStubElementType; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class AtStateMixin extends SoyStubBasedPsiElementBase + implements AtStateElement { + + public AtStateMixin(AtStateStub stub, IStubElementType type) { + super(stub, type); + } + + public AtStateMixin(ASTNode node) { + super(node); + } + + public AtStateMixin(AtStateStub stub, IElementType type, ASTNode node) { + super(stub, type, node); + } + + @NotNull + @Override + public String getName() { + if (getStub() != null) { + return getStub().getName(); + } + if (getParamDefinitionIdentifier() != null) { + return getParamDefinitionIdentifier().getName(); + } + return ""; + } + + @Nullable + @Override + public SoyParamDefinitionIdentifier getParamDefinitionIdentifier() { + return PsiTreeUtil.getChildOfType(this, SoyParamDefinitionIdentifier.class); + } + + @Nullable + @Override + public SoyTypeExpression getTypeExpression() { + return PsiTreeUtil.getChildOfType(this, SoyTypeExpression.class); + } +} diff --git a/src/main/java/com/google/bamboo/soy/format/SoySpacing.java b/src/main/java/com/google/bamboo/soy/format/SoySpacing.java index 2ccfe12f..1f32bd77 100644 --- a/src/main/java/com/google/bamboo/soy/format/SoySpacing.java +++ b/src/main/java/com/google/bamboo/soy/format/SoySpacing.java @@ -35,7 +35,7 @@ public static SpacingBuilder getSpacingBuilder(CommonCodeStyleSettings settings) // Left brace should not be followed by whitespace. .after(SoyTokenTypes.LEFT_BRACES).spacing(0, 0, 0, false, 0) - // /} and /} should be preceded by a space. + // /} and /}} should be preceded by a space. .before(SoyTokenTypes.SLASH_R_BRACES).spacing(1, 1, 0, false, 0) // } and }} should not be preceded by whitespace. .before(SoyTokenTypes.RIGHT_BRACES).spacing(0, 0, 0, false, 0) @@ -51,6 +51,7 @@ public static SpacingBuilder getSpacingBuilder(CommonCodeStyleSettings settings) .around(SoyTypes.NAMESPACE_BLOCK).lineBreakInCode() .around(SoyTypes.AT_INJECT_SINGLE).lineBreakInCode() .around(SoyTypes.AT_PARAM_SINGLE).lineBreakInCode() + .around(SoyTypes.AT_STATE_SINGLE).lineBreakInCode() .around(SoyTypes.CHOICE_CLAUSE).lineBreakInCode() .around(SoyTypes.PARAM_LIST_ELEMENT).lineBreakInCode() diff --git a/src/main/java/com/google/bamboo/soy/format/blocks/SoyBlock.java b/src/main/java/com/google/bamboo/soy/format/blocks/SoyBlock.java index a5cdf2ce..9866a819 100644 --- a/src/main/java/com/google/bamboo/soy/format/blocks/SoyBlock.java +++ b/src/main/java/com/google/bamboo/soy/format/blocks/SoyBlock.java @@ -23,6 +23,7 @@ import com.google.bamboo.soy.format.SoySpacing; import com.google.bamboo.soy.parser.SoyAtInjectSingle; import com.google.bamboo.soy.parser.SoyAtParamSingle; +import com.google.bamboo.soy.parser.SoyAtStateSingle; import com.google.bamboo.soy.parser.SoyChoiceClause; import com.google.bamboo.soy.parser.SoyStatementList; import com.google.bamboo.soy.parser.SoyTypes; @@ -74,6 +75,7 @@ private static boolean isAlwaysIndented(PsiElement element) { return element instanceof ParamElement || element instanceof SoyAtParamSingle || element instanceof SoyAtInjectSingle + || element instanceof SoyAtStateSingle || element instanceof SoyChoiceClause; } diff --git a/src/main/java/com/google/bamboo/soy/insight/annotators/ClosingBraceSanityAnnotator.java b/src/main/java/com/google/bamboo/soy/insight/annotators/ClosingBraceSanityAnnotator.java index 58747b85..d91881f9 100644 --- a/src/main/java/com/google/bamboo/soy/insight/annotators/ClosingBraceSanityAnnotator.java +++ b/src/main/java/com/google/bamboo/soy/insight/annotators/ClosingBraceSanityAnnotator.java @@ -18,6 +18,7 @@ import com.google.bamboo.soy.lexer.SoyTokenTypes; import com.google.bamboo.soy.parser.impl.SoyAliasBlockImpl; import com.google.bamboo.soy.parser.impl.SoyAtParamSingleImpl; +import com.google.bamboo.soy.parser.impl.SoyAtStateSingleImpl; import com.google.bamboo.soy.parser.impl.SoyBeginChoiceClauseImpl; import com.google.bamboo.soy.parser.impl.SoyBeginChoiceImpl; import com.google.bamboo.soy.parser.impl.SoyBeginElseIfImpl; @@ -54,6 +55,7 @@ public class ClosingBraceSanityAnnotator implements Annotator { ImmutableSet.builder() .add(SoyAliasBlockImpl.class) .add(SoyAtParamSingleImpl.class) + .add(SoyAtStateSingleImpl.class) .add(SoyBeginChoiceClauseImpl.class) .add(SoyBeginElseIfImpl.class) .add(SoyBeginForImpl.class) @@ -73,7 +75,7 @@ public class ClosingBraceSanityAnnotator implements Annotator { .add(SoyPrintStatementImpl.class) .add(SoyXidStatementImpl.class) .build(); - + private static ImmutableSet mustCloseSlashRBraceTags = ImmutableSet.of(SoyLetSingleStatementImpl.class); diff --git a/src/main/java/com/google/bamboo/soy/insight/completion/SoyCompletionContributor.java b/src/main/java/com/google/bamboo/soy/insight/completion/SoyCompletionContributor.java index 08c66769..a041d992 100644 --- a/src/main/java/com/google/bamboo/soy/insight/completion/SoyCompletionContributor.java +++ b/src/main/java/com/google/bamboo/soy/insight/completion/SoyCompletionContributor.java @@ -25,6 +25,7 @@ import com.google.bamboo.soy.parser.SoyAliasBlock; import com.google.bamboo.soy.parser.SoyAtInjectSingle; import com.google.bamboo.soy.parser.SoyAtParamSingle; +import com.google.bamboo.soy.parser.SoyAtStateSingle; import com.google.bamboo.soy.parser.SoyBeginCall; import com.google.bamboo.soy.parser.SoyBeginElseIf; import com.google.bamboo.soy.parser.SoyBeginFor; @@ -382,6 +383,7 @@ private void extendWithParameterTypes() { .andOr( psiElement().inside(SoyAtParamSingle.class).afterLeaf(":"), psiElement().inside(SoyAtInjectSingle.class).afterLeaf(":"), + psiElement().inside(SoyAtStateSingle.class).afterLeaf(":"), // List type literal. psiElement().inside(SoyListType.class).afterLeaf("<"), diff --git a/src/main/java/com/google/bamboo/soy/lang/StateVariable.java b/src/main/java/com/google/bamboo/soy/lang/StateVariable.java new file mode 100644 index 00000000..e9316ae5 --- /dev/null +++ b/src/main/java/com/google/bamboo/soy/lang/StateVariable.java @@ -0,0 +1,25 @@ +// Copyright 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License.package com.google.bamboo.soy.lang; + +package com.google.bamboo.soy.lang; + +import com.google.bamboo.soy.parser.SoyParamDefinitionIdentifier; +import org.jetbrains.annotations.NotNull; + +public class StateVariable extends Variable { + public StateVariable( + String name, String type, @NotNull SoyParamDefinitionIdentifier element) { + super(name, type, element); + } +} diff --git a/src/main/java/com/google/bamboo/soy/lexer/SoyTokenTypes.java b/src/main/java/com/google/bamboo/soy/lexer/SoyTokenTypes.java index 4b277bff..36638818 100644 --- a/src/main/java/com/google/bamboo/soy/lexer/SoyTokenTypes.java +++ b/src/main/java/com/google/bamboo/soy/lexer/SoyTokenTypes.java @@ -33,6 +33,7 @@ public class SoyTokenTypes { /* Tag names */ SoyTypes.AT_PARAM, SoyTypes.AT_PARAM_OPT, + SoyTypes.AT_STATE, SoyTypes.AT_INJECT, SoyTypes.AT_INJECT_OPT, SoyTypes.ALIAS, @@ -43,6 +44,7 @@ public class SoyTokenTypes { SoyTypes.DELCALL, SoyTypes.DELPACKAGE, SoyTypes.DELTEMPLATE, + SoyTypes.ELEMENT, SoyTypes.ELSE, SoyTypes.ELSEIF, SoyTypes.FALLBACKMSG, diff --git a/src/main/java/com/google/bamboo/soy/parser/SoyParserUtil.java b/src/main/java/com/google/bamboo/soy/parser/SoyParserUtil.java index 03f5104c..2afb7562 100644 --- a/src/main/java/com/google/bamboo/soy/parser/SoyParserUtil.java +++ b/src/main/java/com/google/bamboo/soy/parser/SoyParserUtil.java @@ -6,6 +6,7 @@ import static com.google.bamboo.soy.parser.SoyTypes.DEL_CALL_STATEMENT; import static com.google.bamboo.soy.parser.SoyTypes.DIRECT_CALL_STATEMENT; import static com.google.bamboo.soy.parser.SoyTypes.DOC_COMMENT_BLOCK; +import static com.google.bamboo.soy.parser.SoyTypes.ELEMENT; import static com.google.bamboo.soy.parser.SoyTypes.FOR; import static com.google.bamboo.soy.parser.SoyTypes.FOREACH; import static com.google.bamboo.soy.parser.SoyTypes.FOREACH_STATEMENT; @@ -91,6 +92,7 @@ public int getEdgePosition(List tokens, boolean atStreamEdge, .put(CALL, DIRECT_CALL_STATEMENT) .put(DELCALL, DEL_CALL_STATEMENT) .put(DELTEMPLATE, TEMPLATE_BLOCK) + .put(ELEMENT, TEMPLATE_BLOCK) .put(FOREACH, FOREACH_STATEMENT) .put(FOR, FOR_STATEMENT) .put(IF, IF_STATEMENT) diff --git a/src/main/java/com/google/bamboo/soy/stubs/AtStateStub.java b/src/main/java/com/google/bamboo/soy/stubs/AtStateStub.java new file mode 100644 index 00000000..2588e0fa --- /dev/null +++ b/src/main/java/com/google/bamboo/soy/stubs/AtStateStub.java @@ -0,0 +1,84 @@ +// Copyright 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.bamboo.soy.stubs; + +import com.google.bamboo.soy.SoyLanguage; +import com.google.bamboo.soy.parser.SoyAtStateSingle; +import com.google.bamboo.soy.parser.impl.SoyAtStateSingleImpl; +import com.intellij.psi.stubs.IStubElementType; +import com.intellij.psi.stubs.IndexSink; +import com.intellij.psi.stubs.NamedStubBase; +import com.intellij.psi.stubs.StubElement; +import com.intellij.psi.stubs.StubInputStream; +import com.intellij.psi.stubs.StubOutputStream; +import com.intellij.util.io.StringRef; +import java.io.IOException; +import org.jetbrains.annotations.NotNull; + +public class AtStateStub extends NamedStubBase { + + static final Type TYPE = new Type(); + public final String type; + + AtStateStub(StubElement parent, String name, String type) { + super(parent, TYPE, name); + this.type = type; + } + + static class Type extends IStubElementType { + + Type() { + super("AT_STATE", SoyLanguage.INSTANCE); + } + + @Override + public SoyAtStateSingle createPsi(@NotNull AtStateStub stub) { + return new SoyAtStateSingleImpl(stub, this); + } + + @NotNull + @Override + public AtStateStub createStub(@NotNull SoyAtStateSingle psi, StubElement parentStub) { + return new AtStateStub(parentStub, psi.getName(), psi.getType()); + } + + @NotNull + @Override + public String getExternalId() { + return "AT_STATE"; + } + + @Override + public void serialize(@NotNull AtStateStub stub, @NotNull StubOutputStream dataStream) + throws IOException { + dataStream.writeName(stub.getName()); + dataStream.writeName(stub.type); + } + + @NotNull + @Override + public AtStateStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) + throws IOException { + final StringRef ref = dataStream.readName(); + final StringRef ref2 = dataStream.readName(); + return new AtStateStub( + parentStub, ref.getString(), ref2.getString()); + } + + @Override + public void indexStub(@NotNull AtStateStub stub, @NotNull IndexSink sink) { + } + } +} diff --git a/src/main/java/com/google/bamboo/soy/stubs/StubFactory.java b/src/main/java/com/google/bamboo/soy/stubs/StubFactory.java index 597ff9ca..21a15a55 100644 --- a/src/main/java/com/google/bamboo/soy/stubs/StubFactory.java +++ b/src/main/java/com/google/bamboo/soy/stubs/StubFactory.java @@ -23,7 +23,8 @@ public abstract class StubFactory { "TEMPLATE_BLOCK", TemplateBlockStub.TYPE, "TEMPLATE_DEFINITION_IDENTIFIER", TemplateDefinitionStub.TYPE, "NAMESPACE_DECLARATION_IDENTIFIER", NamespaceDeclarationStub.TYPE, - "AT_PARAM_SINGLE", AtParamStub.TYPE); + "AT_PARAM_SINGLE", AtParamStub.TYPE, + "AT_STATE_SINGLE", AtStateStub.TYPE); public static IStubElementType getType(String elementName) { return stubTypeByElement.get(elementName); diff --git a/src/main/java/com/google/bamboo/soy/templates/SoyTemplateProvider.java b/src/main/java/com/google/bamboo/soy/templates/SoyTemplateProvider.java index 9177394e..0c0fd909 100644 --- a/src/main/java/com/google/bamboo/soy/templates/SoyTemplateProvider.java +++ b/src/main/java/com/google/bamboo/soy/templates/SoyTemplateProvider.java @@ -26,6 +26,6 @@ public String[] getDefaultLiveTemplateFiles() { @Nullable @Override public String[] getHiddenLiveTemplateFiles() { - return new String[0]; + return null; } } diff --git a/src/main/resources/liveTemplates/ClosureTemplates.xml b/src/main/resources/liveTemplates/ClosureTemplates.xml index f0b27edd..8e8bb5b4 100644 --- a/src/main/resources/liveTemplates/ClosureTemplates.xml +++ b/src/main/resources/liveTemplates/ClosureTemplates.xml @@ -13,6 +13,13 @@