├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── build.yaml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── qdana.yml ├── settings.gradle └── src ├── main ├── java │ └── org │ │ └── nette │ │ └── latte │ │ ├── LatteFileType.java │ │ ├── LatteLanguage.java │ │ ├── annotator │ │ └── LatteAnnotator.java │ │ ├── codeStyle │ │ ├── LatteCodeStyleSettings.java │ │ ├── LatteCodeStyleSettingsProvider.java │ │ └── LatteLanguageCodeStyleSettingsProvider.java │ │ ├── commenter │ │ └── LatteCommenter.java │ │ ├── completion │ │ ├── LatteCompletionContributor.java │ │ ├── handlers │ │ │ ├── AttrMacroInsertHandler.java │ │ │ ├── FilterInsertHandler.java │ │ │ ├── MacroCustomFunctionInsertHandler.java │ │ │ ├── MacroInsertHandler.java │ │ │ ├── PhpClassInsertHandler.java │ │ │ ├── PhpNamespaceInsertHandler.java │ │ │ └── PhpVariableInsertHandler.java │ │ ├── providers │ │ │ ├── BaseLatteCompletionProvider.java │ │ │ ├── LattePhpClassCompletionProvider.java │ │ │ ├── LattePhpCompletionProvider.java │ │ │ ├── LattePhpFunctionCompletionProvider.java │ │ │ ├── LattePhpNamespaceCompletionProvider.java │ │ │ └── LatteVariableCompletionProvider.java │ │ └── resolvers │ │ │ ├── LinkResolver.java │ │ │ └── PresenterResolver.java │ │ ├── config │ │ ├── LatteConfiguration.java │ │ └── LatteDefaultConfiguration.java │ │ ├── documentation │ │ └── LatteDocumentationProvider.java │ │ ├── editor │ │ ├── LatteSmartEnterProcessor.java │ │ ├── LatteStructureViewFactory.java │ │ ├── LatteStructureViewModel.java │ │ └── LatteStructureViewTreeElement.java │ │ ├── editorActions │ │ ├── LatteCompletionAutoPopupHandler.java │ │ ├── LatteQuoteHandler.java │ │ └── LatteTypedHandler.java │ │ ├── folding │ │ └── LatteFoldingBuilder.java │ │ ├── formatter │ │ ├── LatteBlock.java │ │ └── LatteFormattingModelBuilder.java │ │ ├── icons │ │ └── LatteIcons.java │ │ ├── indexes │ │ ├── LatteIndexUtil.java │ │ ├── LatteStubBasedPsiElement.java │ │ ├── extensions │ │ │ ├── LatteFilterIndex.java │ │ │ ├── LattePhpClassIndex.java │ │ │ ├── LattePhpConstantIndex.java │ │ │ ├── LattePhpMethodIndex.java │ │ │ ├── LattePhpNamespaceIndex.java │ │ │ ├── LattePhpPropertyIndex.java │ │ │ ├── LattePhpStaticVariableIndex.java │ │ │ └── LattePhpTypeIndex.java │ │ ├── externalizer │ │ │ └── ObjectStreamDataExternalizer.java │ │ └── stubs │ │ │ ├── LatteFileStub.java │ │ │ ├── LatteFilterStub.java │ │ │ ├── LattePhpClassStub.java │ │ │ ├── LattePhpConstantStub.java │ │ │ ├── LattePhpMethodStub.java │ │ │ ├── LattePhpNamespaceStub.java │ │ │ ├── LattePhpPropertyStub.java │ │ │ ├── LattePhpStaticVariableStub.java │ │ │ ├── LattePhpTypeStub.java │ │ │ ├── impl │ │ │ ├── LatteFilterStubImpl.java │ │ │ ├── LattePhpClassStubImpl.java │ │ │ ├── LattePhpConstantStubImpl.java │ │ │ ├── LattePhpMethodStubImpl.java │ │ │ ├── LattePhpNamespaceStubImpl.java │ │ │ ├── LattePhpPropertyStubImpl.java │ │ │ ├── LattePhpStaticVariableStubImpl.java │ │ │ └── LattePhpTypeStubImpl.java │ │ │ └── types │ │ │ ├── LatteFilterStubType.java │ │ │ ├── LattePhpClassStubType.java │ │ │ ├── LattePhpConstantStubType.java │ │ │ ├── LattePhpMethodStubType.java │ │ │ ├── LattePhpNamespaceStubType.java │ │ │ ├── LattePhpPropertyStubType.java │ │ │ ├── LattePhpStaticVariableStubType.java │ │ │ ├── LattePhpStubType.java │ │ │ └── LattePhpTypeStubType.java │ │ ├── inspections │ │ ├── BaseLocalInspectionTool.java │ │ ├── ClassUsagesInspection.java │ │ ├── ConstantUsagesInspection.java │ │ ├── DeprecatedTagInspection.java │ │ ├── LatteIterableTypeInspection.java │ │ ├── MacroTemplateTypeInspection.java │ │ ├── MacroVarInspection.java │ │ ├── MacroVarTypeInspection.java │ │ ├── MethodUsagesInspection.java │ │ ├── MissingFileInspection.java │ │ ├── ModifierDefinitionInspection.java │ │ ├── ModifierNotAllowedInspection.java │ │ ├── PropertyUsagesInspection.java │ │ ├── StaticPropertyUsagesInspection.java │ │ ├── VariablesInspection.java │ │ └── utils │ │ │ └── LatteInspectionInfo.java │ │ ├── intentions │ │ ├── AddCustomAttrOnlyMacro.java │ │ ├── AddCustomLatteFunction.java │ │ ├── AddCustomLatteModifier.java │ │ ├── AddCustomMacro.java │ │ ├── AddCustomNotNullVariable.java │ │ ├── AddCustomNullableVariable.java │ │ ├── AddCustomPairMacro.java │ │ ├── AddCustomUnpairedMacro.java │ │ ├── AddCustomVariable.java │ │ └── CreateMissingFile.java │ │ ├── lexer │ │ ├── LatteBaseFlexLexer.java │ │ ├── LatteHighlightingLexer.java │ │ ├── LatteHtmlHighlightingLexer.java │ │ ├── LatteLexer.java │ │ ├── LatteLookAheadLexer.java │ │ ├── LatteMacroContentLexerAdapter.java │ │ ├── LatteMacroLexerAdapter.java │ │ ├── LattePhpLexerAdapter.java │ │ ├── LatteTopLexerAdapter.java │ │ └── grammars │ │ │ ├── LatteMacroContentLexer.flex │ │ │ ├── LatteMacroLexer.flex │ │ │ ├── LattePhpLexer.flex │ │ │ └── LatteTopLexer.flex │ │ ├── liveTemplates │ │ ├── AbstractLatteTemplateContext.java │ │ ├── LatteTemplateContext.java │ │ └── LatteTemplatePreprocessor.java │ │ ├── parser │ │ ├── LatteElementTypes.java │ │ ├── LatteParser.bnf │ │ ├── LatteParserDefinition.java │ │ └── LatteParserUtil.java │ │ ├── php │ │ ├── LattePhpTypeDetector.java │ │ ├── LattePhpUtil.java │ │ ├── LattePhpVariableUtil.java │ │ └── NettePhpType.java │ │ ├── psi │ │ ├── ErrorFilter.java │ │ ├── LatteElementFactory.java │ │ ├── LatteElementType.java │ │ ├── LatteFile.java │ │ ├── LatteFileViewProvider.java │ │ ├── LatteFileViewProviderFactory.java │ │ ├── LatteIndexPatternBuilder.java │ │ ├── LatteOuterElementType.java │ │ ├── LatteTemplateDataElementType.java │ │ ├── LatteTokenType.java │ │ ├── elements │ │ │ ├── BaseLattePhpElement.java │ │ │ ├── LatteFilePathElement.java │ │ │ ├── LatteHtmlTagContainerElement.java │ │ │ ├── LatteLinkDestinationElement.java │ │ │ ├── LatteMacroContentElement.java │ │ │ ├── LatteMacroModifierElement.java │ │ │ ├── LatteMacroTagElement.java │ │ │ ├── LattePairMacroElement.java │ │ │ ├── LattePhpClassReferenceElement.java │ │ │ ├── LattePhpClassUsageElement.java │ │ │ ├── LattePhpConstantElement.java │ │ │ ├── LattePhpExpressionElement.java │ │ │ ├── LattePhpMethodElement.java │ │ │ ├── LattePhpNamespaceReferenceElement.java │ │ │ ├── LattePhpPropertyElement.java │ │ │ ├── LattePhpStatementElement.java │ │ │ ├── LattePhpStatementPartElement.java │ │ │ ├── LattePhpStaticVariableElement.java │ │ │ ├── LattePhpTypeElement.java │ │ │ ├── LattePhpTypedPartElement.java │ │ │ ├── LattePhpVariableElement.java │ │ │ ├── LattePsiElement.java │ │ │ └── LattePsiNamedElement.java │ │ └── impl │ │ │ ├── LattePhpElementImpl.java │ │ │ ├── LattePsiElementImpl.java │ │ │ ├── LattePsiImplUtil.java │ │ │ ├── LatteReferencedElementImpl.java │ │ │ ├── LatteStubElementImpl.java │ │ │ ├── LatteStubPhpElementImpl.java │ │ │ └── elements │ │ │ ├── LatteFilePathElementImpl.java │ │ │ ├── LatteHtmlTagContainerImpl.java │ │ │ ├── LatteLinkDestinationElementImpl.java │ │ │ ├── LatteMacroContentImpl.java │ │ │ ├── LatteMacroModifierElementImpl.java │ │ │ ├── LatteMacroTagElementImpl.java │ │ │ ├── LatteMacroTagImpl.java │ │ │ ├── LattePairMacroImpl.java │ │ │ ├── LattePhpClassReferenceElementImpl.java │ │ │ ├── LattePhpClassUsageElementImpl.java │ │ │ ├── LattePhpConstantElementImpl.java │ │ │ ├── LattePhpExpressionElementImpl.java │ │ │ ├── LattePhpMethodElementImpl.java │ │ │ ├── LattePhpNamespaceReferenceElementImpl.java │ │ │ ├── LattePhpPropertyElementImpl.java │ │ │ ├── LattePhpStatementElementImpl.java │ │ │ ├── LattePhpStatementPartElementImpl.java │ │ │ ├── LattePhpStaticVariableElementImpl.java │ │ │ ├── LattePhpTypeElementImpl.java │ │ │ ├── LattePhpTypedPartElementImpl.java │ │ │ └── LattePhpVariableElementImpl.java │ │ ├── refactoring │ │ └── LatteRenamePsiElementProcessor.java │ │ ├── reference │ │ ├── LatteBraceMatcher.java │ │ ├── LatteFindUsagesProvider.java │ │ ├── LatteReferenceContributor.java │ │ ├── LatteReferenceSearch.java │ │ └── references │ │ │ ├── LatteFilterReference.java │ │ │ ├── LatteLinkDestinationReference.java │ │ │ ├── LatteMacroTagReference.java │ │ │ ├── LatteNamespaceReference.java │ │ │ ├── LattePhpClassReference.java │ │ │ ├── LattePhpConstantReference.java │ │ │ ├── LattePhpMethodReference.java │ │ │ ├── LattePhpPropertyReference.java │ │ │ ├── LattePhpStaticVariableReference.java │ │ │ ├── LattePhpVariableReference.java │ │ │ ├── LatteXmlFilterDeclarationReference.java │ │ │ └── LatteXmlFunctionDeclarationReference.java │ │ ├── settings │ │ ├── BaseLatteSettings.java │ │ ├── LatteArgumentSettings.java │ │ ├── LatteFilterSettings.java │ │ ├── LatteFunctionSettings.java │ │ ├── LatteSettings.java │ │ ├── LatteTagSettings.java │ │ └── LatteVariableSettings.java │ │ ├── syntaxHighlighter │ │ ├── LatteColorSettingsPage.java │ │ ├── LatteEditorHighlighter.java │ │ ├── LatteSyntaxHighlighter.java │ │ └── LatteSyntaxHighlighterFactory.java │ │ ├── ui │ │ ├── LatteCustomFunctionSettingsDialog.form │ │ ├── LatteCustomFunctionSettingsDialog.java │ │ ├── LatteCustomFunctionSettingsForm.form │ │ ├── LatteCustomFunctionSettingsForm.java │ │ ├── LatteCustomMacroSettingsDialog.form │ │ ├── LatteCustomMacroSettingsDialog.java │ │ ├── LatteCustomMacroSettingsForm.form │ │ ├── LatteCustomMacroSettingsForm.java │ │ ├── LatteCustomModifierSettingsDialog.form │ │ ├── LatteCustomModifierSettingsDialog.java │ │ ├── LatteCustomModifierSettingsForm.form │ │ ├── LatteCustomModifierSettingsForm.java │ │ ├── LatteSettingsForm.form │ │ ├── LatteSettingsForm.java │ │ ├── LatteVariableSettingsDialog.form │ │ ├── LatteVariableSettingsDialog.java │ │ ├── LatteVariableSettingsForm.form │ │ ├── LatteVariableSettingsForm.java │ │ ├── PhpTypeColumn.java │ │ └── VendorTypeColumn.java │ │ └── utils │ │ ├── LatteHtmlUtil.java │ │ ├── LatteIdeHelper.java │ │ ├── LatteMimeTypes.java │ │ ├── LattePhpCachedVariable.java │ │ ├── LattePhpVariableDefinition.java │ │ ├── LatteTagsUtil.java │ │ ├── LatteTypesUtil.java │ │ └── LatteUtil.java └── resources │ ├── META-INF │ ├── plugin.xml │ ├── pluginIcon.svg │ └── pluginIcon_dark.svg │ ├── icons │ ├── Latte.png │ ├── Latte.xcf │ ├── Latte@2x.png │ ├── Latte@2x.xcf │ ├── LatteXml.png │ ├── LatteXml.xcf │ ├── Logo.png │ ├── Macro.png │ ├── Macro.xcf │ ├── Modifier.png │ ├── Modifier.xcf │ ├── NTag.png │ └── NTag.xcf │ ├── inspectionDescriptions │ ├── LatteIterableType.html │ ├── LatteMacroVar.html │ ├── LatteVarType.html │ └── LatteVariablesProblems.html │ ├── liveTemplates │ └── Latte.xml │ └── xmlSources │ └── Latte.xml └── test ├── java └── org │ └── nette │ └── latte │ ├── Assert.java │ ├── BasePsiParsingTestCase.java │ ├── inspections │ └── VariablesInspectionTest.java │ ├── lexer │ ├── LatteHighlightingLexerTest.java │ ├── LatteLexerTest.java │ ├── LatteLookAheadLexerTest.java │ ├── LatteMacroContentLexerAdapterTest.java │ ├── LatteMacroLexerAdapterTest.java │ ├── LattePhpLexerTest.java │ └── LatteTopLexerAdapterTest.java │ ├── parser │ └── ParserTest.java │ └── php │ ├── NettePhpTypeTest.java │ ├── VariableContextTest.java │ ├── VariableDefinitionBeforeElementTest.java │ ├── VariableDefinitionTest.java │ ├── VariableIsDefinitionTest.java │ └── variables │ └── PhpVariableTypeTest.java └── resources └── data ├── inspections └── variables │ ├── DefinitionsInAnotherContext.latte │ ├── MultipleDefinitions.latte │ ├── ProbablyUndefinedVariable.latte │ ├── UndefinedVariable.latte │ ├── VariableInBlock.latte │ └── VariableInNFor.latte ├── parser ├── BlockDefinition.latte ├── BlockDefinition.txt ├── ClassDefinition.latte ├── ClassDefinition.txt ├── ForDefinition.latte ├── ForDefinition.txt ├── ForeachDefinition.latte ├── ForeachDefinition.txt ├── ForeachReferenceDefinition.latte ├── ForeachReferenceDefinition.txt ├── MacroFilters.latte ├── MacroFilters.txt ├── NBlock.latte ├── NBlock.txt ├── ParametersDefinition.latte ├── ParametersDefinition.txt ├── TypedDefinition.latte ├── TypedDefinition.txt ├── UnknownInIf.latte ├── UnknownInIf.txt ├── Variable.latte └── Variable.txt ├── php ├── context │ ├── HtmlTag.latte │ ├── InBlock.latte │ ├── NetteAttrComplexForeach.latte │ ├── NetteAttribute.latte │ ├── NetteAttributeForeach.latte │ ├── Variable.latte │ ├── VariableInNFor.latte │ └── VariablesInDefine.latte ├── definition │ ├── BlockInIf.latte │ ├── BlockWithNAttr.latte │ ├── OtherVariables.latte │ ├── Variable.latte │ ├── VariableInNFor.latte │ └── VariableInside.latte ├── definitionBefore │ ├── DefinitionInBlock.latte │ └── SimpleDefinition.latte ├── isDefinition │ ├── DefinitionInNForeach.latte │ ├── DefinitionInNForeachWithBefore.latte │ └── VarTypeDefinition.latte └── variables │ └── variableType │ ├── ArrayDefinition.latte │ ├── BlockDefinition.latte │ ├── ClassDefinition.latte │ ├── ForDefinition.latte │ ├── ForeachArrowDefinition.latte │ ├── ForeachArrowNestedArrayDefinition.latte │ ├── ForeachDefinition.latte │ ├── ForeachNestedArrayDefinition.latte │ ├── ForeachReferenceDefinition.latte │ ├── MethodDefinition.latte │ ├── NForeachArrowDefinition.latte │ ├── ParametersDefinition.latte │ └── TypedDefinition.latte └── ss /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is and expected behavior. 12 | 13 | **Environment (please complete the following information):** 14 | - PhpStorm version [e.g. 2020.3.3] 15 | - Plugin version [e.g. 1.1.2] 16 | 17 | **To Reproduce** 18 | Steps to reproduce the behavior (or attach video): 19 | 1. Go to '...' 20 | 2. Click on '....' 21 | 3. Scroll down to '....' 22 | 4. See error 23 | 24 | **Code** 25 | If applicable, add your Latte code here as a text or upload file (text is better than screenshot for debugging) 26 | 27 | **Screenshots** 28 | If applicable, add screenshots to help explain your problem. 29 | 30 | **Additional context** 31 | Add any other context about the problem here if needed. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build with Gradle 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | # Only run on PRs if the source branch is on a different repo. We do not need to run everything twice. 8 | if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: gradle/actions/wrapper-validation@v3 13 | - name: Set up JDK 17 14 | uses: actions/setup-java@v4 15 | with: 16 | distribution: 'temurin' 17 | java-version: 17 18 | - name: Build with Gradle 19 | run: | 20 | chmod +x gradlew 21 | ./gradlew build -x test 22 | - name: Create artifact name 23 | id: vars 24 | run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT 25 | - name: Upload artifact 26 | uses: actions/upload-artifact@v4 27 | with: 28 | name: artifact-${{ steps.vars.outputs.sha_short }} 29 | path: build/libs 30 | - name: Download artifact 31 | uses: actions/download-artifact@v4 32 | - name: IntelliJ Platform Plugin Verifier 33 | uses: ChrisCarini/intellij-platform-plugin-verifier-action@v2.0.1 34 | with: 35 | ide-versions: | 36 | phpstorm:2022.2 37 | phpstorm:2023.1 38 | phpstorm:2024.1 39 | phpstorm:LATEST-EAP-SNAPSHOT 40 | - name: Upload release assets 41 | uses: softprops/action-gh-release@v2 42 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') 43 | with: 44 | files: artifact-${{ steps.vars.outputs.sha_short }}/**.jar 45 | - name: Publish plugin 46 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') 47 | run: | 48 | ./gradlew publishPlugin -x verifyPluginConfiguration 49 | env: 50 | PLUGIN_PUBLISH_TOKEN: ${{ secrets.PLUGIN_PUBLISH_TOKEN }} 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.iml 3 | local.properties 4 | /src/main/gen 5 | /.idea 6 | /.gradle 7 | /build 8 | /out 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 Nette Community 4 | Copyright (c) 2014-2024 Jan Tvrdík, Matouš Němec 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Latte Support for PhpStorm 2 | ========================================= 3 | 4 | 5 | Fork of the [original free plugin](https://github.com/nette-intellij/intellij-latte), provides decent support for [Latte](https://latte.nette.org) templates. 6 | 7 | 8 | 9 | ![example](https://i.imgur.com/KjIAx90.gif) 10 | 11 | 12 | Notice 13 | ------------ 14 | This plugin is in maintenance mode only (but feel free to contribute new features), errors and performance issues will still be fixed and updates will be on time, if you are looking for a plugin with more features, check out paid [Latte Pro](https://plugins.jetbrains.com/plugin/19661-latte-pro) plugin. This fork has been created as another free plugin, since code completion feature was removed from the original free plugin. 15 | 16 | If you have any problems with the plugin, [create an issue](https://github.com/Rixafy/LatteSupport/issues/new/choose) or use #latte channel at the [Nette Discord](https://discord.gg/azXxTbuQVq). 17 | 18 | 19 | Installation 20 | ------------ 21 | Settings → Plugins → Browse repositories → Find "Latte Support" → Install Plugin → Apply 22 | 23 | 24 | Installation from .jar file 25 | ------------ 26 | Download `instrumented.jar` file from [latest release](https://github.com/Rixafy/LatteSupport/releases) or latest successful [GitHub Actions build](https://github.com/Rixafy/LatteSupport/actions) 27 | 28 | 29 | Supported Features 30 | ------------------ 31 | 32 | * Syntax highlighting and code completion for `PHP` in `Latte` files 33 | * Type support and reference to classes and methods in `Latte` files (see [{templateType}](https://latte.nette.org/type-system#toc-templatetype)) 34 | * Refactoring support for `Latte` files (when changing class name, method name, etc.) 35 | * Live analysis of `Latte` files (unused variables, syntax errors, etc.) 36 | 37 | 38 | Building 39 | ------------ 40 | 41 | ```$xslt 42 | $ ./gradlew build -x test 43 | ``` 44 | 45 | Testing in dummy IDE 46 | ------------ 47 | 48 | ```$xslt 49 | $ ./gradlew runide 50 | ``` 51 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # IntelliJ Platform Artifacts Repositories -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html 2 | 3 | pluginGroup = org.nette.latte 4 | pluginName = Latte Support 5 | pluginRepositoryUrl = https://github.com/Rixafy/LatteSupport 6 | # SemVer format -> https://semver.org 7 | pluginVersion = 1.4.0 8 | 9 | # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html 10 | pluginSinceBuild = 222 11 | pluginUntilBuild = 291.* 12 | 13 | # IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension 14 | platformType = PS 15 | platformVersion = 2023.3.3 16 | platformDownloadSources = true 17 | 18 | # GrammarKit Properties 19 | jflexRelease = 1.7.0-1 20 | grammarKitRelease = 2022.3.2 21 | grammarKitIntelliJRelease = 223.8214.52 22 | 23 | # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html 24 | # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 25 | platformPlugins = com.jetbrains.php:233.11799.232 26 | 27 | # Java language level used to compile sources and to generate the files for - Java 11 is required since 2020.3 28 | javaVersion = 17 29 | 30 | # Gradle Releases -> https://github.com/gradle/gradle/releases 31 | gradleVersion = 8.7 32 | 33 | # Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib 34 | # suppress inspection "UnusedProperty" 35 | kotlin.stdlib.default.dependency = false 36 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /qdana.yml: -------------------------------------------------------------------------------- 1 | # Qodana configuration: 2 | # https://www.jetbrains.com/help/qodana/qodana-yaml.html 3 | 4 | version: 1.0 5 | profile: 6 | name: qodana.recommended 7 | exclude: 8 | - name: All 9 | paths: 10 | - .qodana -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'LatteSupport' 2 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/LatteFileType.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte; 2 | 3 | import com.intellij.openapi.editor.colors.EditorColorsScheme; 4 | import com.intellij.openapi.editor.highlighter.EditorHighlighter; 5 | import com.intellij.openapi.fileTypes.EditorHighlighterProvider; 6 | import com.intellij.openapi.fileTypes.FileType; 7 | import com.intellij.openapi.fileTypes.FileTypeEditorHighlighterProviders; 8 | import com.intellij.openapi.fileTypes.LanguageFileType; 9 | import com.intellij.openapi.project.Project; 10 | import com.intellij.openapi.vfs.VirtualFile; 11 | import org.nette.latte.icons.LatteIcons; 12 | import org.nette.latte.syntaxHighlighter.LatteEditorHighlighter; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | import javax.swing.*; 16 | 17 | public class LatteFileType extends LanguageFileType { 18 | public static final LatteFileType INSTANCE = new LatteFileType(); 19 | 20 | private LatteFileType() { 21 | super(LatteLanguage.INSTANCE); 22 | 23 | FileTypeEditorHighlighterProviders.INSTANCE.addExplicitExtension(this, new EditorHighlighterProvider() { 24 | public EditorHighlighter getEditorHighlighter(@Nullable Project project, @NotNull FileType fileType, @Nullable VirtualFile virtualFile, @NotNull EditorColorsScheme colors) { 25 | return new LatteEditorHighlighter(project, virtualFile,colors); 26 | } 27 | }); 28 | } 29 | 30 | @NotNull 31 | @Override 32 | public String getName() { 33 | return "Latte"; 34 | } 35 | 36 | @NotNull 37 | @Override 38 | public String getDescription() { 39 | return "Latte template files"; 40 | } 41 | 42 | @NotNull 43 | @Override 44 | public String getDefaultExtension() { 45 | return "latte"; 46 | } 47 | 48 | @Nullable 49 | @Override 50 | public Icon getIcon() { 51 | return LatteIcons.FILE; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/LatteLanguage.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte; 2 | 3 | import com.intellij.lang.Language; 4 | 5 | public class LatteLanguage extends Language { 6 | public static final LatteLanguage INSTANCE = new LatteLanguage(); 7 | 8 | private LatteLanguage() { 9 | super("Latte"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/codeStyle/LatteCodeStyleSettings.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.codeStyle; 2 | 3 | import com.intellij.psi.codeStyle.*; 4 | 5 | public class LatteCodeStyleSettings extends CustomCodeStyleSettings { 6 | public static boolean SPACE_AROUND_CONCATENATION = true; 7 | 8 | public LatteCodeStyleSettings(CodeStyleSettings settings) { 9 | super("LatteCodeStyleSettings", settings); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/codeStyle/LatteCodeStyleSettingsProvider.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.codeStyle; 2 | 3 | import com.intellij.application.options.*; 4 | import com.intellij.psi.codeStyle.*; 5 | import org.nette.latte.LatteLanguage; 6 | import org.jetbrains.annotations.*; 7 | 8 | public class LatteCodeStyleSettingsProvider extends CodeStyleSettingsProvider { 9 | @Override 10 | public CustomCodeStyleSettings createCustomSettings(CodeStyleSettings settings) { 11 | return new LatteCodeStyleSettings(settings); 12 | } 13 | 14 | @Nullable 15 | @Override 16 | public String getConfigurableDisplayName() { 17 | return "Latte"; 18 | } 19 | 20 | @NotNull 21 | public CodeStyleConfigurable createConfigurable(@NotNull CodeStyleSettings settings, @NotNull CodeStyleSettings modelSettings) { 22 | return new CodeStyleAbstractConfigurable(settings, modelSettings, this.getConfigurableDisplayName()) { 23 | @Override 24 | protected CodeStyleAbstractPanel createPanel(CodeStyleSettings settings) { 25 | return new LatteCodeStyleMainPanel(getCurrentSettings(), settings); 26 | } 27 | }; 28 | } 29 | 30 | private static class LatteCodeStyleMainPanel extends TabbedLanguageCodeStylePanel { 31 | public LatteCodeStyleMainPanel(CodeStyleSettings currentSettings, CodeStyleSettings settings) { 32 | super(LatteLanguage.INSTANCE, currentSettings, settings); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/commenter/LatteCommenter.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.commenter; 2 | 3 | import com.intellij.lang.Commenter; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * Implements support for action "Comments with Block Comment". 8 | */ 9 | public class LatteCommenter implements Commenter { 10 | @Nullable 11 | @Override 12 | public String getLineCommentPrefix() { 13 | return null; 14 | } 15 | 16 | @Nullable 17 | @Override 18 | public String getBlockCommentPrefix() { 19 | return "{*"; 20 | } 21 | 22 | @Nullable 23 | @Override 24 | public String getBlockCommentSuffix() { 25 | return "*}"; 26 | } 27 | 28 | @Nullable 29 | @Override 30 | public String getCommentedBlockCommentPrefix() { 31 | return null; 32 | } 33 | 34 | @Nullable 35 | @Override 36 | public String getCommentedBlockCommentSuffix() { 37 | return null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/completion/handlers/AttrMacroInsertHandler.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.completion.handlers; 2 | 3 | import com.intellij.codeInsight.completion.InsertHandler; 4 | import com.intellij.codeInsight.completion.InsertionContext; 5 | import com.intellij.codeInsight.lookup.LookupElement; 6 | import com.intellij.openapi.editor.CaretModel; 7 | import com.intellij.openapi.editor.Editor; 8 | import com.intellij.psi.PsiDocumentManager; 9 | import com.intellij.psi.PsiElement; 10 | import org.nette.latte.LatteLanguage; 11 | import org.nette.latte.config.LatteConfiguration; 12 | import org.nette.latte.psi.LatteTypes; 13 | import org.nette.latte.settings.LatteTagSettings; 14 | import org.nette.latte.utils.LatteUtil; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | public class AttrMacroInsertHandler implements InsertHandler { 18 | 19 | private static final AttrMacroInsertHandler instance = new AttrMacroInsertHandler(); 20 | 21 | public static AttrMacroInsertHandler getInstance() { 22 | return instance; 23 | } 24 | 25 | protected AttrMacroInsertHandler() { 26 | super(); 27 | } 28 | 29 | public void handleInsert(@NotNull InsertionContext context, @NotNull LookupElement lookupElement) { 30 | PsiElement element = context.getFile().findElementAt(context.getStartOffset()); 31 | if (element != null && element.getLanguage() == LatteLanguage.INSTANCE && element.getNode().getElementType() == LatteTypes.T_HTML_TAG_NATTR_NAME) { 32 | Editor editor = context.getEditor(); 33 | CaretModel caretModel = editor.getCaretModel(); 34 | int offset = caretModel.getOffset(); 35 | if (LatteUtil.isStringAtCaret(editor, "=")) { 36 | caretModel.moveToOffset(offset + 2); 37 | return; 38 | } 39 | 40 | String attrName = LatteUtil.normalizeNAttrNameModifier(element.getText()); 41 | LatteTagSettings macro = LatteConfiguration.getInstance(element.getProject()).getTag(attrName); 42 | if (macro != null && !macro.hasParameters()) { 43 | return; 44 | } 45 | 46 | editor.getDocument().insertString(offset, "=\"\""); 47 | caretModel.moveToOffset(offset + 2); 48 | 49 | PsiDocumentManager.getInstance(context.getProject()).commitDocument(editor.getDocument()); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/completion/handlers/PhpClassInsertHandler.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.completion.handlers; 2 | 3 | import com.intellij.codeInsight.completion.InsertionContext; 4 | import com.intellij.codeInsight.lookup.LookupElement; 5 | import com.intellij.psi.PsiDocumentManager; 6 | import com.jetbrains.php.completion.insert.PhpReferenceInsertHandler; 7 | import com.jetbrains.php.lang.psi.elements.PhpClass; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | public class PhpClassInsertHandler extends PhpReferenceInsertHandler { 11 | 12 | private static final PhpClassInsertHandler instance = new PhpClassInsertHandler(); 13 | 14 | public PhpClassInsertHandler() { 15 | super(); 16 | } 17 | 18 | public void handleInsert(@NotNull InsertionContext context, @NotNull LookupElement lookupElement) { 19 | final Object object = lookupElement.getObject(); 20 | final String classNamespace = object instanceof PhpClass ? ((PhpClass) object).getNamespaceName() : ""; 21 | 22 | if (!classNamespace.isEmpty()) { 23 | int startOffset = context.getEditor().getCaretModel().getOffset(); 24 | String fileText = context.getEditor().getDocument().getText(); 25 | String current = fileText.substring(0, startOffset); 26 | int lastSpace = current.lastIndexOf(" "); 27 | current = current.substring(lastSpace + 1); 28 | int index = current.lastIndexOf("\\"); 29 | String existingNamespace = ""; 30 | if (index > 0 && current.length() >= index) { 31 | existingNamespace = current.substring(0, index) + "\\"; 32 | } 33 | 34 | String fqn = classNamespace; 35 | if (!classNamespace.equals("\\") && !existingNamespace.startsWith("\\") && fqn.startsWith("\\")) { 36 | fqn = fqn.substring(1); 37 | } else if (classNamespace.equals("\\") && existingNamespace.length() == 0) { 38 | fqn = "\\"; 39 | } 40 | 41 | if (existingNamespace.length() > 0 && fqn.contains(existingNamespace)) { 42 | fqn = fqn.replace(existingNamespace, ""); 43 | } 44 | 45 | context.getDocument().insertString(context.getStartOffset(), fqn); 46 | PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument()); 47 | } 48 | } 49 | 50 | public static PhpClassInsertHandler getInstance() { 51 | return instance; 52 | } 53 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/completion/handlers/PhpNamespaceInsertHandler.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.completion.handlers; 2 | 3 | import com.intellij.codeInsight.completion.InsertionContext; 4 | import com.intellij.codeInsight.lookup.LookupElement; 5 | import com.intellij.openapi.editor.EditorModificationUtil; 6 | import com.intellij.psi.PsiDocumentManager; 7 | import com.jetbrains.php.completion.insert.PhpReferenceInsertHandler; 8 | import com.jetbrains.php.lang.psi.elements.PhpNamespace; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class PhpNamespaceInsertHandler extends PhpReferenceInsertHandler { 12 | 13 | private static final PhpNamespaceInsertHandler instance = new PhpNamespaceInsertHandler(); 14 | 15 | public PhpNamespaceInsertHandler() { 16 | super(); 17 | } 18 | 19 | public void handleInsert(@NotNull InsertionContext context, @NotNull LookupElement lookupElement) { 20 | final Object object = lookupElement.getObject(); 21 | String fqn = object instanceof PhpNamespace ? ((PhpNamespace) object).getParentNamespaceName() : ""; 22 | if (fqn.isEmpty()) { 23 | return; 24 | } 25 | 26 | int startOffset = context.getEditor().getCaretModel().getOffset(); 27 | String fileText = context.getEditor().getDocument().getText(); 28 | String current = fileText.substring(0, startOffset); 29 | int lastSpace = current.lastIndexOf(" "); 30 | current = current.substring(lastSpace + 1); 31 | 32 | if (fqn.startsWith("\\")) { 33 | fqn = fqn.substring(1); 34 | } 35 | 36 | context.getDocument().insertString(context.getStartOffset(), fqn); 37 | 38 | if (!current.endsWith("\\")) { 39 | EditorModificationUtil.insertStringAtCaret(context.getEditor(), "\\"); 40 | } 41 | 42 | PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument()); 43 | } 44 | 45 | public static PhpNamespaceInsertHandler getInstance() { 46 | return instance; 47 | } 48 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/completion/handlers/PhpVariableInsertHandler.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.completion.handlers; 2 | 3 | import com.intellij.codeInsight.completion.*; 4 | import com.intellij.codeInsight.lookup.LookupElement; 5 | import com.intellij.openapi.editor.CaretModel; 6 | import com.intellij.openapi.editor.Editor; 7 | import com.intellij.openapi.editor.EditorModificationUtil; 8 | import com.intellij.psi.PsiDocumentManager; 9 | import com.intellij.psi.PsiElement; 10 | import org.nette.latte.LatteLanguage; 11 | import com.jetbrains.php.lang.parser.PhpElementTypes; 12 | import com.jetbrains.php.lang.psi.PhpPsiUtil; 13 | import com.jetbrains.php.lang.psi.elements.Variable; 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | public class PhpVariableInsertHandler implements InsertHandler { 17 | 18 | private static final PhpVariableInsertHandler instance = new PhpVariableInsertHandler(); 19 | 20 | public PhpVariableInsertHandler() { 21 | super(); 22 | } 23 | 24 | public void handleInsert(@NotNull InsertionContext context, @NotNull LookupElement lookupElement) { 25 | PsiElement element = context.getFile().findElementAt(context.getStartOffset()); 26 | if (element != null && element.getLanguage() == LatteLanguage.INSTANCE) { 27 | PsiElement parent = element.getParent(); 28 | if (!(parent instanceof Variable) && !element.getText().startsWith("$")) { 29 | Editor editor = context.getEditor(); 30 | CaretModel caretModel = editor.getCaretModel(); 31 | int offset = caretModel.getOffset(); 32 | caretModel.moveToOffset(element.getTextOffset() + (PhpPsiUtil.isOfType(parent, PhpElementTypes.CAST_EXPRESSION) ? 1 : 0)); 33 | EditorModificationUtil.insertStringAtCaret(editor, "$"); 34 | caretModel.moveToOffset(offset + 1); 35 | PsiDocumentManager.getInstance(context.getProject()).commitDocument(editor.getDocument()); 36 | } 37 | } 38 | } 39 | 40 | public static PhpVariableInsertHandler getInstance() { 41 | return instance; 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/completion/providers/BaseLatteCompletionProvider.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.completion.providers; 2 | 3 | import com.intellij.codeInsight.completion.CompletionParameters; 4 | import com.intellij.codeInsight.completion.CompletionProvider; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.util.PsiTreeUtil; 7 | import org.nette.latte.psi.LattePhpClassUsage; 8 | import org.nette.latte.php.LattePhpUtil; 9 | import com.jetbrains.php.completion.PhpLookupElement; 10 | import com.jetbrains.php.lang.psi.elements.PhpNamedElement; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | 14 | import java.util.HashSet; 15 | import java.util.Set; 16 | 17 | abstract class BaseLatteCompletionProvider extends CompletionProvider { 18 | protected PhpLookupElement getPhpLookupElement(@NotNull PhpNamedElement phpNamedElement, @Nullable String searchedWord) { 19 | return getPhpLookupElement(phpNamedElement, searchedWord, null); 20 | } 21 | 22 | protected PhpLookupElement getPhpLookupElement(@NotNull PhpNamedElement phpNamedElement, @Nullable String searchedWord, @Nullable String tailText) { 23 | PhpLookupElement element = new PhpLookupElement(phpNamedElement) { 24 | @Override 25 | public Set getAllLookupStrings() { 26 | Set original = super.getAllLookupStrings(); 27 | Set strings = new HashSet<>(original.size() + 1); 28 | strings.addAll(original); 29 | if (searchedWord != null || this.getNamedElement() != null) { 30 | strings.add(searchedWord == null ? this.getNamedElement().getFQN() : searchedWord); 31 | } 32 | return strings; 33 | } 34 | }; 35 | if (tailText != null) { 36 | element.tailText = tailText; 37 | } 38 | return element; 39 | } 40 | 41 | protected String getNamespaceName(PsiElement element) { 42 | LattePhpClassUsage classUsage = PsiTreeUtil.getParentOfType(element, LattePhpClassUsage.class); 43 | String namespaceName = ""; 44 | if (classUsage != null) { 45 | String className = classUsage.getClassName().substring(1); 46 | if (className.length() == 1) { 47 | return ""; 48 | } 49 | className = classUsage.getClassName(); 50 | int index = className.lastIndexOf("\\"); 51 | namespaceName = className.substring(0, index); 52 | } 53 | return LattePhpUtil.normalizeClassName(namespaceName); 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/completion/providers/LattePhpClassCompletionProvider.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.completion.providers; 2 | 3 | import com.intellij.codeInsight.completion.*; 4 | import com.intellij.openapi.project.Project; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.util.PsiTreeUtil; 7 | import com.intellij.util.ProcessingContext; 8 | import org.nette.latte.completion.handlers.PhpClassInsertHandler; 9 | import org.nette.latte.psi.LattePhpContent; 10 | import org.nette.latte.php.LattePhpUtil; 11 | import com.jetbrains.php.completion.PhpLookupElement; 12 | import com.jetbrains.php.lang.psi.elements.PhpNamedElement; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.util.Collection; 16 | 17 | /** 18 | * Complete class names 19 | */ 20 | public class LattePhpClassCompletionProvider extends BaseLatteCompletionProvider { 21 | 22 | public LattePhpClassCompletionProvider() { 23 | super(); 24 | } 25 | 26 | @Override 27 | protected void addCompletions(@NotNull CompletionParameters params, @NotNull ProcessingContext ctx, @NotNull CompletionResultSet results) { 28 | PsiElement curr = params.getPosition().getOriginalElement(); 29 | if (PsiTreeUtil.getParentOfType(curr, LattePhpContent.class) == null) { 30 | return; 31 | } 32 | 33 | String prefix = results.getPrefixMatcher().getPrefix(); 34 | String namespaceName = getNamespaceName(curr); 35 | if (namespaceName.length() > 0) { 36 | namespaceName = namespaceName + "\\" + prefix; 37 | } 38 | 39 | Project project = params.getPosition().getProject(); 40 | Collection classNames = LattePhpUtil.getAllExistingClassAndInterfacesNames(project, results.getPrefixMatcher().cloneWithPrefix(namespaceName)); 41 | Collection variants = LattePhpUtil.getAllClassNamesAndInterfaces(project, classNames); 42 | 43 | // Add variants 44 | for (PhpNamedElement item : variants) { 45 | PhpLookupElement lookupItem = getPhpLookupElement(item, null); 46 | lookupItem.handler = PhpClassInsertHandler.getInstance(); 47 | results.addElement(lookupItem); 48 | } 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/completion/providers/LattePhpNamespaceCompletionProvider.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.completion.providers; 2 | 3 | import com.intellij.codeInsight.completion.CompletionParameters; 4 | import com.intellij.codeInsight.completion.CompletionResultSet; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.util.PsiTreeUtil; 7 | import com.intellij.util.ProcessingContext; 8 | import org.nette.latte.completion.handlers.PhpNamespaceInsertHandler; 9 | import org.nette.latte.psi.LattePhpContent; 10 | import org.nette.latte.php.LattePhpUtil; 11 | import com.jetbrains.php.completion.PhpLookupElement; 12 | import com.jetbrains.php.lang.psi.elements.PhpNamespace; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | import java.util.Collection; 17 | 18 | public class LattePhpNamespaceCompletionProvider extends BaseLatteCompletionProvider { 19 | 20 | public LattePhpNamespaceCompletionProvider() { 21 | } 22 | 23 | @Override 24 | protected void addCompletions(@NotNull CompletionParameters params, ProcessingContext context, @NotNull CompletionResultSet result) { 25 | PsiElement curr = params.getPosition().getOriginalElement(); 26 | if (PsiTreeUtil.getParentOfType(curr, LattePhpContent.class) == null) { 27 | return; 28 | } 29 | 30 | String namespaceName = getNamespaceName(curr); 31 | Collection namespaceNames = LattePhpUtil.getAllExistingNamespacesByName(curr.getProject(), namespaceName); 32 | Collection namespaces = LattePhpUtil.getAlNamespaces(curr.getProject(), namespaceNames); 33 | for (PhpNamespace namespace : namespaces) { 34 | PhpLookupElement lookupItem = getPhpLookupElement(namespace, null, getTypeText(namespace.getParentNamespaceName())); 35 | lookupItem.handler = PhpNamespaceInsertHandler.getInstance(); 36 | result.addElement(lookupItem); 37 | } 38 | } 39 | 40 | @Nullable 41 | private String getTypeText(String parentNamespace) { 42 | if (parentNamespace.length() > 1) { 43 | if (parentNamespace.startsWith("\\")) { 44 | parentNamespace = parentNamespace.substring(1); 45 | } 46 | if (parentNamespace.endsWith("\\") && parentNamespace.length() > 1) { 47 | parentNamespace = parentNamespace.substring(0, parentNamespace.length() - 1); 48 | } 49 | return " [" + parentNamespace + "]"; 50 | } 51 | return null; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/documentation/LatteDocumentationProvider.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.documentation; 2 | 3 | import com.intellij.lang.documentation.AbstractDocumentationProvider; 4 | import com.intellij.psi.PsiElement; 5 | import org.nette.latte.config.LatteConfiguration; 6 | import org.nette.latte.psi.LatteMacroModifier; 7 | import org.nette.latte.psi.LattePhpMethod; 8 | import org.nette.latte.settings.LatteFunctionSettings; 9 | import org.nette.latte.settings.LatteFilterSettings; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | public class LatteDocumentationProvider extends AbstractDocumentationProvider { 13 | 14 | @Override 15 | public @Nullable String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { 16 | if (element instanceof LatteMacroModifier) { 17 | LatteFilterSettings modifier = ((LatteMacroModifier) element).getMacroModifier(); 18 | if (modifier == null) { 19 | return null; 20 | } 21 | return createHelpWithDescription(modifier.getModifierHelp(), modifier.getModifierDescription()); 22 | 23 | } else if (element instanceof LattePhpMethod) { 24 | if (!((LattePhpMethod) element).isFunction()) { 25 | return null; 26 | } 27 | 28 | LatteFunctionSettings customFunction = LatteConfiguration.getInstance(element.getProject()).getFunction( 29 | ((LattePhpMethod) element).getMethodName() 30 | ); 31 | if (customFunction == null) { 32 | return null; 33 | } 34 | 35 | if (customFunction.getFunctionHelp().length() == 0 && customFunction.getFunctionDescription().length() == 0) { 36 | return "Custom defined Latte function (can be changed in project settings)"; 37 | } 38 | 39 | return createHelpWithDescription(customFunction.getFunctionHelp(), customFunction.getFunctionDescription()); 40 | } 41 | return null; 42 | } 43 | 44 | private String createHelpWithDescription(String help, String description) { 45 | String helpText = help.trim(); 46 | boolean hasDescription = description.trim().length() > 0; 47 | if (helpText.length() > 0 && hasDescription) { 48 | helpText += " - "; 49 | } 50 | if (hasDescription) { 51 | helpText += "\"" + description + "\""; 52 | } 53 | return helpText; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/editor/LatteSmartEnterProcessor.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.editor; 2 | 3 | import com.intellij.codeInsight.editorActions.smartEnter.SmartEnterProcessor; 4 | import com.intellij.openapi.editor.Editor; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.psi.FileViewProvider; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiFile; 9 | import com.intellij.psi.PsiWhiteSpace; 10 | import com.intellij.psi.util.PsiTreeUtil; 11 | import org.nette.latte.psi.LatteFile; 12 | import com.jetbrains.php.lang.PhpLanguage; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | public class LatteSmartEnterProcessor extends SmartEnterProcessor { 16 | 17 | @Override 18 | public boolean process(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile psiFile) { 19 | if (!(psiFile instanceof LatteFile)) { 20 | return false; 21 | } else { 22 | int offset = editor.getCaretModel().getOffset() - 1; 23 | FileViewProvider viewProvider = psiFile.getViewProvider(); 24 | PsiElement currElement = viewProvider.findElementAt(offset, PhpLanguage.INSTANCE); 25 | if (currElement instanceof PsiWhiteSpace) { 26 | currElement = PsiTreeUtil.prevLeaf(currElement); 27 | } 28 | 29 | if (true) { 30 | return false; 31 | } else { 32 | //boolean result = this.completeStatement(psiFile, editor, statement); 33 | //result |= completeParentStatement(psiFile, statement, editor); 34 | return false; 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/editor/LatteStructureViewFactory.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.editor; 2 | 3 | import com.intellij.ide.structureView.StructureViewBuilder; 4 | import com.intellij.ide.structureView.StructureViewModel; 5 | import com.intellij.ide.structureView.TreeBasedStructureViewBuilder; 6 | import com.intellij.lang.PsiStructureViewFactory; 7 | import com.intellij.openapi.editor.Editor; 8 | import com.intellij.psi.PsiFile; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | public class LatteStructureViewFactory implements PsiStructureViewFactory{ 13 | @Nullable 14 | @Override 15 | public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) { 16 | return new TreeBasedStructureViewBuilder() { 17 | @NotNull 18 | @Override 19 | public StructureViewModel createStructureViewModel(@Nullable Editor editor) { 20 | return new LatteStructureViewModel(psiFile); 21 | } 22 | }; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/editor/LatteStructureViewModel.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.editor; 2 | 3 | import com.intellij.ide.structureView.*; 4 | import com.intellij.ide.util.treeView.smartTree.Sorter; 5 | import com.intellij.psi.PsiFile; 6 | import org.nette.latte.psi.LatteFile; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | public class LatteStructureViewModel extends StructureViewModelBase implements StructureViewModel.ElementInfoProvider { 10 | public LatteStructureViewModel(PsiFile psiFile) { 11 | super(psiFile, new LatteStructureViewTreeElement(psiFile)); 12 | } 13 | 14 | @NotNull 15 | public Sorter[] getSorters() { 16 | return new Sorter[]{Sorter.ALPHA_SORTER}; 17 | } 18 | 19 | @Override 20 | public boolean isAlwaysShowsPlus(StructureViewTreeElement element) { 21 | return false; 22 | } 23 | 24 | @Override 25 | public boolean isAlwaysLeaf(StructureViewTreeElement element) { 26 | return element instanceof LatteFile; 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/editorActions/LatteCompletionAutoPopupHandler.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.editorActions; 2 | 3 | import com.intellij.codeInsight.AutoPopupController; 4 | import com.intellij.codeInsight.editorActions.CompletionAutoPopupHandler; 5 | import com.intellij.openapi.editor.Editor; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.psi.PsiFile; 8 | import org.nette.latte.psi.LatteFile; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.*; 12 | 13 | /** 14 | * Handles auto popups 15 | */ 16 | public class LatteCompletionAutoPopupHandler extends CompletionAutoPopupHandler { 17 | 18 | final private Map allowedPairs = new HashMap() {{ 19 | put('>', '-'); 20 | put(':', ':'); 21 | }}; 22 | 23 | final private Set allowedCharacters = new HashSet() {{ 24 | add('$'); 25 | add('|'); 26 | add('{'); 27 | add('\\'); 28 | }}; 29 | 30 | @Override 31 | public @NotNull Result checkAutoPopup(char charTyped, @NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { 32 | if (!(file instanceof LatteFile)) { 33 | return Result.DEFAULT; 34 | } 35 | 36 | if (allowedCharacters.contains(charTyped)) { 37 | AutoPopupController.getInstance(project).scheduleAutoPopup(editor); 38 | return Result.STOP; 39 | 40 | } else if (allowedPairs.containsKey(charTyped)) { 41 | int offset = editor.getCaretModel().getOffset(); 42 | String text = editor.getDocument().getText(); 43 | 44 | Character pairChar = allowedPairs.get(charTyped); 45 | if (offset > 0 && text.length() - 1 >= offset && text.charAt(offset - 1) == pairChar) { 46 | AutoPopupController.getInstance(project).scheduleAutoPopup(editor); 47 | return Result.STOP; 48 | } 49 | return Result.CONTINUE; 50 | } 51 | return super.checkAutoPopup(charTyped, project, editor, file); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/editorActions/LatteQuoteHandler.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.editorActions; 2 | 3 | import com.intellij.codeInsight.editorActions.QuoteHandler; 4 | import com.intellij.openapi.editor.Editor; 5 | import com.intellij.openapi.editor.highlighter.HighlighterIterator; 6 | import org.nette.latte.psi.LatteTypes; 7 | 8 | 9 | public class LatteQuoteHandler implements QuoteHandler { 10 | 11 | @Override 12 | public boolean isClosingQuote(HighlighterIterator iterator, int offset) { 13 | return iterator.getTokenType() == LatteTypes.T_PHP_DOUBLE_QUOTE_RIGHT || iterator.getTokenType() == LatteTypes.T_PHP_SINGLE_QUOTE_RIGHT; 14 | } 15 | 16 | @Override 17 | public boolean isOpeningQuote(HighlighterIterator iterator, int offset) { 18 | return iterator.getTokenType() == LatteTypes.T_PHP_DOUBLE_QUOTE_LEFT || iterator.getTokenType() == LatteTypes.T_PHP_SINGLE_QUOTE_LEFT; 19 | } 20 | 21 | @Override 22 | public boolean hasNonClosedLiteral(Editor editor, HighlighterIterator iterator, int offset) { 23 | return true; 24 | } 25 | 26 | @Override 27 | public boolean isInsideLiteral(HighlighterIterator iterator) { 28 | return false; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/folding/LatteFoldingBuilder.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.folding; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.lang.folding.FoldingBuilderEx; 5 | import com.intellij.lang.folding.FoldingDescriptor; 6 | import com.intellij.openapi.editor.Document; 7 | import com.intellij.openapi.util.TextRange; 8 | import com.intellij.psi.PsiElement; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import org.nette.latte.psi.*; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | import org.nette.latte.psi.LatteMacroClassic; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Collection; 17 | import java.util.List; 18 | 19 | public class LatteFoldingBuilder extends FoldingBuilderEx { 20 | @SuppressWarnings("unchecked") 21 | @NotNull 22 | @Override 23 | public FoldingDescriptor[] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) { 24 | List descriptors = new ArrayList<>(); 25 | 26 | if (!quick) { 27 | Collection nodes = PsiTreeUtil.findChildrenOfAnyType(root, LatteMacroClassic.class); 28 | for (PsiElement node : nodes) { 29 | int start = node.getFirstChild().getTextRange().getEndOffset(); 30 | int end = node.getLastChild().getTextRange().getEndOffset(); 31 | if (end == start) { 32 | continue; 33 | } 34 | if (node instanceof LatteMacroClassic) { 35 | start--; 36 | end--; 37 | } 38 | 39 | descriptors.add(new FoldingDescriptor(node, TextRange.create(start, end))); 40 | 41 | } 42 | } 43 | 44 | return descriptors.toArray(new FoldingDescriptor[0]); 45 | } 46 | 47 | @Nullable 48 | @Override 49 | public String getPlaceholderText(@NotNull ASTNode node) { 50 | return null; 51 | } 52 | 53 | @Override 54 | public boolean isCollapsedByDefault(@NotNull ASTNode node) { 55 | return false; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/icons/LatteIcons.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.icons; 2 | 3 | import com.intellij.openapi.util.IconLoader; 4 | 5 | import javax.swing.Icon; 6 | 7 | /** 8 | * Holds icon instances. 9 | */ 10 | public class LatteIcons { 11 | 12 | public static final Icon LOGO = IconLoader.getIcon("/icons/Logo.png", LatteIcons.class); 13 | public static final Icon FILE = IconLoader.getIcon("/icons/Latte.png", LatteIcons.class); 14 | public static final Icon FILE_XML = IconLoader.getIcon("/icons/LatteXml.png", LatteIcons.class); 15 | public static final Icon MACRO = IconLoader.getIcon("/icons/Macro.png", LatteIcons.class); 16 | public static final Icon MODIFIER = IconLoader.getIcon("/icons/Modifier.png", LatteIcons.class); 17 | public static final Icon N_TAG = IconLoader.getIcon("/icons/NTag.png", LatteIcons.class); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/LatteStubBasedPsiElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes; 2 | 3 | import com.intellij.extapi.psi.StubBasedPsiElementBase; 4 | import com.intellij.lang.ASTNode; 5 | import com.intellij.psi.PsiFile; 6 | import com.intellij.psi.stubs.IStubElementType; 7 | import com.intellij.psi.stubs.StubElement; 8 | import org.nette.latte.psi.LatteFile; 9 | import org.nette.latte.psi.elements.LattePsiElement; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | public class LatteStubBasedPsiElement extends StubBasedPsiElementBaseimplements LattePsiElement { 14 | private LatteFile file = null; 15 | 16 | public LatteStubBasedPsiElement(@NotNull T stub, @NotNull IStubElementType nodeType) { 17 | super(stub, nodeType); 18 | } 19 | 20 | public LatteStubBasedPsiElement(@NotNull ASTNode node) { 21 | super(node); 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return this.getClass().getSimpleName() + "(" + getNode().getElementType() + ")('" + getNode().getText() + "')"; 27 | } 28 | 29 | @Nullable public LatteFile getLatteFile() { 30 | if (file == null) { 31 | PsiFile containingFile = getContainingFile(); 32 | file = containingFile instanceof LatteFile ? (LatteFile) containingFile : null; 33 | } 34 | return file; 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/extensions/LatteFilterIndex.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.extensions; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.search.GlobalSearchScope; 5 | import com.intellij.psi.stubs.StringStubIndexExtension; 6 | import com.intellij.psi.stubs.StubIndex; 7 | import com.intellij.psi.stubs.StubIndexKey; 8 | import org.nette.latte.psi.LatteMacroModifier; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Collection; 12 | 13 | public class LatteFilterIndex extends StringStubIndexExtension { 14 | public static final StubIndexKey KEY = StubIndexKey.createIndexKey("latte.filter.index"); 15 | 16 | private static final LatteFilterIndex ourInstance = new LatteFilterIndex(); 17 | 18 | public static LatteFilterIndex getInstance() { 19 | return ourInstance; 20 | } 21 | 22 | @Override 23 | public int getVersion() { 24 | return super.getVersion() + 3; 25 | } 26 | 27 | @Override 28 | @NotNull 29 | public StubIndexKey getKey() { 30 | return KEY; 31 | } 32 | 33 | @Override 34 | public Collection get(@NotNull String key, @NotNull Project project, @NotNull GlobalSearchScope scope) { 35 | return StubIndex.getElements(getKey(), key, project, scope, LatteMacroModifier.class); 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/extensions/LattePhpClassIndex.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.extensions; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.search.GlobalSearchScope; 5 | import com.intellij.psi.stubs.StringStubIndexExtension; 6 | import com.intellij.psi.stubs.StubIndex; 7 | import com.intellij.psi.stubs.StubIndexKey; 8 | import org.nette.latte.psi.LattePhpClassReference; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Collection; 12 | 13 | public class LattePhpClassIndex extends StringStubIndexExtension { 14 | public static final StubIndexKey KEY = StubIndexKey.createIndexKey("latte.phpClass.index"); 15 | 16 | private static final LattePhpClassIndex ourInstance = new LattePhpClassIndex(); 17 | 18 | public static LattePhpClassIndex getInstance() { 19 | return ourInstance; 20 | } 21 | 22 | @Override 23 | public int getVersion() { 24 | return super.getVersion() + 3; 25 | } 26 | 27 | @Override 28 | @NotNull 29 | public StubIndexKey getKey() { 30 | return KEY; 31 | } 32 | 33 | @Override 34 | public Collection get(@NotNull String key, @NotNull Project project, @NotNull GlobalSearchScope scope) { 35 | return StubIndex.getElements(getKey(), key, project, scope, LattePhpClassReference.class); 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/extensions/LattePhpConstantIndex.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.extensions; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.search.GlobalSearchScope; 5 | import com.intellij.psi.stubs.StringStubIndexExtension; 6 | import com.intellij.psi.stubs.StubIndex; 7 | import com.intellij.psi.stubs.StubIndexKey; 8 | import org.nette.latte.psi.LattePhpConstant; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Collection; 12 | 13 | public class LattePhpConstantIndex extends StringStubIndexExtension { 14 | public static final StubIndexKey KEY = StubIndexKey.createIndexKey("latte.phpConstant.index"); 15 | 16 | private static final LattePhpConstantIndex ourInstance = new LattePhpConstantIndex(); 17 | 18 | public static LattePhpConstantIndex getInstance() { 19 | return ourInstance; 20 | } 21 | 22 | @Override 23 | public int getVersion() { 24 | return super.getVersion() + 3; 25 | } 26 | 27 | @Override 28 | @NotNull 29 | public StubIndexKey getKey() { 30 | return KEY; 31 | } 32 | 33 | @Override 34 | public Collection get(@NotNull String key, @NotNull Project project, @NotNull GlobalSearchScope scope) { 35 | return StubIndex.getElements(getKey(), key, project, scope, LattePhpConstant.class); 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/extensions/LattePhpMethodIndex.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.extensions; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.search.GlobalSearchScope; 5 | import com.intellij.psi.stubs.StringStubIndexExtension; 6 | import com.intellij.psi.stubs.StubIndex; 7 | import com.intellij.psi.stubs.StubIndexKey; 8 | import org.nette.latte.psi.LattePhpMethod; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Collection; 12 | 13 | public class LattePhpMethodIndex extends StringStubIndexExtension { 14 | public static final StubIndexKey KEY = StubIndexKey.createIndexKey("latte.phpMethod.index"); 15 | 16 | private static final LattePhpMethodIndex ourInstance = new LattePhpMethodIndex(); 17 | 18 | public static LattePhpMethodIndex getInstance() { 19 | return ourInstance; 20 | } 21 | 22 | @Override 23 | public int getVersion() { 24 | return super.getVersion() + 3; 25 | } 26 | 27 | @Override 28 | @NotNull 29 | public StubIndexKey getKey() { 30 | return KEY; 31 | } 32 | 33 | @Override 34 | public Collection get(@NotNull String key, @NotNull Project project, @NotNull GlobalSearchScope scope) { 35 | return StubIndex.getElements(getKey(), key, project, scope, LattePhpMethod.class); 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/extensions/LattePhpNamespaceIndex.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.extensions; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.search.GlobalSearchScope; 5 | import com.intellij.psi.stubs.StringStubIndexExtension; 6 | import com.intellij.psi.stubs.StubIndex; 7 | import com.intellij.psi.stubs.StubIndexKey; 8 | import org.nette.latte.psi.LattePhpNamespaceReference; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Collection; 12 | 13 | public class LattePhpNamespaceIndex extends StringStubIndexExtension { 14 | public static final StubIndexKey KEY = StubIndexKey.createIndexKey("latte.phpNamespace.index"); 15 | 16 | private static final LattePhpNamespaceIndex ourInstance = new LattePhpNamespaceIndex(); 17 | 18 | public static LattePhpNamespaceIndex getInstance() { 19 | return ourInstance; 20 | } 21 | 22 | @Override 23 | public int getVersion() { 24 | return super.getVersion() + 3; 25 | } 26 | 27 | @Override 28 | @NotNull 29 | public StubIndexKey getKey() { 30 | return KEY; 31 | } 32 | 33 | @Override 34 | public Collection get(@NotNull String key, @NotNull Project project, @NotNull GlobalSearchScope scope) { 35 | return StubIndex.getElements(getKey(), key, project, scope, LattePhpNamespaceReference.class); 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/extensions/LattePhpPropertyIndex.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.extensions; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.search.GlobalSearchScope; 5 | import com.intellij.psi.stubs.StringStubIndexExtension; 6 | import com.intellij.psi.stubs.StubIndex; 7 | import com.intellij.psi.stubs.StubIndexKey; 8 | import org.nette.latte.psi.LattePhpProperty; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Collection; 12 | 13 | public class LattePhpPropertyIndex extends StringStubIndexExtension { 14 | public static final StubIndexKey KEY = StubIndexKey.createIndexKey("latte.phpProperty.index"); 15 | 16 | private static final LattePhpPropertyIndex ourInstance = new LattePhpPropertyIndex(); 17 | 18 | public static LattePhpPropertyIndex getInstance() { 19 | return ourInstance; 20 | } 21 | 22 | @Override 23 | public int getVersion() { 24 | return super.getVersion() + 3; 25 | } 26 | 27 | @Override 28 | @NotNull 29 | public StubIndexKey getKey() { 30 | return KEY; 31 | } 32 | 33 | @Override 34 | public Collection get(@NotNull String key, @NotNull Project project, @NotNull GlobalSearchScope scope) { 35 | return StubIndex.getElements(getKey(), key, project, scope, LattePhpProperty.class); 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/extensions/LattePhpStaticVariableIndex.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.extensions; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.search.GlobalSearchScope; 5 | import com.intellij.psi.stubs.StringStubIndexExtension; 6 | import com.intellij.psi.stubs.StubIndex; 7 | import com.intellij.psi.stubs.StubIndexKey; 8 | import org.nette.latte.psi.LattePhpStaticVariable; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Collection; 12 | 13 | public class LattePhpStaticVariableIndex extends StringStubIndexExtension { 14 | public static final StubIndexKey KEY = StubIndexKey.createIndexKey("latte.phpStaticVariable.index"); 15 | 16 | private static final LattePhpStaticVariableIndex ourInstance = new LattePhpStaticVariableIndex(); 17 | 18 | public static LattePhpStaticVariableIndex getInstance() { 19 | return ourInstance; 20 | } 21 | 22 | @Override 23 | public int getVersion() { 24 | return super.getVersion() + 3; 25 | } 26 | 27 | @Override 28 | @NotNull 29 | public StubIndexKey getKey() { 30 | return KEY; 31 | } 32 | 33 | @Override 34 | public Collection get(@NotNull String key, @NotNull Project project, @NotNull GlobalSearchScope scope) { 35 | return StubIndex.getElements(getKey(), key, project, scope, LattePhpStaticVariable.class); 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/extensions/LattePhpTypeIndex.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.extensions; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.search.GlobalSearchScope; 5 | import com.intellij.psi.stubs.StringStubIndexExtension; 6 | import com.intellij.psi.stubs.StubIndex; 7 | import com.intellij.psi.stubs.StubIndexKey; 8 | import org.nette.latte.psi.LattePhpType; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Collection; 12 | 13 | public class LattePhpTypeIndex extends StringStubIndexExtension { 14 | public static final StubIndexKey KEY = StubIndexKey.createIndexKey("latte.phpType.index"); 15 | 16 | private static final LattePhpTypeIndex ourInstance = new LattePhpTypeIndex(); 17 | 18 | public static LattePhpTypeIndex getInstance() { 19 | return ourInstance; 20 | } 21 | 22 | @Override 23 | public int getVersion() { 24 | return super.getVersion() + 3; 25 | } 26 | 27 | @Override 28 | @NotNull 29 | public StubIndexKey getKey() { 30 | return KEY; 31 | } 32 | 33 | @Override 34 | public Collection get(@NotNull String key, @NotNull Project project, @NotNull GlobalSearchScope scope) { 35 | return StubIndex.getElements(getKey(), key, project, scope, LattePhpType.class); 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/externalizer/ObjectStreamDataExternalizer.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.externalizer; 2 | 3 | import com.intellij.util.io.DataExternalizer; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.io.*; 7 | 8 | public class ObjectStreamDataExternalizer implements DataExternalizer { 9 | 10 | @Override 11 | public void save(@NotNull DataOutput out, T value) throws IOException { 12 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 13 | ObjectOutput output = new ObjectOutputStream(stream); 14 | 15 | output.writeObject(value); 16 | 17 | out.writeInt(stream.size()); 18 | out.write(stream.toByteArray()); 19 | } 20 | 21 | @Override 22 | public T read(@NotNull DataInput in) throws IOException { 23 | int bufferSize = in.readInt(); 24 | byte[] buffer = new byte[bufferSize]; 25 | in.readFully(buffer, 0, bufferSize); 26 | 27 | ByteArrayInputStream stream = new ByteArrayInputStream(buffer); 28 | ObjectInput input = new ObjectInputStream(stream); 29 | 30 | T object = null; 31 | try { 32 | object = (T) input.readObject(); 33 | } catch (ClassNotFoundException | ClassCastException ignored) { 34 | } 35 | 36 | return object; 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/LatteFileStub.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs; 2 | 3 | import com.intellij.psi.stubs.PsiFileStub; 4 | import org.nette.latte.psi.LatteFile; 5 | 6 | public interface LatteFileStub extends PsiFileStub { 7 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/LatteFilterStub.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs; 2 | 3 | import com.intellij.psi.stubs.StubElement; 4 | import org.nette.latte.psi.LatteMacroModifier; 5 | 6 | public interface LatteFilterStub extends StubElement { 7 | String getModifierName(); 8 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/LattePhpClassStub.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs; 2 | 3 | import com.intellij.psi.stubs.StubElement; 4 | import org.nette.latte.psi.LattePhpClassReference; 5 | 6 | public interface LattePhpClassStub extends StubElement { 7 | String getClassName(); 8 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/LattePhpConstantStub.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs; 2 | 3 | import com.intellij.psi.stubs.StubElement; 4 | import org.nette.latte.psi.LattePhpConstant; 5 | 6 | public interface LattePhpConstantStub extends StubElement { 7 | String getConstantName(); 8 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/LattePhpMethodStub.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs; 2 | 3 | import com.intellij.psi.stubs.StubElement; 4 | import org.nette.latte.psi.LattePhpMethod; 5 | 6 | public interface LattePhpMethodStub extends StubElement { 7 | String getMethodName(); 8 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/LattePhpNamespaceStub.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs; 2 | 3 | import com.intellij.psi.stubs.StubElement; 4 | import org.nette.latte.psi.LattePhpNamespaceReference; 5 | 6 | public interface LattePhpNamespaceStub extends StubElement { 7 | String getNamespaceName(); 8 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/LattePhpPropertyStub.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs; 2 | 3 | import com.intellij.psi.stubs.StubElement; 4 | import org.nette.latte.psi.LattePhpProperty; 5 | 6 | public interface LattePhpPropertyStub extends StubElement { 7 | String getPropertyName(); 8 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/LattePhpStaticVariableStub.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs; 2 | 3 | import com.intellij.psi.stubs.StubElement; 4 | import org.nette.latte.psi.LattePhpStaticVariable; 5 | 6 | public interface LattePhpStaticVariableStub extends StubElement { 7 | String getVariableName(); 8 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/LattePhpTypeStub.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs; 2 | 3 | import com.intellij.psi.stubs.StubElement; 4 | import org.nette.latte.psi.LattePhpType; 5 | 6 | public interface LattePhpTypeStub extends StubElement { 7 | String getPhpType(); 8 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/impl/LatteFilterStubImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs.impl; 2 | 3 | import com.intellij.psi.stubs.StubBase; 4 | import com.intellij.psi.stubs.StubElement; 5 | import org.nette.latte.indexes.stubs.LatteFilterStub; 6 | import org.nette.latte.indexes.stubs.types.LatteFilterStubType; 7 | import org.nette.latte.psi.LatteMacroModifier; 8 | import org.nette.latte.psi.LatteTypes; 9 | 10 | public class LatteFilterStubImpl extends StubBase implements LatteFilterStub { 11 | private final String filterName; 12 | 13 | public LatteFilterStubImpl(final StubElement parent, final String filterName) { 14 | super(parent, (LatteFilterStubType) LatteTypes.MACRO_MODIFIER); 15 | this.filterName = filterName; 16 | } 17 | 18 | @Override 19 | public String getModifierName() { 20 | return filterName; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/impl/LattePhpClassStubImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs.impl; 2 | 3 | import com.intellij.psi.stubs.StubBase; 4 | import com.intellij.psi.stubs.StubElement; 5 | import org.nette.latte.indexes.stubs.LattePhpClassStub; 6 | import org.nette.latte.indexes.stubs.types.LattePhpClassStubType; 7 | import org.nette.latte.psi.LattePhpClassReference; 8 | import org.nette.latte.psi.LatteTypes; 9 | 10 | public class LattePhpClassStubImpl extends StubBase implements LattePhpClassStub { 11 | private final String className; 12 | 13 | public LattePhpClassStubImpl(final StubElement parent, final String className) { 14 | super(parent, (LattePhpClassStubType) LatteTypes.PHP_CLASS_REFERENCE); 15 | this.className = className; 16 | } 17 | 18 | @Override 19 | public String getClassName() { 20 | return className; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/impl/LattePhpConstantStubImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs.impl; 2 | 3 | import com.intellij.psi.stubs.StubBase; 4 | import com.intellij.psi.stubs.StubElement; 5 | import org.nette.latte.indexes.stubs.LattePhpConstantStub; 6 | import org.nette.latte.indexes.stubs.types.LattePhpConstantStubType; 7 | import org.nette.latte.psi.LattePhpConstant; 8 | import org.nette.latte.psi.LatteTypes; 9 | 10 | public class LattePhpConstantStubImpl extends StubBase implements LattePhpConstantStub { 11 | private final String constantName; 12 | 13 | public LattePhpConstantStubImpl(final StubElement parent, final String constantName) { 14 | super(parent, (LattePhpConstantStubType) LatteTypes.PHP_CONSTANT); 15 | this.constantName = constantName; 16 | } 17 | 18 | @Override 19 | public String getConstantName() { 20 | return constantName; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/impl/LattePhpMethodStubImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs.impl; 2 | 3 | import com.intellij.psi.stubs.StubElement; 4 | import com.intellij.psi.stubs.StubBase; 5 | import org.nette.latte.indexes.stubs.LattePhpMethodStub; 6 | import org.nette.latte.indexes.stubs.types.LattePhpMethodStubType; 7 | import org.nette.latte.psi.LattePhpMethod; 8 | import org.nette.latte.psi.LatteTypes; 9 | 10 | public class LattePhpMethodStubImpl extends StubBase implements LattePhpMethodStub { 11 | private final String methodName; 12 | 13 | public LattePhpMethodStubImpl(final StubElement parent, final String methodName) { 14 | super(parent, (LattePhpMethodStubType) LatteTypes.PHP_METHOD); 15 | this.methodName = methodName; 16 | } 17 | 18 | @Override 19 | public String getMethodName() { 20 | return methodName; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/impl/LattePhpNamespaceStubImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs.impl; 2 | 3 | import com.intellij.psi.stubs.StubBase; 4 | import com.intellij.psi.stubs.StubElement; 5 | import org.nette.latte.indexes.stubs.LattePhpNamespaceStub; 6 | import org.nette.latte.indexes.stubs.types.LattePhpNamespaceStubType; 7 | import org.nette.latte.psi.LattePhpNamespaceReference; 8 | import org.nette.latte.psi.LatteTypes; 9 | 10 | public class LattePhpNamespaceStubImpl extends StubBase implements LattePhpNamespaceStub { 11 | private final String namespaceName; 12 | 13 | public LattePhpNamespaceStubImpl(final StubElement parent, final String constantName) { 14 | super(parent, (LattePhpNamespaceStubType) LatteTypes.PHP_NAMESPACE_REFERENCE); 15 | this.namespaceName = constantName; 16 | } 17 | 18 | @Override 19 | public String getNamespaceName() { 20 | return namespaceName; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/impl/LattePhpPropertyStubImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs.impl; 2 | 3 | import com.intellij.psi.stubs.StubBase; 4 | import com.intellij.psi.stubs.StubElement; 5 | import org.nette.latte.indexes.stubs.LattePhpPropertyStub; 6 | import org.nette.latte.indexes.stubs.types.LattePhpPropertyStubType; 7 | import org.nette.latte.psi.LattePhpProperty; 8 | import org.nette.latte.psi.LatteTypes; 9 | 10 | public class LattePhpPropertyStubImpl extends StubBase implements LattePhpPropertyStub { 11 | private final String propertyName; 12 | 13 | public LattePhpPropertyStubImpl(final StubElement parent, final String propertyName) { 14 | super(parent, (LattePhpPropertyStubType) LatteTypes.PHP_PROPERTY); 15 | this.propertyName = propertyName; 16 | } 17 | 18 | @Override 19 | public String getPropertyName() { 20 | return propertyName; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/impl/LattePhpStaticVariableStubImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs.impl; 2 | 3 | import com.intellij.psi.stubs.StubBase; 4 | import com.intellij.psi.stubs.StubElement; 5 | import org.nette.latte.indexes.stubs.LattePhpStaticVariableStub; 6 | import org.nette.latte.indexes.stubs.types.LattePhpStaticVariableStubType; 7 | import org.nette.latte.psi.LattePhpStaticVariable; 8 | import org.nette.latte.psi.LatteTypes; 9 | 10 | public class LattePhpStaticVariableStubImpl extends StubBase implements LattePhpStaticVariableStub { 11 | private final String variableName; 12 | 13 | public LattePhpStaticVariableStubImpl(final StubElement parent, final String variableName) { 14 | super(parent, (LattePhpStaticVariableStubType) LatteTypes.PHP_STATIC_VARIABLE); 15 | this.variableName = variableName; 16 | } 17 | 18 | @Override 19 | public String getVariableName() { 20 | return variableName; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/impl/LattePhpTypeStubImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs.impl; 2 | 3 | import com.intellij.psi.stubs.StubBase; 4 | import com.intellij.psi.stubs.StubElement; 5 | import org.nette.latte.indexes.stubs.LattePhpTypeStub; 6 | import org.nette.latte.indexes.stubs.types.LattePhpTypeStubType; 7 | import org.nette.latte.psi.LattePhpType; 8 | import org.nette.latte.psi.LatteTypes; 9 | 10 | public class LattePhpTypeStubImpl extends StubBase implements LattePhpTypeStub { 11 | private final String phpType; 12 | 13 | public LattePhpTypeStubImpl(final StubElement parent, final String phpType) { 14 | super(parent, (LattePhpTypeStubType) LatteTypes.PHP_TYPE); 15 | this.phpType = phpType; 16 | } 17 | 18 | @Override 19 | public String getPhpType() { 20 | return phpType; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/indexes/stubs/types/LattePhpStubType.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.indexes.stubs.types; 2 | 3 | import com.intellij.lang.Language; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.stubs.*; 6 | import org.nette.latte.php.NettePhpType; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.io.IOException; 11 | import java.util.ArrayList; 12 | import java.util.Collection; 13 | import java.util.List; 14 | 15 | abstract public class LattePhpStubType, P extends PsiElement> extends ILightStubElementType { 16 | public LattePhpStubType(@NotNull String debugName, @Nullable Language language) { 17 | super(debugName, language); 18 | } 19 | 20 | protected static void writePhpType(StubOutputStream dataStream, @NotNull NettePhpType type) throws IOException { 21 | Collection types = type.getTypes(); 22 | dataStream.writeVarInt(types.size()); 23 | for (String s : types) { 24 | dataStream.writeName(s); 25 | } 26 | } 27 | 28 | @NotNull 29 | protected static NettePhpType readPhpType(StubInputStream dataStream) throws IOException { 30 | int i = dataStream.readVarInt(); 31 | 32 | List types = new ArrayList<>(); 33 | for(int j = 0; j < i; ++j) { 34 | String s = dataStream.readNameString(); 35 | if (s != null) { 36 | types.add(s); 37 | } 38 | } 39 | return NettePhpType.create(String.join("|", types)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/inspections/ClassUsagesInspection.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.inspections; 2 | 3 | import com.intellij.codeInspection.*; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.PsiFile; 6 | import com.intellij.psi.PsiRecursiveElementWalkingVisitor; 7 | import org.nette.latte.psi.LatteFile; 8 | import org.nette.latte.psi.LattePhpClassReference; 9 | import org.nette.latte.php.LattePhpUtil; 10 | import com.jetbrains.php.lang.psi.elements.PhpClass; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | 14 | import java.util.ArrayList; 15 | import java.util.Collection; 16 | import java.util.List; 17 | 18 | public class ClassUsagesInspection extends BaseLocalInspectionTool { 19 | 20 | @NotNull 21 | @Override 22 | public String getShortName() { 23 | return "LatteClassUsages"; 24 | } 25 | 26 | @Nullable 27 | @Override 28 | public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull final InspectionManager manager, final boolean isOnTheFly) { 29 | if (!(file instanceof LatteFile)) { 30 | return null; 31 | } 32 | 33 | final List problems = new ArrayList<>(); 34 | file.acceptChildren(new PsiRecursiveElementWalkingVisitor() { 35 | @Override 36 | public void visitElement(PsiElement element) { 37 | if (element instanceof LattePhpClassReference) { 38 | String className = ((LattePhpClassReference) element).getClassName(); 39 | Collection classes = LattePhpUtil.getClassesByFQN(element.getProject(), className); 40 | if (classes.size() == 0) { 41 | addProblem(manager, problems, element, "Undefined class '" + className + "'", isOnTheFly); 42 | 43 | } else { 44 | for (PhpClass phpClass : classes) { 45 | if (phpClass.isDeprecated()) { 46 | addDeprecated(manager, problems, element, "Used class '" + className + "' is marked as deprecated", isOnTheFly); 47 | break; 48 | 49 | } else if (phpClass.isInternal()) { 50 | addDeprecated(manager, problems, element, "Used class '" + className + "' is marked as internal", isOnTheFly); 51 | break; 52 | } 53 | } 54 | } 55 | 56 | } else { 57 | super.visitElement(element); 58 | } 59 | } 60 | }); 61 | 62 | return problems.toArray(new ProblemDescriptor[0]); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/inspections/DeprecatedTagInspection.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.inspections; 2 | 3 | import com.intellij.codeInspection.InspectionManager; 4 | import com.intellij.codeInspection.LocalInspectionTool; 5 | import com.intellij.codeInspection.ProblemDescriptor; 6 | import com.intellij.codeInspection.ProblemHighlightType; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiFile; 9 | import com.intellij.psi.PsiRecursiveElementWalkingVisitor; 10 | import org.nette.latte.config.LatteConfiguration; 11 | import org.nette.latte.psi.LatteFile; 12 | import org.nette.latte.psi.LatteMacroTag; 13 | import org.nette.latte.settings.LatteTagSettings; 14 | import org.jetbrains.annotations.NotNull; 15 | import org.jetbrains.annotations.Nullable; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | public class DeprecatedTagInspection extends LocalInspectionTool { 21 | 22 | @NotNull 23 | @Override 24 | public String getShortName() { 25 | return "DeprecatedTag"; 26 | } 27 | 28 | @Nullable 29 | @Override 30 | public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull final InspectionManager manager, final boolean isOnTheFly) { 31 | if (!(file instanceof LatteFile)) { 32 | return null; 33 | } 34 | final List problems = new ArrayList<>(); 35 | file.acceptChildren(new PsiRecursiveElementWalkingVisitor() { 36 | @Override 37 | public void visitElement(PsiElement element) { 38 | if (element instanceof LatteMacroTag) { 39 | String macroName = ((LatteMacroTag) element).getMacroName(); 40 | LatteTagSettings macro = LatteConfiguration.getInstance(element.getProject()).getTag(macroName); 41 | if (macro != null && macro.isDeprecated()) { 42 | String description = macro.getDeprecatedMessage() != null && macro.getDeprecatedMessage().length() > 0 43 | ? macro.getDeprecatedMessage() 44 | : "Tag {" + macroName + "} is deprecated"; 45 | ProblemDescriptor problem = manager.createProblemDescriptor(element, description, true, ProblemHighlightType.LIKE_DEPRECATED, isOnTheFly); 46 | problems.add(problem); 47 | 48 | } 49 | } else { 50 | super.visitElement(element); 51 | } 52 | } 53 | }); 54 | 55 | return problems.toArray(new ProblemDescriptor[0]); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/intentions/AddCustomAttrOnlyMacro.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.intentions; 2 | 3 | import org.nette.latte.settings.LatteTagSettings; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Registers custom macro which can be used only as an attribute macro. 8 | */ 9 | public class AddCustomAttrOnlyMacro extends AddCustomMacro { 10 | 11 | public AddCustomAttrOnlyMacro(String macroName) { 12 | super(macroName); 13 | } 14 | 15 | @NotNull 16 | @Override 17 | public LatteTagSettings.Type getMacroType() { 18 | return LatteTagSettings.Type.ATTR_ONLY; 19 | } 20 | 21 | @NotNull 22 | @Override 23 | public String getText() { 24 | return "Add custom unpaired attribute tag n:" + macro.getMacroName(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/intentions/AddCustomLatteFunction.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.intentions; 2 | 3 | import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; 4 | import com.intellij.codeInsight.intention.impl.BaseIntentionAction; 5 | import com.intellij.openapi.editor.Editor; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.psi.PsiFile; 8 | import com.intellij.util.IncorrectOperationException; 9 | import org.nette.latte.LatteLanguage; 10 | import org.nette.latte.settings.LatteFunctionSettings; 11 | import org.nette.latte.settings.LatteSettings; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | /** 15 | * Base class for intentions which will register a custom variable. 16 | */ 17 | public class AddCustomLatteFunction extends BaseIntentionAction { 18 | 19 | /** custom macro which will be registered on invocation */ 20 | protected final LatteFunctionSettings defaultFunction; 21 | 22 | @NotNull 23 | @Override 24 | public String getText() { 25 | return "Add custom latte function " + defaultFunction.getFunctionName() + "()"; 26 | } 27 | 28 | public AddCustomLatteFunction(String functionName) { 29 | this.defaultFunction = new LatteFunctionSettings(functionName); 30 | } 31 | 32 | @NotNull 33 | @Override 34 | public String getFamilyName() { 35 | return "Latte"; 36 | } 37 | 38 | @Override 39 | public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { 40 | return file.getLanguage() == LatteLanguage.INSTANCE; 41 | } 42 | 43 | @Override 44 | public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { 45 | LatteSettings.getInstance(project).functionSettings.add(defaultFunction); 46 | DaemonCodeAnalyzer.getInstance(project).restart(); // force re-analyzing 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/intentions/AddCustomLatteModifier.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.intentions; 2 | 3 | import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; 4 | import com.intellij.codeInsight.intention.impl.BaseIntentionAction; 5 | import com.intellij.openapi.editor.Editor; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.psi.PsiFile; 8 | import com.intellij.util.IncorrectOperationException; 9 | import org.nette.latte.LatteLanguage; 10 | import org.nette.latte.settings.LatteFilterSettings; 11 | import org.nette.latte.settings.LatteSettings; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | /** 15 | * Base class for intentions which will register a custom variable. 16 | */ 17 | public class AddCustomLatteModifier extends BaseIntentionAction { 18 | 19 | /** custom macro which will be registered on invocation */ 20 | protected final LatteFilterSettings defaultModifier; 21 | 22 | @NotNull 23 | @Override 24 | public String getText() { 25 | return "Add custom filter |" + defaultModifier.getModifierName(); 26 | } 27 | 28 | public AddCustomLatteModifier(String modifierName) { 29 | this.defaultModifier = new LatteFilterSettings(modifierName); 30 | } 31 | 32 | @NotNull 33 | @Override 34 | public String getFamilyName() { 35 | return "Latte"; 36 | } 37 | 38 | @Override 39 | public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { 40 | return file.getLanguage() == LatteLanguage.INSTANCE; 41 | } 42 | 43 | @Override 44 | public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { 45 | LatteSettings.getInstance(project).filterSettings.add(defaultModifier); 46 | DaemonCodeAnalyzer.getInstance(project).restart(); // force re-analyzing 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/intentions/AddCustomMacro.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.intentions; 2 | 3 | import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; 4 | import com.intellij.codeInsight.intention.impl.BaseIntentionAction; 5 | import com.intellij.openapi.editor.Editor; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.psi.PsiFile; 8 | import com.intellij.util.IncorrectOperationException; 9 | import org.nette.latte.LatteLanguage; 10 | import org.nette.latte.settings.LatteTagSettings; 11 | import org.nette.latte.settings.LatteSettings; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | /** 15 | * Base class for intentions which will register a custom macro. 16 | */ 17 | abstract public class AddCustomMacro extends BaseIntentionAction { 18 | 19 | /** custom macro which will be registered on invocation */ 20 | protected final LatteTagSettings macro; 21 | 22 | public AddCustomMacro(String macroName) { 23 | this.macro = new LatteTagSettings(macroName, getMacroType()); 24 | } 25 | 26 | @NotNull 27 | protected abstract LatteTagSettings.Type getMacroType(); 28 | 29 | @NotNull 30 | @Override 31 | public String getFamilyName() { 32 | return "Latte"; 33 | } 34 | 35 | @Override 36 | public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { 37 | return file.getLanguage() == LatteLanguage.INSTANCE; 38 | } 39 | 40 | @Override 41 | public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { 42 | LatteSettings.getInstance(project).tagSettings.add(macro); 43 | DaemonCodeAnalyzer.getInstance(project).restart(); // force re-analyzing 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/intentions/AddCustomNotNullVariable.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.intentions; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Registers custom not null variable which can be used only as an classic defined variable. 7 | */ 8 | public class AddCustomNotNullVariable extends AddCustomVariable { 9 | 10 | public AddCustomNotNullVariable(String variableName) { 11 | super(variableName); 12 | } 13 | 14 | @Override 15 | public boolean isNullable() { 16 | return false; 17 | } 18 | 19 | @NotNull 20 | @Override 21 | public String getText() { 22 | return "Add custom not null variable " + defaultVariable.getVarName(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/intentions/AddCustomNullableVariable.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.intentions; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Registers custom nullable variable which can be used only as an classic defined variable. 7 | */ 8 | public class AddCustomNullableVariable extends AddCustomVariable { 9 | 10 | public AddCustomNullableVariable(String variableName) { 11 | super(variableName); 12 | } 13 | 14 | @Override 15 | public boolean isNullable() { 16 | return true; 17 | } 18 | 19 | @NotNull 20 | @Override 21 | public String getText() { 22 | return "Add custom nullable variable " + defaultVariable.getVarName(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/intentions/AddCustomPairMacro.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.intentions; 2 | 3 | import org.nette.latte.settings.LatteTagSettings; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Registers custom macro which can be used only as both classic pair macro and attribute macro. 8 | */ 9 | public class AddCustomPairMacro extends AddCustomMacro { 10 | 11 | public AddCustomPairMacro(String macroName) { 12 | super(macroName); 13 | } 14 | 15 | @NotNull 16 | @Override 17 | public LatteTagSettings.Type getMacroType() { 18 | return LatteTagSettings.Type.PAIR; 19 | } 20 | 21 | @NotNull 22 | @Override 23 | public String getText() { 24 | return "Add custom pair tag {" + macro.getMacroName() + "}...{/" + macro.getMacroName() + "} and n:" + macro.getMacroName(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/intentions/AddCustomUnpairedMacro.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.intentions; 2 | 3 | import org.nette.latte.settings.LatteTagSettings; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Registers custom macro which can be used only as an classic unpaired macro. 8 | */ 9 | public class AddCustomUnpairedMacro extends AddCustomMacro { 10 | 11 | public AddCustomUnpairedMacro(String macroName) { 12 | super(macroName); 13 | } 14 | 15 | @NotNull 16 | @Override 17 | public LatteTagSettings.Type getMacroType() { 18 | return LatteTagSettings.Type.UNPAIRED; 19 | } 20 | 21 | @NotNull 22 | @Override 23 | public String getText() { 24 | return "Add custom unpaired tag {" + macro.getMacroName() + "}"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/intentions/AddCustomVariable.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.intentions; 2 | 3 | import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; 4 | import com.intellij.codeInsight.intention.impl.BaseIntentionAction; 5 | import com.intellij.openapi.editor.Editor; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.psi.PsiFile; 8 | import com.intellij.util.IncorrectOperationException; 9 | import org.nette.latte.LatteLanguage; 10 | import org.nette.latte.settings.LatteVariableSettings; 11 | import org.nette.latte.settings.LatteSettings; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | /** 15 | * Base class for intentions which will register a custom variable. 16 | */ 17 | abstract public class AddCustomVariable extends BaseIntentionAction { 18 | 19 | /** custom macro which will be registered on invocation */ 20 | protected final LatteVariableSettings defaultVariable; 21 | 22 | public AddCustomVariable(String variableName) { 23 | this.defaultVariable = new LatteVariableSettings(variableName, "mixed"); 24 | } 25 | 26 | protected abstract boolean isNullable(); 27 | 28 | @NotNull 29 | @Override 30 | public String getFamilyName() { 31 | return "Latte"; 32 | } 33 | 34 | @Override 35 | public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { 36 | return file.getLanguage() == LatteLanguage.INSTANCE; 37 | } 38 | 39 | @Override 40 | public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { 41 | LatteSettings.getInstance(project).variableSettings.add(defaultVariable); 42 | DaemonCodeAnalyzer.getInstance(project).restart(); // force re-analyzing 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/lexer/LatteBaseFlexLexer.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.lexer; 2 | 3 | import com.intellij.lexer.FlexLexer; 4 | import com.intellij.openapi.util.text.StringUtil; 5 | import com.intellij.util.ArrayUtil; 6 | 7 | import java.util.Arrays; 8 | import java.util.EmptyStackException; 9 | 10 | /** 11 | * Base class for lexers generated by JFlex. 12 | */ 13 | public abstract class LatteBaseFlexLexer implements FlexLexer { 14 | 15 | /** stack of lexical states */ 16 | private IntStack stateStack = new IntStack(10); 17 | 18 | /** 19 | * Changes lexical state to given state and pushes it to the stack. 20 | */ 21 | protected void pushState(int state) { 22 | stateStack.push(yystate()); 23 | yybegin(state); 24 | } 25 | 26 | /** 27 | * Returns to previous state and checks that the previous state is one of give states. 28 | */ 29 | protected void popState(int... states) { 30 | int top = stateStack.pop(); 31 | if (states.length > 0) { 32 | if (ArrayUtil.indexOf(states, top) < 0) { 33 | String list = StringUtil.join(states, ", "); 34 | throw new RuntimeException("Unexpected state on stack; expected one of " + list + " but found " + top + "."); 35 | } 36 | } 37 | yybegin(top); 38 | } 39 | 40 | /** 41 | * Rollbacks the entire match. 42 | */ 43 | protected void rollbackMatch() { 44 | yypushback(yylength()); 45 | } 46 | 47 | /** 48 | * Returns length of current match. 49 | */ 50 | public abstract int yylength(); 51 | 52 | /** 53 | * Rollbacks given number of characters from current match. 54 | */ 55 | public abstract void yypushback(int number); 56 | 57 | public static class IntStack { 58 | private int[] data; 59 | private int size; 60 | 61 | public IntStack(int initialCapacity) { 62 | this.data = new int[initialCapacity]; 63 | this.size = 0; 64 | } 65 | 66 | public void push(int t) { 67 | if (this.size >= this.data.length) { 68 | this.data = ArrayUtil.realloc(this.data, this.data.length * 3 / 2); 69 | } 70 | 71 | this.data[this.size++] = t; 72 | } 73 | 74 | public int pop() { 75 | if (this.size == 0) { 76 | throw new EmptyStackException(); 77 | } else { 78 | return this.data[--this.size]; 79 | } 80 | } 81 | 82 | public String toString() { 83 | return Arrays.toString(Arrays.copyOf(this.data, this.size)); 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/lexer/LatteHtmlHighlightingLexer.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.lexer; 2 | 3 | import com.intellij.lexer.Lexer; 4 | import com.intellij.lexer.LookAheadLexer; 5 | import com.intellij.psi.tree.IElementType; 6 | import org.nette.latte.psi.LatteTypes; 7 | import org.nette.latte.utils.LatteHtmlUtil; 8 | 9 | public class LatteHtmlHighlightingLexer extends LookAheadLexer { 10 | public LatteHtmlHighlightingLexer(Lexer baseLexer) { 11 | super(baseLexer, 1); 12 | } 13 | 14 | @Override 15 | protected void lookAhead(Lexer baseLexer) { 16 | IElementType currentToken = baseLexer.getTokenType(); 17 | 18 | if (currentToken != LatteTypes.T_TEXT && LatteHtmlUtil.HTML_TOKENS.contains(currentToken)) { 19 | advanceLexer(baseLexer); 20 | replaceCachedType(0, LatteTypes.T_TEXT); 21 | 22 | } else { 23 | super.lookAhead(baseLexer); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/lexer/LatteLexer.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.lexer; 2 | 3 | import com.intellij.lexer.LayeredLexer; 4 | import org.nette.latte.psi.LatteTypes; 5 | 6 | /** 7 | * Main Latte lexer which combines "top lexer" and "macro lexer". 8 | * 9 | * LatteMacroLexerAdapter is used to further process token T_MACRO_CLASSIC. 10 | */ 11 | public class LatteLexer extends LayeredLexer { 12 | public LatteLexer() { 13 | super(new LatteTopLexerAdapter()); 14 | LayeredLexer macroLexer = new LayeredLexer(new LatteMacroLexerAdapter()); 15 | macroLexer.registerLayer(createContentLexerAdapter(), LatteTypes.T_MACRO_CONTENT); 16 | 17 | registerLayer(macroLexer, LatteTypes.T_MACRO_CLASSIC); 18 | registerLayer(createContentLexerAdapter(), LatteTypes.T_MACRO_CONTENT); 19 | } 20 | 21 | private LayeredLexer createContentLexerAdapter() { 22 | LayeredLexer contentMacroLexer = new LayeredLexer(new LatteMacroContentLexerAdapter()); 23 | contentMacroLexer.registerLayer(new LattePhpLexerAdapter(), LatteTypes.T_PHP_CONTENT); 24 | return contentMacroLexer; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/lexer/LatteMacroContentLexerAdapter.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.lexer; 2 | 3 | import com.intellij.lexer.FlexAdapter; 4 | import com.intellij.lexer.MergingLexerAdapter; 5 | import com.intellij.psi.tree.TokenSet; 6 | import org.nette.latte.psi.LatteTypes; 7 | 8 | public class LatteMacroContentLexerAdapter extends MergingLexerAdapter { 9 | 10 | public LatteMacroContentLexerAdapter() { 11 | super( 12 | new FlexAdapter(new LatteMacroContentLexer(null)), 13 | TokenSet.create(LatteTypes.T_PHP_CONTENT, LatteTypes.T_MACRO_ARGS) 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/lexer/LatteMacroLexerAdapter.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.lexer; 2 | 3 | import com.intellij.lexer.FlexAdapter; 4 | import com.intellij.lexer.MergingLexerAdapter; 5 | import com.intellij.psi.tree.TokenSet; 6 | import org.nette.latte.psi.LatteTypes; 7 | 8 | /** 9 | * Adapter for {@link LatteMacroLexer} which is generated by JFlex to IntelliJ's interface 10 | * {@link com.intellij.lexer.Lexer}. 11 | * 12 | * Also merges any sequence of T_MACRO_CONTENT tokens to a single T_MACRO_CONTENT token. 13 | */ 14 | public class LatteMacroLexerAdapter extends MergingLexerAdapter { 15 | 16 | public LatteMacroLexerAdapter() { 17 | super( 18 | new FlexAdapter(new LatteMacroLexer((java.io.Reader) null)), 19 | TokenSet.create(LatteTypes.T_MACRO_CONTENT) 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/lexer/LattePhpLexerAdapter.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.lexer; 2 | 3 | import com.intellij.lexer.FlexAdapter; 4 | import com.intellij.lexer.Lexer; 5 | import com.intellij.lexer.MergingLexerAdapter; 6 | import com.intellij.psi.tree.TokenSet; 7 | import org.nette.latte.psi.LatteTypes; 8 | 9 | /** 10 | * Adapter for {@link LatteTopLexer} which is generated by JFlex to IntelliJ's interface 11 | * {@link Lexer}. 12 | * 13 | * Also merges any sequence of selected tokens to a single token. 14 | */ 15 | public class LattePhpLexerAdapter extends MergingLexerAdapter { 16 | public LattePhpLexerAdapter() { 17 | super( 18 | new FlexAdapter(new LattePhpLexer((java.io.Reader) null)), 19 | TokenSet.create(LatteTypes.T_TEXT, LatteTypes.T_HTML_CLOSE_TAG_OPEN, LatteTypes.T_HTML_OPEN_TAG_OPEN, LatteTypes.T_HTML_OPEN_TAG_CLOSE, LatteTypes.T_HTML_TAG_CLOSE) 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/lexer/LatteTopLexerAdapter.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.lexer; 2 | 3 | import com.intellij.lexer.FlexAdapter; 4 | import com.intellij.lexer.MergingLexerAdapter; 5 | import org.nette.latte.utils.LatteHtmlUtil; 6 | 7 | /** 8 | * Adapter for {@link LatteTopLexer} which is generated by JFlex to IntelliJ's interface 9 | * {@link com.intellij.lexer.Lexer}. 10 | * 11 | * Also merges any sequence of selected tokens to a single token. 12 | */ 13 | public class LatteTopLexerAdapter extends MergingLexerAdapter { 14 | public LatteTopLexerAdapter() { 15 | super( 16 | new FlexAdapter(new LatteTopLexer((java.io.Reader) null)), 17 | LatteHtmlUtil.HTML_TOKENS 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/lexer/grammars/LatteMacroContentLexer.flex: -------------------------------------------------------------------------------- 1 | package org.nette.latte.lexer; 2 | 3 | import com.intellij.psi.tree.IElementType; 4 | import static org.nette.latte.psi.LatteTypes.*; 5 | 6 | %% 7 | 8 | %class LatteMacroContentLexer 9 | %extends LatteBaseFlexLexer 10 | %function advance 11 | %type IElementType 12 | %unicode 13 | %ignorecase 14 | 15 | 16 | WHITE_SPACE=[ \t\r\n]+ 17 | SYMBOL = [_[:letter:]][_0-9[:letter:]]*(-[_0-9[:letter:]]+)* //todo: unicode letters 18 | FUNCTION_CALL=[a-zA-Z_][a-zA-Z0-9_]* "(" 19 | CLASS_NAME=\\?[a-zA-Z_][a-zA-Z0-9_]*\\[a-zA-Z_][a-zA-Z0-9_\\]* | \\[a-zA-Z_][a-zA-Z0-9_]* 20 | CONTENT_TYPE=[a-zA-Z\-][a-zA-Z0-9\-]*\/[a-zA-Z\-][a-zA-Z0-9\-\.]* 21 | FILE_IMPORT=[\w\-.@()#$%\^&*()!\/]+ ".latte" 22 | SIGNAL=[a-zA-Z\-\:]+ "!" 23 | 24 | %% 25 | 26 | 27 | { 28 | 29 | ({CLASS_NAME} | "$" | {FUNCTION_CALL} | "\"" | "'" | "{" | "(" | "[" | "|") .+ { 30 | return T_PHP_CONTENT; 31 | } 32 | 33 | {CONTENT_TYPE} { 34 | return T_PHP_CONTENT; 35 | } 36 | 37 | ([0-9]+ | {SYMBOL} | {CLASS_NAME}) { 38 | return T_PHP_CONTENT; 39 | } 40 | 41 | {WHITE_SPACE} { 42 | return T_WHITESPACE; 43 | } 44 | 45 | {FILE_IMPORT} { 46 | return T_FILE_PATH; 47 | } 48 | 49 | {SIGNAL} { 50 | return T_LINK_DESTINATION; 51 | } 52 | 53 | [^] { 54 | return T_MACRO_ARGS; 55 | } 56 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/lexer/grammars/LatteMacroLexer.flex: -------------------------------------------------------------------------------- 1 | package org.nette.latte.lexer; 2 | 3 | import com.intellij.psi.tree.IElementType; 4 | import static org.nette.latte.psi.LatteTypes.*; 5 | 6 | %% 7 | 8 | %class LatteMacroLexer 9 | %extends LatteBaseFlexLexer 10 | %function advance 11 | %type IElementType 12 | %unicode 13 | %ignorecase 14 | 15 | %state NAME_ANY 16 | %state NAME_NOT_Q 17 | %state NAME_SHORT 18 | %state ARGS 19 | 20 | NAME_FULL = [a-zA-Z][a-zA-Z0-9_]* ([.:][a-zA-Z0-9_]+)* 21 | 22 | %% 23 | { 24 | "{" { 25 | yybegin(NAME_ANY); 26 | return T_MACRO_OPEN_TAG_OPEN; 27 | } 28 | 29 | "{/" { 30 | yybegin(NAME_NOT_Q); 31 | return T_MACRO_CLOSE_TAG_OPEN; 32 | } 33 | } 34 | 35 | { 36 | "?" { 37 | yybegin(ARGS); 38 | return T_MACRO_NAME; 39 | } 40 | } 41 | 42 | { 43 | "!" { 44 | yybegin(NAME_SHORT); 45 | return T_MACRO_NOESCAPE; 46 | } 47 | 48 | {NAME_FULL} { 49 | yybegin(ARGS); 50 | return T_MACRO_NAME; 51 | } 52 | 53 | {NAME_FULL} ("::" | "(" | "\\") { 54 | yybegin(ARGS); 55 | return T_MACRO_CONTENT; 56 | } 57 | } 58 | 59 | { 60 | [=~#%\^&_] { 61 | yybegin(ARGS); 62 | return T_MACRO_SHORTNAME; 63 | } 64 | } 65 | 66 | { 67 | "}" { 68 | yybegin(ARGS); 69 | return T_MACRO_TAG_CLOSE; 70 | } 71 | 72 | "}" / [^] { 73 | yybegin(ARGS); 74 | return T_MACRO_CONTENT; 75 | } 76 | 77 | "/}" { 78 | yybegin(ARGS); 79 | return T_MACRO_TAG_CLOSE_EMPTY; 80 | } 81 | 82 | "/}" / [^] { 83 | yybegin(ARGS); 84 | return T_MACRO_CONTENT; 85 | } 86 | 87 | [^] { 88 | yybegin(ARGS); 89 | return T_MACRO_CONTENT; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/liveTemplates/AbstractLatteTemplateContext.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.liveTemplates; 2 | 3 | import com.intellij.codeInsight.template.TemplateActionContext; 4 | import com.intellij.codeInsight.template.TemplateContextType; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiFile; 7 | import com.intellij.psi.PsiWhiteSpace; 8 | import com.intellij.psi.util.PsiUtilCore; 9 | import com.jetbrains.php.lang.PhpLanguage; 10 | import org.jetbrains.annotations.NonNls; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.io.File; 14 | 15 | abstract public class AbstractLatteTemplateContext extends TemplateContextType { 16 | protected AbstractLatteTemplateContext(@NotNull String id, @NotNull String presentableName) { 17 | super(id, presentableName); 18 | } 19 | 20 | @Override 21 | public boolean isInContext(@NotNull TemplateActionContext templateActionContext) { 22 | PsiFile file = templateActionContext.getFile(); 23 | int offset = templateActionContext.getStartOffset(); 24 | if (PsiUtilCore.getLanguageAtOffset(file, offset).isKindOf(PhpLanguage.INSTANCE)) { 25 | PsiElement element = file.findElementAt(offset); 26 | if (element instanceof PsiWhiteSpace && offset > 0) { 27 | element = file.findElementAt(offset - 1); 28 | } 29 | 30 | return element != null && this.isInContext(element); 31 | } else { 32 | return false; 33 | } 34 | } 35 | 36 | protected abstract boolean isInContext(@NotNull PsiElement element); 37 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/liveTemplates/LatteTemplateContext.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.liveTemplates; 2 | 3 | import com.intellij.codeInsight.template.TemplateActionContext; 4 | import com.intellij.codeInsight.template.TemplateContextType; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiFile; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | public class LatteTemplateContext extends TemplateContextType { 11 | protected LatteTemplateContext() { 12 | super("LATTE", "Latte"); 13 | } 14 | 15 | @Override 16 | public boolean isInContext(@NotNull TemplateActionContext templateActionContext) { 17 | return templateActionContext.getFile().getName().endsWith(".latte"); 18 | } 19 | 20 | @Override 21 | public @Nullable TemplateContextType getBaseContextType() { 22 | return super.getBaseContextType(); 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/liveTemplates/LatteTemplatePreprocessor.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.liveTemplates; 2 | 3 | import com.intellij.codeInsight.template.impl.TemplatePreprocessor; 4 | import com.intellij.openapi.editor.Editor; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiFile; 7 | import org.nette.latte.psi.LatteMacroContent; 8 | import org.nette.latte.psi.LatteTypes; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | public class LatteTemplatePreprocessor implements TemplatePreprocessor { 12 | 13 | @Override 14 | public void preprocessTemplate(Editor editor, PsiFile file, int caretOffset, String textToInsert, String templateText) { 15 | if (!textToInsert.endsWith("}")) { 16 | return; 17 | } 18 | 19 | PsiElement el = file.findElementAt(caretOffset); 20 | if (el == null) { 21 | return; 22 | } 23 | 24 | PsiElement nextCloseTag = getNextElementTagClose(el); 25 | if (nextCloseTag != null) { 26 | editor.getDocument().replaceString(caretOffset, caretOffset + 1, ""); 27 | } 28 | } 29 | 30 | @Nullable 31 | private PsiElement getNextElementTagClose(PsiElement element) { 32 | PsiElement next = element.getNextSibling(); 33 | while (next != null) { 34 | if (next instanceof LatteMacroContent || next.getNode().getElementType() == LatteTypes.T_MACRO_NAME) { 35 | next = next.getNextSibling(); 36 | continue; 37 | 38 | } else if (next.getNode().getElementType() == LatteTypes.T_MACRO_TAG_CLOSE) { 39 | return next; 40 | } 41 | break; 42 | } 43 | return null; 44 | } 45 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/parser/LatteElementTypes.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.parser; 2 | 3 | import com.intellij.lang.*; 4 | import com.intellij.openapi.project.Project; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.tree.ILightStubFileElementType; 7 | import com.intellij.util.diff.FlyweightCapableTreeStructure; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.nette.latte.LatteLanguage; 10 | import org.nette.latte.indexes.stubs.LatteFileStub; 11 | 12 | public class LatteElementTypes { 13 | public static LatteLanguage LANG = LatteLanguage.INSTANCE; 14 | 15 | public static final ILightStubFileElementType FILE = new ILightStubFileElementType<>(LANG) { 16 | @NotNull 17 | @Override 18 | public String getExternalId() { 19 | return "latte." + super.getExternalId(); 20 | } 21 | 22 | @Override 23 | public FlyweightCapableTreeStructure parseContentsLight(ASTNode chameleon) { 24 | PsiElement psi = chameleon.getPsi(); 25 | assert psi != null : "Bad chameleon: " + chameleon; 26 | 27 | Project project = psi.getProject(); 28 | PsiBuilderFactory factory = PsiBuilderFactory.getInstance(); 29 | PsiBuilder builder = factory.createBuilder(project, chameleon); 30 | ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(getLanguage()); 31 | assert parserDefinition != null : this; 32 | 33 | LatteParser parser = new LatteParser(); 34 | parser.parseLight(this, builder); 35 | return builder.getLightTree(); 36 | } 37 | }; 38 | 39 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/parser/LatteParserDefinition.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.parser; 2 | 3 | import com.intellij.lang.*; 4 | import com.intellij.lexer.Lexer; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.psi.FileViewProvider; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiFile; 9 | import com.intellij.psi.TokenType; 10 | import com.intellij.psi.tree.IFileElementType; 11 | import com.intellij.psi.tree.TokenSet; 12 | import org.nette.latte.lexer.LatteLexer; 13 | import org.nette.latte.lexer.LatteLookAheadLexer; 14 | import org.nette.latte.psi.LatteFile; 15 | import org.nette.latte.psi.LatteTypes; 16 | import org.jetbrains.annotations.NotNull; 17 | 18 | public class LatteParserDefinition implements ParserDefinition { 19 | public static final TokenSet WHITE_SPACES = TokenSet.create(LatteTypes.T_WHITESPACE, TokenType.WHITE_SPACE); 20 | public static final TokenSet COMMENTS = TokenSet.create(LatteTypes.T_MACRO_COMMENT); 21 | public static final TokenSet STRINGS = TokenSet.create(LatteTypes.T_MACRO_ARGS_STRING); 22 | 23 | @NotNull 24 | @Override 25 | public Lexer createLexer(Project project) { 26 | return new LatteLookAheadLexer(new LatteLexer()); 27 | } 28 | 29 | @Override 30 | public PsiParser createParser(Project project) { 31 | return new LatteParser(); 32 | } 33 | 34 | @Override 35 | public IFileElementType getFileNodeType() { 36 | return LatteElementTypes.FILE; 37 | } 38 | 39 | @NotNull 40 | @Override 41 | public TokenSet getWhitespaceTokens() { 42 | return WHITE_SPACES; 43 | } 44 | 45 | @NotNull 46 | @Override 47 | public TokenSet getCommentTokens() { 48 | return COMMENTS; 49 | } 50 | 51 | @NotNull 52 | @Override 53 | public TokenSet getStringLiteralElements() { 54 | return STRINGS; 55 | } 56 | 57 | @NotNull 58 | @Override 59 | public PsiElement createElement(ASTNode node) { 60 | return LatteTypes.Factory.createElement(node); 61 | } 62 | 63 | @Override 64 | public PsiFile createFile(FileViewProvider viewProvider) { 65 | return new LatteFile(viewProvider); 66 | } 67 | 68 | @Override 69 | public SpaceRequirements spaceExistenceTypeBetweenTokens(ASTNode left, ASTNode right) { 70 | return SpaceRequirements.MAY; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/ErrorFilter.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi; 2 | 3 | import com.intellij.codeInsight.highlighting.HighlightErrorFilter; 4 | import com.intellij.lang.Language; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiErrorElement; 7 | import com.intellij.psi.PsiFile; 8 | import com.intellij.psi.PsiWhiteSpace; 9 | import com.intellij.psi.templateLanguages.OuterLanguageElement; 10 | import com.intellij.psi.util.PsiTreeUtil; 11 | import com.intellij.psi.util.PsiUtilCore; 12 | import com.intellij.psi.xml.XmlElement; 13 | import org.nette.latte.LatteLanguage; 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | public class ErrorFilter extends HighlightErrorFilter { 17 | public ErrorFilter() { 18 | } 19 | 20 | public boolean shouldHighlightErrorElement(@NotNull PsiErrorElement element) { 21 | PsiFile templateLanguageFile = PsiUtilCore.getTemplateLanguageFile(element.getContainingFile()); 22 | if (templateLanguageFile == null) { 23 | return true; 24 | } 25 | Language language = templateLanguageFile.getLanguage(); 26 | if (language != LatteLanguage.INSTANCE) { 27 | return true; 28 | } 29 | if (element.getParent() instanceof XmlElement) { 30 | return false; 31 | } 32 | if (element.getParent().getLanguage() == LatteLanguage.INSTANCE) { 33 | return true; 34 | } 35 | PsiElement nextSibling; 36 | for (nextSibling = PsiTreeUtil.nextLeaf(element); nextSibling instanceof PsiWhiteSpace; nextSibling = nextSibling.getNextSibling()); 37 | 38 | PsiElement psiElement = nextSibling == null ? null : PsiTreeUtil.findCommonParent(nextSibling, element); 39 | boolean nextIsOuterLanguageElement = nextSibling instanceof OuterLanguageElement || nextSibling instanceof LatteMacroClassic; 40 | return !nextIsOuterLanguageElement || psiElement == null || psiElement instanceof PsiFile; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/LatteElementType.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi; 2 | 3 | import com.intellij.psi.tree.IElementType; 4 | import org.nette.latte.LatteLanguage; 5 | import org.jetbrains.annotations.NonNls; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public class LatteElementType extends IElementType { 9 | public LatteElementType(@NotNull @NonNls String debugName) { 10 | super(debugName, LatteLanguage.INSTANCE); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/LatteFileViewProviderFactory.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi; 2 | 3 | import com.intellij.lang.Language; 4 | import com.intellij.openapi.vfs.VirtualFile; 5 | import com.intellij.psi.FileViewProvider; 6 | import com.intellij.psi.FileViewProviderFactory; 7 | import com.intellij.psi.PsiManager; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | public class LatteFileViewProviderFactory implements FileViewProviderFactory { 11 | 12 | @NotNull 13 | @Override 14 | public FileViewProvider createFileViewProvider(@NotNull VirtualFile file, Language language, @NotNull PsiManager manager, boolean eventSystemEnabled) { 15 | return new LatteFileViewProvider(manager, file, eventSystemEnabled); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/LatteIndexPatternBuilder.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi; 2 | 3 | import com.intellij.lexer.LayeredLexer; 4 | import com.intellij.lexer.Lexer; 5 | import com.intellij.openapi.editor.highlighter.EditorHighlighter; 6 | import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory; 7 | import com.intellij.openapi.vfs.VirtualFile; 8 | import com.intellij.psi.PsiFile; 9 | import com.intellij.psi.impl.search.IndexPatternBuilder; 10 | import com.intellij.psi.impl.search.LexerEditorHighlighterLexer; 11 | import com.intellij.psi.tree.IElementType; 12 | import com.intellij.psi.tree.TokenSet; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | 17 | public class LatteIndexPatternBuilder implements IndexPatternBuilder { 18 | 19 | @Nullable 20 | @Override 21 | public Lexer getIndexingLexer(@NotNull PsiFile file) { 22 | if (!(file instanceof LatteFile)) { 23 | return null; 24 | } 25 | VirtualFile virtualFile = file.getVirtualFile(); 26 | if (virtualFile == null) { 27 | virtualFile = file.getViewProvider().getVirtualFile(); 28 | } 29 | 30 | try { 31 | LayeredLexer.ourDisableLayersFlag.set(Boolean.TRUE); 32 | EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(file.getProject(), virtualFile); 33 | return new LexerEditorHighlighterLexer(highlighter, false); 34 | } finally { 35 | LayeredLexer.ourDisableLayersFlag.set(Boolean.FALSE); 36 | } 37 | } 38 | 39 | @Nullable 40 | @Override 41 | public TokenSet getCommentTokenSet(@NotNull PsiFile file) { 42 | return TokenSet.create(LatteTypes.T_MACRO_COMMENT); 43 | } 44 | 45 | @Override 46 | public int getCommentStartDelta(IElementType tokenType) { 47 | return 0; 48 | } 49 | 50 | @Override 51 | public int getCommentEndDelta(IElementType tokenType) { 52 | if (tokenType == LatteTypes.T_MACRO_COMMENT) { 53 | return 2; 54 | } 55 | return 0; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/LatteOuterElementType.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.psi.templateLanguages.OuterLanguageElementImpl; 5 | import com.intellij.psi.tree.IElementType; 6 | import com.intellij.psi.tree.ILeafElementType; 7 | import org.nette.latte.LatteLanguage; 8 | import org.jetbrains.annotations.NonNls; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class LatteOuterElementType extends IElementType implements ILeafElementType { 12 | public LatteOuterElementType(@NotNull @NonNls String debugName) { 13 | super(debugName, LatteLanguage.INSTANCE); 14 | } 15 | 16 | public @NotNull 17 | ASTNode createLeafNode(@NotNull CharSequence charSequence) { 18 | return new OuterLanguageElementImpl(this, charSequence); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/LatteTemplateDataElementType.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi; 2 | 3 | import com.intellij.lang.Language; 4 | import com.intellij.lexer.Lexer; 5 | import com.intellij.openapi.util.TextRange; 6 | import com.intellij.openapi.util.text.StringUtil; 7 | import com.intellij.psi.templateLanguages.TemplateDataElementType; 8 | import com.intellij.psi.tree.IElementType; 9 | import com.intellij.psi.tree.TokenSet; 10 | import org.jetbrains.annotations.NonNls; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | public class LatteTemplateDataElementType extends TemplateDataElementType { 14 | 15 | private final TokenSet elementTypesSet; 16 | 17 | public LatteTemplateDataElementType(@NonNls String debugName, 18 | Language language, 19 | @NotNull TokenSet htmlTemplateElementType, 20 | @NotNull IElementType outerElementType) { 21 | super(debugName, language, htmlTemplateElementType.getTypes()[0], outerElementType); 22 | elementTypesSet = htmlTemplateElementType; 23 | } 24 | 25 | protected CharSequence createTemplateText(@NotNull CharSequence sourceCode, 26 | @NotNull Lexer baseLexer, 27 | @NotNull RangeCollector rangeCollector) { 28 | StringBuilder result = new StringBuilder(sourceCode.length()); 29 | baseLexer.start(sourceCode); 30 | 31 | TextRange currentRange = TextRange.EMPTY_RANGE; 32 | while (baseLexer.getTokenType() != null) { 33 | TextRange newRange = TextRange.create(baseLexer.getTokenStart(), baseLexer.getTokenEnd()); 34 | assert currentRange.getEndOffset() == newRange.getStartOffset() : 35 | "Inconsistent tokens stream from " + baseLexer + 36 | ": " + getRangeDump(currentRange, sourceCode) + " followed by " + getRangeDump(newRange, sourceCode); 37 | currentRange = newRange; 38 | if (elementTypesSet.contains(baseLexer.getTokenType())) { 39 | result.append(sourceCode, baseLexer.getTokenStart(), baseLexer.getTokenEnd()); 40 | appendCurrentTemplateToken(baseLexer.getTokenEnd(), sourceCode); 41 | } 42 | else { 43 | rangeCollector.addOuterRange(currentRange); 44 | } 45 | baseLexer.advance(); 46 | } 47 | 48 | return result; 49 | } 50 | 51 | @NotNull 52 | private static String getRangeDump(@NotNull TextRange range, @NotNull CharSequence sequence) { 53 | return "'" + StringUtil.escapeLineBreak(range.subSequence(sequence).toString()) + "' " + range; 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/LatteTokenType.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi; 2 | 3 | import com.intellij.psi.tree.IElementType; 4 | import org.nette.latte.LatteLanguage; 5 | import org.jetbrains.annotations.NonNls; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public class LatteTokenType extends IElementType { 9 | public LatteTokenType(@NotNull @NonNls String debugName) { 10 | super(debugName, LatteLanguage.INSTANCE); 11 | } 12 | 13 | @Override 14 | public String toString() { 15 | return "LatteTokenType." + super.toString(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/BaseLattePhpElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import org.nette.latte.php.LattePhpTypeDetector; 5 | import org.nette.latte.php.NettePhpType; 6 | import org.nette.latte.psi.LattePhpArrayUsage; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | public interface BaseLattePhpElement extends LattePsiNamedElement { 14 | 15 | default @NotNull List getPhpArrayUsageList() { 16 | return Collections.emptyList(); 17 | } 18 | 19 | default NettePhpType getPrevReturnType() { 20 | return getReturnType(); 21 | } 22 | 23 | default NettePhpType getReturnType() { 24 | return LattePhpTypeDetector.detectPhpType(this); 25 | } 26 | 27 | String getPhpElementName(); 28 | 29 | int getPhpArrayLevel(); 30 | 31 | @Nullable PsiElement getTextElement(); 32 | 33 | @Nullable LattePhpStatementPartElement getPhpStatementPart(); 34 | 35 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LatteFilePathElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.util.IncorrectOperationException; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | public interface LatteFilePathElement extends LattePsiNamedElement { 8 | @Override 9 | default PsiElement setName(@NotNull String name) throws IncorrectOperationException { 10 | return this; 11 | } 12 | 13 | @NotNull 14 | String getFilePath(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LatteHtmlTagContainerElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import org.nette.latte.psi.LatteHtmlOpenTag; 4 | 5 | public interface LatteHtmlTagContainerElement extends LattePsiElement { 6 | 7 | LatteHtmlOpenTag getHtmlOpenTag(); 8 | 9 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LatteLinkDestinationElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.util.IncorrectOperationException; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | public interface LatteLinkDestinationElement extends LattePsiNamedElement { 8 | @Override 9 | default PsiElement setName(@NotNull String name) throws IncorrectOperationException { 10 | return this; 11 | } 12 | 13 | @NotNull 14 | String getLinkDestination(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LatteMacroContentElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import org.nette.latte.psi.LattePhpContent; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import java.util.List; 9 | 10 | public interface LatteMacroContentElement extends LattePsiElement { 11 | 12 | @Nullable LattePhpContent getFirstPhpContent(); 13 | 14 | @NotNull 15 | List getPhpContentList(); 16 | 17 | @Nullable PsiElement getMacroNameElement(); 18 | 19 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LatteMacroModifierElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.psi.StubBasedPsiElement; 5 | import com.intellij.util.IncorrectOperationException; 6 | import org.nette.latte.indexes.stubs.LatteFilterStub; 7 | import org.nette.latte.settings.LatteFilterSettings; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | public interface LatteMacroModifierElement extends LattePsiNamedElement, StubBasedPsiElement { 12 | 13 | @Override 14 | default PsiElement setName(@NotNull String name) throws IncorrectOperationException { 15 | return this; 16 | } 17 | 18 | String getModifierName(); 19 | 20 | @Nullable 21 | LatteFilterSettings getMacroModifier(); 22 | 23 | @Nullable PsiElement getTextElement(); 24 | 25 | boolean isVariableModifier(); 26 | 27 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LatteMacroTagElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.util.IncorrectOperationException; 5 | import org.nette.latte.psi.LatteMacroContent; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | public interface LatteMacroTagElement extends LattePsiNamedElement { 10 | 11 | @Override 12 | default PsiElement setName(@NotNull String name) throws IncorrectOperationException { 13 | return this; 14 | } 15 | 16 | @NotNull String getMacroName(); 17 | 18 | int getMacroNameLength(); 19 | 20 | @Nullable 21 | LatteMacroContent getMacroContent(); 22 | 23 | boolean matchMacroName(@NotNull String name); 24 | 25 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePairMacroElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import org.nette.latte.psi.LatteMacroTag; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import java.util.List; 8 | 9 | public interface LattePairMacroElement extends LattePsiElement { 10 | 11 | @NotNull 12 | List getMacroTagList(); 13 | 14 | @Nullable 15 | LatteMacroTag getMacroOpenTag(); 16 | 17 | @NotNull 18 | LatteMacroTag getOpenTag(); 19 | 20 | @Nullable 21 | LatteMacroTag getCloseTag(); 22 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePhpClassReferenceElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.StubBasedPsiElement; 4 | import org.nette.latte.indexes.stubs.LattePhpClassStub; 5 | import org.nette.latte.psi.LattePhpClassUsage; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public interface LattePhpClassReferenceElement extends BaseLattePhpElement, StubBasedPsiElement { 9 | 10 | String getClassName(); 11 | 12 | @NotNull 13 | LattePhpClassUsage getPhpClassUsage(); 14 | 15 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePhpClassUsageElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | public interface LattePhpClassUsageElement extends BaseLattePhpElement { 4 | 5 | String getClassName(); 6 | 7 | boolean isTemplateType(); 8 | 9 | void reset(); 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePhpConstantElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.StubBasedPsiElement; 4 | import org.nette.latte.indexes.stubs.LattePhpConstantStub; 5 | import org.nette.latte.php.LattePhpTypeDetector; 6 | import org.nette.latte.php.NettePhpType; 7 | 8 | public interface LattePhpConstantElement extends BaseLattePhpElement, StubBasedPsiElement { 9 | 10 | default NettePhpType getPrevReturnType() { 11 | return LattePhpTypeDetector.detectPrevPhpType(this); 12 | } 13 | 14 | String getConstantName(); 15 | 16 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePhpExpressionElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import org.nette.latte.php.NettePhpType; 4 | import org.nette.latte.psi.LattePhpStatement; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.List; 8 | 9 | public interface LattePhpExpressionElement extends LattePsiElement { 10 | 11 | @NotNull 12 | NettePhpType getReturnType(); 13 | 14 | @NotNull 15 | List getPhpStatementList(); 16 | 17 | int getPhpArrayLevel(); 18 | 19 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePhpMethodElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.StubBasedPsiElement; 4 | import org.nette.latte.indexes.stubs.LattePhpMethodStub; 5 | import org.nette.latte.php.LattePhpTypeDetector; 6 | import org.nette.latte.php.NettePhpType; 7 | 8 | public interface LattePhpMethodElement extends BaseLattePhpElement, StubBasedPsiElement { 9 | 10 | default NettePhpType getPrevReturnType() { 11 | return LattePhpTypeDetector.detectPrevPhpType(this); 12 | } 13 | 14 | String getMethodName(); 15 | 16 | boolean isStatic(); 17 | 18 | boolean isFunction(); 19 | 20 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePhpNamespaceReferenceElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.StubBasedPsiElement; 4 | import org.nette.latte.indexes.stubs.LattePhpNamespaceStub; 5 | 6 | public interface LattePhpNamespaceReferenceElement extends BaseLattePhpElement, StubBasedPsiElement { 7 | 8 | public abstract String getNamespaceName(); 9 | 10 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePhpPropertyElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.StubBasedPsiElement; 4 | import org.nette.latte.indexes.stubs.LattePhpPropertyStub; 5 | import org.nette.latte.php.LattePhpTypeDetector; 6 | import org.nette.latte.php.NettePhpType; 7 | 8 | public interface LattePhpPropertyElement extends BaseLattePhpElement, StubBasedPsiElement { 9 | 10 | default NettePhpType getPrevReturnType() { 11 | return LattePhpTypeDetector.detectPrevPhpType(this); 12 | } 13 | 14 | String getPropertyName(); 15 | 16 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePhpStatementElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import org.nette.latte.php.NettePhpType; 4 | import org.nette.latte.psi.LattePhpStatementFirstPart; 5 | import org.nette.latte.psi.LattePhpStatementPart; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import java.util.List; 10 | 11 | public interface LattePhpStatementElement extends LattePsiElement { 12 | 13 | @NotNull LattePhpStatementFirstPart getPhpStatementFirstPart(); 14 | 15 | @NotNull List getPhpStatementPartList(); 16 | 17 | NettePhpType getReturnType(); 18 | 19 | boolean isPhpVariableOnly(); 20 | 21 | boolean isPhpClassReferenceOnly(); 22 | 23 | @Nullable BaseLattePhpElement getLastPhpElement(); 24 | 25 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePhpStatementPartElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import org.nette.latte.php.LattePhpTypeDetector; 4 | import org.nette.latte.php.NettePhpType; 5 | import org.nette.latte.psi.LattePhpStatement; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | public interface LattePhpStatementPartElement extends LattePsiElement { 10 | 11 | default @NotNull NettePhpType getReturnType() { 12 | return LattePhpTypeDetector.detectPhpType(this); 13 | } 14 | 15 | @NotNull LattePhpStatement getPhpStatement(); 16 | 17 | @Nullable LattePhpStatementPartElement getPrevPhpStatementPart(); 18 | 19 | @Nullable BaseLattePhpElement getPhpElement(); 20 | 21 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePhpStaticVariableElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.StubBasedPsiElement; 4 | import org.nette.latte.indexes.stubs.LattePhpStaticVariableStub; 5 | import org.nette.latte.php.LattePhpTypeDetector; 6 | import org.nette.latte.php.NettePhpType; 7 | 8 | public interface LattePhpStaticVariableElement extends BaseLattePhpElement, StubBasedPsiElement { 9 | 10 | default NettePhpType getPrevReturnType() { 11 | return LattePhpTypeDetector.detectPrevPhpType(this); 12 | } 13 | 14 | String getVariableName(); 15 | 16 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePhpTypeElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.StubBasedPsiElement; 4 | import org.nette.latte.indexes.stubs.LattePhpTypeStub; 5 | import org.nette.latte.php.NettePhpType; 6 | import org.nette.latte.psi.LattePhpTypePart; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.util.List; 10 | 11 | public interface LattePhpTypeElement extends LattePsiElement, StubBasedPsiElement { 12 | 13 | @NotNull 14 | List getPhpTypePartList(); 15 | 16 | @NotNull 17 | NettePhpType getReturnType(); 18 | 19 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePhpTypedPartElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import org.nette.latte.php.LattePhpTypeDetector; 4 | import org.nette.latte.php.NettePhpType; 5 | import org.nette.latte.psi.LattePhpType; 6 | import org.nette.latte.psi.LattePhpVariable; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | public interface LattePhpTypedPartElement extends LattePsiElement { 11 | 12 | @Nullable 13 | LattePhpType getPhpType(); 14 | 15 | @NotNull 16 | LattePhpVariable getPhpVariable(); 17 | 18 | default @NotNull NettePhpType getReturnType() { 19 | return LattePhpTypeDetector.detectPhpType(this); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePhpVariableElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import org.nette.latte.utils.LattePhpCachedVariable; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import java.util.List; 9 | 10 | public interface LattePhpVariableElement extends BaseLattePhpElement { 11 | 12 | String getVariableName(); 13 | 14 | @Nullable LattePhpCachedVariable getCachedVariable(); 15 | 16 | boolean isDefinition(); 17 | 18 | @Nullable PsiElement getVariableContext(); 19 | 20 | @NotNull List getVariableDefinition(); 21 | 22 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePsiElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import org.nette.latte.psi.LatteFile; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | public interface LattePsiElement extends PsiElement { 8 | 9 | @Nullable LatteFile getLatteFile(); 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/elements/LattePsiNamedElement.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.elements; 2 | 3 | import com.intellij.psi.PsiNameIdentifierOwner; 4 | 5 | public interface LattePsiNamedElement extends PsiNameIdentifierOwner, LattePsiElement { 6 | 7 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/LattePhpElementImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.psi.PsiElement; 5 | import org.nette.latte.psi.elements.BaseLattePhpElement; 6 | import org.nette.latte.psi.elements.LattePhpStatementPartElement; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | public abstract class LattePhpElementImpl extends LatteReferencedElementImpl implements BaseLattePhpElement { 11 | 12 | public LattePhpElementImpl(@NotNull ASTNode node) { 13 | super(node); 14 | } 15 | 16 | @Override 17 | public String getName() { 18 | return getPhpElementName(); 19 | } 20 | 21 | @Override 22 | public @Nullable PsiElement getTextElement() { 23 | return getNameIdentifier(); 24 | } 25 | 26 | public int getPhpArrayLevel() { 27 | return this.getPhpArrayUsageList().size(); 28 | } 29 | 30 | @Override 31 | public @Nullable LattePhpStatementPartElement getPhpStatementPart() { 32 | PsiElement parent = this.getParent(); 33 | return parent instanceof LattePhpStatementPartElement ? (LattePhpStatementPartElement) parent : null; 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/LattePsiElementImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl; 2 | 3 | import com.intellij.extapi.psi.ASTWrapperPsiElement; 4 | import com.intellij.lang.ASTNode; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.psi.PsiFile; 7 | import org.nette.latte.psi.LatteFile; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | public abstract class LattePsiElementImpl extends ASTWrapperPsiElement { 12 | 13 | private Project project = null; 14 | private LatteFile file = null; 15 | 16 | public LattePsiElementImpl(@NotNull ASTNode node) { 17 | super(node); 18 | } 19 | 20 | public @Nullable LatteFile getLatteFile() { 21 | if (file == null) { 22 | PsiFile containingFile = getContainingFile(); 23 | file = containingFile instanceof LatteFile ? (LatteFile) containingFile : null; 24 | } 25 | return file; 26 | } 27 | 28 | @Override 29 | public @NotNull Project getProject() { 30 | if (project == null) { 31 | project = super.getProject(); 32 | } 33 | return project; 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/LatteReferencedElementImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl; 2 | 3 | import com.intellij.extapi.psi.ASTWrapperPsiElement; 4 | import com.intellij.lang.ASTNode; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.psi.PsiFile; 7 | import com.intellij.psi.PsiReference; 8 | import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; 9 | import org.nette.latte.psi.LatteFile; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | public abstract class LatteReferencedElementImpl extends ASTWrapperPsiElement { 14 | 15 | private Project project = null; 16 | private LatteFile file = null; 17 | 18 | public LatteReferencedElementImpl(@NotNull ASTNode node) { 19 | super(node); 20 | } 21 | 22 | public @Nullable LatteFile getLatteFile() { 23 | if (file == null) { 24 | PsiFile containingFile = getContainingFile(); 25 | file = containingFile instanceof LatteFile ? (LatteFile) containingFile : null; 26 | } 27 | return file; 28 | } 29 | 30 | @Override 31 | public @NotNull Project getProject() { 32 | if (project == null) { 33 | project = super.getProject(); 34 | } 35 | return project; 36 | } 37 | 38 | public @Nullable PsiReference getReference() { 39 | PsiReference[] references = getReferences(); 40 | return references.length == 0 ? null : references[0]; 41 | } 42 | 43 | public @NotNull PsiReference[] getReferences() { 44 | return ReferenceProvidersRegistry.getReferencesFromProviders(this); 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/LatteStubElementImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.openapi.project.Project; 5 | import com.intellij.psi.PsiReference; 6 | import com.intellij.psi.StubBasedPsiElement; 7 | import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; 8 | import com.intellij.psi.stubs.IStubElementType; 9 | import com.intellij.psi.stubs.StubElement; 10 | import org.nette.latte.indexes.LatteStubBasedPsiElement; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | 14 | public abstract class LatteStubElementImpl extends LatteStubBasedPsiElement implements StubBasedPsiElement { 15 | 16 | private Project project = null; 17 | 18 | public LatteStubElementImpl(@NotNull ASTNode node) { 19 | super(node); 20 | } 21 | 22 | public LatteStubElementImpl(final T stub, final IStubElementType nodeType) { 23 | super(stub, nodeType); 24 | } 25 | 26 | @Override 27 | public @NotNull Project getProject() { 28 | if (project == null) { 29 | project = super.getProject(); 30 | } 31 | return project; 32 | } 33 | 34 | @Nullable 35 | public PsiReference getReference() { 36 | PsiReference[] references = getReferences(); 37 | return references.length == 0 ? null : references[0]; 38 | } 39 | 40 | @NotNull 41 | public PsiReference[] getReferences() { 42 | return ReferenceProvidersRegistry.getReferencesFromProviders(this); 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/LatteStubPhpElementImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.StubBasedPsiElement; 6 | import com.intellij.psi.stubs.IStubElementType; 7 | import com.intellij.psi.stubs.StubElement; 8 | import org.nette.latte.psi.elements.BaseLattePhpElement; 9 | import org.nette.latte.psi.elements.LattePhpStatementPartElement; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | public abstract class LatteStubPhpElementImpl extends LatteStubElementImpl implements BaseLattePhpElement, StubBasedPsiElement { 14 | 15 | public LatteStubPhpElementImpl(@NotNull ASTNode node) { 16 | super(node); 17 | } 18 | 19 | public LatteStubPhpElementImpl(final T stub, final IStubElementType nodeType) { 20 | super(stub, nodeType); 21 | } 22 | 23 | @Override 24 | public String getName() { 25 | return getPhpElementName(); 26 | } 27 | 28 | @Override 29 | public @Nullable PsiElement getTextElement() { 30 | return getNameIdentifier(); 31 | } 32 | 33 | public int getPhpArrayLevel() { 34 | return this.getPhpArrayUsageList().size(); 35 | } 36 | 37 | @Override 38 | public @Nullable LattePhpStatementPartElement getPhpStatementPart() { 39 | PsiElement parent = this.getParent(); 40 | return parent instanceof LattePhpStatementPartElement ? (LattePhpStatementPartElement) parent : null; 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/elements/LatteHtmlTagContainerImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl.elements; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.nette.latte.psi.LatteHtmlOpenTag; 5 | import org.nette.latte.psi.elements.LatteHtmlTagContainerElement; 6 | import org.nette.latte.psi.impl.LattePsiElementImpl; 7 | import org.nette.latte.psi.impl.LattePsiImplUtil; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | public abstract class LatteHtmlTagContainerImpl extends LattePsiElementImpl implements LatteHtmlTagContainerElement { 11 | 12 | public LatteHtmlTagContainerImpl(@NotNull ASTNode node) { 13 | super(node); 14 | } 15 | 16 | @Override 17 | public LatteHtmlOpenTag getHtmlOpenTag() { 18 | return LattePsiImplUtil.getHtmlOpenTag(this); 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/elements/LatteMacroContentImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl.elements; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.psi.PsiElement; 5 | import org.nette.latte.psi.LattePhpContent; 6 | import org.nette.latte.psi.elements.LatteMacroContentElement; 7 | import org.nette.latte.psi.impl.LattePsiElementImpl; 8 | import org.nette.latte.psi.impl.LattePsiImplUtil; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | public abstract class LatteMacroContentImpl extends LattePsiElementImpl implements LatteMacroContentElement { 13 | 14 | public LatteMacroContentImpl(@NotNull ASTNode node) { 15 | super(node); 16 | } 17 | 18 | @Override 19 | public @Nullable LattePhpContent getFirstPhpContent() { 20 | return LattePsiImplUtil.getFirstPhpContent(this); 21 | } 22 | 23 | @Override 24 | public @Nullable PsiElement getMacroNameElement() { 25 | return LattePsiImplUtil.getMacroNameElement(this); 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/elements/LatteMacroTagElementImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl.elements; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.psi.PsiElement; 5 | import org.nette.latte.icons.LatteIcons; 6 | import org.nette.latte.psi.LatteMacroContent; 7 | import org.nette.latte.psi.elements.LatteMacroTagElement; 8 | import org.nette.latte.psi.impl.LatteReferencedElementImpl; 9 | import org.nette.latte.psi.impl.LattePsiImplUtil; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | import org.nette.latte.psi.LatteTypes; 13 | 14 | import javax.swing.*; 15 | 16 | public abstract class LatteMacroTagElementImpl extends LatteReferencedElementImpl implements LatteMacroTagElement { 17 | 18 | private @Nullable String tagName = null; 19 | private @Nullable PsiElement identifier = null; 20 | private int macroNameLength = -1; 21 | 22 | public LatteMacroTagElementImpl(@NotNull ASTNode node) { 23 | super(node); 24 | } 25 | 26 | @Override 27 | public void subtreeChanged() { 28 | super.subtreeChanged(); 29 | tagName = null; 30 | identifier = null; 31 | macroNameLength = -1; 32 | } 33 | 34 | @Nullable 35 | public LatteMacroContent getMacroContent() { 36 | return findChildByClass(LatteMacroContent.class); 37 | } 38 | 39 | @Override 40 | public @Nullable Icon getIcon(int flags) { 41 | return LatteIcons.MACRO; 42 | } 43 | 44 | @Override 45 | public @NotNull String getMacroName() { 46 | if (tagName == null) { 47 | tagName = LattePsiImplUtil.getMacroName(this); 48 | } 49 | return tagName; 50 | } 51 | 52 | @Override 53 | public String getName() { 54 | return getMacroName(); 55 | } 56 | 57 | @Override 58 | public @Nullable PsiElement getNameIdentifier() { 59 | if (identifier == null) { 60 | identifier = LattePsiImplUtil.findFirstChildWithType(this, LatteTypes.T_MACRO_NAME); 61 | } 62 | return identifier; 63 | } 64 | 65 | public boolean matchMacroName(@NotNull String name) { 66 | return LattePsiImplUtil.matchMacroName(this, name); 67 | } 68 | 69 | @Override 70 | public int getMacroNameLength() { 71 | if (macroNameLength == -1) { 72 | macroNameLength = LattePsiImplUtil.getMacroNameLength(this); 73 | } 74 | return macroNameLength; 75 | } 76 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/elements/LatteMacroTagImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl.elements; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.nette.latte.psi.LatteMacroTag; 5 | import org.nette.latte.psi.elements.LattePairMacroElement; 6 | import org.nette.latte.psi.impl.LattePsiElementImpl; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | public abstract class LatteMacroTagImpl extends LattePsiElementImpl implements LattePairMacroElement { 11 | 12 | public LatteMacroTagImpl(@NotNull ASTNode node) { 13 | super(node); 14 | } 15 | 16 | @Nullable 17 | public LatteMacroTag getMacroOpenTag() { 18 | return getMacroTagList().stream().findFirst().orElse(null); 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/elements/LattePairMacroImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl.elements; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.psi.util.PsiTreeUtil; 5 | import org.nette.latte.psi.LatteMacroTag; 6 | import org.nette.latte.psi.elements.LattePairMacroElement; 7 | import org.nette.latte.psi.impl.LattePsiElementImpl; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.util.List; 12 | 13 | public abstract class LattePairMacroImpl extends LattePsiElementImpl implements LattePairMacroElement { 14 | 15 | public LattePairMacroImpl(@NotNull ASTNode node) { 16 | super(node); 17 | } 18 | 19 | @Override 20 | public @NotNull List getMacroTagList() { 21 | return PsiTreeUtil.getChildrenOfTypeAsList(this, LatteMacroTag.class); 22 | } 23 | 24 | @Nullable 25 | public LatteMacroTag getMacroOpenTag() { 26 | return getMacroTagList().stream().findFirst().orElse(null); 27 | } 28 | 29 | @Override 30 | public @Nullable LatteMacroTag getCloseTag() { 31 | List tags = getMacroTagList(); 32 | return tags.size() < 2 ? null : tags.get(1); 33 | } 34 | 35 | public @NotNull LatteMacroTag getOpenTag() { 36 | return getMacroTagList().get(0); 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/elements/LattePhpClassReferenceElementImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl.elements; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.stubs.IStubElementType; 6 | import com.intellij.util.IncorrectOperationException; 7 | import org.nette.latte.indexes.stubs.LattePhpClassStub; 8 | import org.nette.latte.psi.elements.LattePhpClassReferenceElement; 9 | import org.nette.latte.psi.impl.LatteStubPhpElementImpl; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | public abstract class LattePhpClassReferenceElementImpl extends LatteStubPhpElementImpl implements LattePhpClassReferenceElement { 14 | 15 | private @Nullable String name = null; 16 | private @Nullable String className = null; 17 | 18 | public LattePhpClassReferenceElementImpl(@NotNull ASTNode node) { 19 | super(node); 20 | } 21 | 22 | public LattePhpClassReferenceElementImpl(final LattePhpClassStub stub, final IStubElementType nodeType) { 23 | super(stub, nodeType); 24 | } 25 | 26 | @Override 27 | public void subtreeChanged() { 28 | super.subtreeChanged(); 29 | name = null; 30 | className = null; 31 | getPhpClassUsage().reset(); 32 | } 33 | 34 | @Override 35 | public String getPhpElementName() 36 | { 37 | return getClassName(); 38 | } 39 | 40 | @Override 41 | public @Nullable PsiElement getNameIdentifier() { 42 | return getPhpClassUsage().getNameIdentifier(); 43 | } 44 | 45 | @Override 46 | public String getClassName() { 47 | if (className == null) { 48 | final LattePhpClassStub stub = getStub(); 49 | if (stub != null) { 50 | className = stub.getClassName(); 51 | return className; 52 | } 53 | className = getPhpClassUsage().getClassName(); 54 | } 55 | return className; 56 | } 57 | 58 | @Override 59 | public PsiElement setName(@NotNull String name) throws IncorrectOperationException { 60 | return this; 61 | } 62 | 63 | @Override 64 | public String getName() { 65 | if (name == null) { 66 | PsiElement found = getNameIdentifier(); 67 | name = found != null ? found.getText() : null; 68 | } 69 | return name; 70 | } 71 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/elements/LattePhpExpressionElementImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl.elements; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.nette.latte.php.LattePhpTypeDetector; 5 | import org.nette.latte.php.NettePhpType; 6 | import org.nette.latte.psi.LattePhpStatement; 7 | import org.nette.latte.psi.elements.BaseLattePhpElement; 8 | import org.nette.latte.psi.elements.LattePhpExpressionElement; 9 | import org.nette.latte.psi.impl.LattePsiElementImpl; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.List; 13 | 14 | public abstract class LattePhpExpressionElementImpl extends LattePsiElementImpl implements LattePhpExpressionElement { 15 | 16 | private int phpArrayLevel = -1; 17 | 18 | public LattePhpExpressionElementImpl(@NotNull ASTNode node) { 19 | super(node); 20 | } 21 | 22 | @Override 23 | public void subtreeChanged() { 24 | super.subtreeChanged(); 25 | phpArrayLevel = -1; 26 | } 27 | 28 | @Override 29 | public @NotNull NettePhpType getReturnType() { 30 | return LattePhpTypeDetector.detectPhpType(this); 31 | } 32 | 33 | @Override 34 | public int getPhpArrayLevel() { 35 | if (phpArrayLevel == -1) { 36 | List statements = getPhpStatementList(); 37 | if (statements.size() > 0) { 38 | BaseLattePhpElement phpElement = statements.get(statements.size() - 1).getLastPhpElement(); 39 | phpArrayLevel = phpElement != null ? phpElement.getPhpArrayLevel() : 0; 40 | return phpArrayLevel; 41 | } 42 | phpArrayLevel = 0; 43 | } 44 | return phpArrayLevel; 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/elements/LattePhpStatementElementImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl.elements; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.nette.latte.php.LattePhpTypeDetector; 5 | import org.nette.latte.php.NettePhpType; 6 | import org.nette.latte.psi.elements.BaseLattePhpElement; 7 | import org.nette.latte.psi.elements.LattePhpStatementElement; 8 | import org.nette.latte.psi.impl.LattePsiElementImpl; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | public abstract class LattePhpStatementElementImpl extends LattePsiElementImpl implements LattePhpStatementElement { 13 | 14 | private @Nullable BaseLattePhpElement lastPhpElement; 15 | 16 | public LattePhpStatementElementImpl(@NotNull ASTNode node) { 17 | super(node); 18 | } 19 | 20 | @Override 21 | public void subtreeChanged() { 22 | super.subtreeChanged(); 23 | lastPhpElement = null; 24 | } 25 | 26 | @Override 27 | public NettePhpType getReturnType() { 28 | return LattePhpTypeDetector.detectPhpType(this); 29 | } 30 | 31 | @Override 32 | public @Nullable BaseLattePhpElement getLastPhpElement() { 33 | if (lastPhpElement == null) { 34 | int partsCount = getPhpStatementPartList().size(); 35 | if (partsCount > 0) { 36 | lastPhpElement = getPhpStatementPartList().get(partsCount - 1).getPhpElement(); 37 | return lastPhpElement; 38 | } 39 | lastPhpElement = getPhpStatementFirstPart().getPhpElement(); 40 | } 41 | return lastPhpElement; 42 | } 43 | 44 | @Override 45 | public boolean isPhpVariableOnly() { 46 | return getPhpStatementFirstPart().getPhpVariable() != null && getPhpStatementPartList().size() == 0; 47 | } 48 | 49 | @Override 50 | public boolean isPhpClassReferenceOnly() { 51 | return getPhpStatementFirstPart().getPhpClassReference() != null && getPhpStatementPartList().size() == 0; 52 | } 53 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/psi/impl/elements/LattePhpTypedPartElementImpl.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.psi.impl.elements; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.nette.latte.psi.elements.LattePhpTypedPartElement; 5 | import org.nette.latte.psi.impl.LattePsiElementImpl; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public abstract class LattePhpTypedPartElementImpl extends LattePsiElementImpl implements LattePhpTypedPartElement { 9 | 10 | public LattePhpTypedPartElementImpl(@NotNull ASTNode node) { 11 | super(node); 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/refactoring/LatteRenamePsiElementProcessor.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.refactoring; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.refactoring.rename.RenamePsiElementProcessor; 5 | import org.nette.latte.psi.*; 6 | import com.jetbrains.php.lang.psi.elements.Field; 7 | import com.jetbrains.php.lang.psi.elements.Method; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.nette.latte.psi.*; 10 | 11 | class LatteRenamePsiElementProcessor extends RenamePsiElementProcessor { 12 | 13 | @Override 14 | public boolean canProcessElement(@NotNull PsiElement psiElement) { 15 | return psiElement instanceof LattePhpMethod 16 | || psiElement instanceof LattePhpClassUsage 17 | // || psiElement instanceof LattePhpNamespaceReference todo: temporarily disabled (weird PHPStorm behavior for PhpIndex.getNamespaceByName) 18 | || psiElement instanceof LattePhpConstant 19 | || psiElement instanceof LattePhpStaticVariable 20 | || psiElement instanceof LattePhpProperty 21 | || psiElement instanceof Field 22 | || psiElement instanceof Method; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/reference/LatteBraceMatcher.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.reference; 2 | 3 | import com.intellij.lang.BracePair; 4 | import com.intellij.lang.PairedBraceMatcher; 5 | import com.intellij.psi.PsiFile; 6 | import com.intellij.psi.tree.IElementType; 7 | import org.nette.latte.psi.LatteTypes; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | public class LatteBraceMatcher implements PairedBraceMatcher { 12 | private static final BracePair[] PAIRS = new BracePair[]{ 13 | new BracePair(LatteTypes.T_PHP_LEFT_BRACKET, LatteTypes.T_PHP_RIGHT_BRACKET, false), 14 | new BracePair(LatteTypes.T_PHP_LEFT_CURLY_BRACE, LatteTypes.T_PHP_RIGHT_CURLY_BRACE, true), 15 | new BracePair(LatteTypes.T_PHP_LEFT_NORMAL_BRACE, LatteTypes.T_PHP_RIGHT_NORMAL_BRACE, false), 16 | }; 17 | 18 | @NotNull 19 | @Override 20 | public BracePair[] getPairs() { 21 | return PAIRS; 22 | } 23 | 24 | @Override 25 | public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType lbraceType, @Nullable IElementType contextType) { 26 | return true; 27 | } 28 | 29 | @Override 30 | public int getCodeConstructStart(PsiFile file, int openingBraceOffset) { 31 | return openingBraceOffset; 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/reference/LatteFindUsagesProvider.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.reference; 2 | 3 | import com.intellij.lang.cacheBuilder.*; 4 | import com.intellij.lang.findUsages.FindUsagesProvider; 5 | import com.intellij.psi.*; 6 | import com.intellij.psi.tree.TokenSet; 7 | import org.nette.latte.lexer.LatteLexer; 8 | import org.nette.latte.lexer.LatteLookAheadLexer; 9 | import org.nette.latte.psi.LattePhpVariable; 10 | import org.nette.latte.psi.LatteTypes; 11 | import org.jetbrains.annotations.*; 12 | 13 | public class LatteFindUsagesProvider implements FindUsagesProvider { 14 | @Nullable 15 | @Override 16 | public WordsScanner getWordsScanner() { 17 | return new DefaultWordsScanner( 18 | new LatteLookAheadLexer(new LatteLexer()), 19 | TokenSet.create(LatteTypes.PHP_VARIABLE), 20 | TokenSet.create(LatteTypes.MACRO_COMMENT), 21 | TokenSet.EMPTY 22 | ); 23 | } 24 | 25 | @Override 26 | public boolean canFindUsagesFor(@NotNull PsiElement psiElement) { 27 | return psiElement instanceof LattePhpVariable && ((LattePhpVariable) psiElement).isDefinition(); 28 | } 29 | 30 | @Nullable 31 | @Override 32 | public String getHelpId(@NotNull PsiElement psiElement) { 33 | return null; 34 | } 35 | 36 | @NotNull 37 | @Override 38 | public String getType(@NotNull PsiElement element) { 39 | if (element instanceof LattePhpVariable) { 40 | return "latte variable"; 41 | } else { 42 | return ""; 43 | } 44 | } 45 | 46 | @NotNull 47 | @Override 48 | public String getDescriptiveName(@NotNull PsiElement element) { 49 | if (element instanceof LattePhpVariable) { 50 | return ((LattePhpVariable) element).getVariableName(); 51 | } else { 52 | return ""; 53 | } 54 | } 55 | 56 | @NotNull 57 | @Override 58 | public String getNodeText(@NotNull PsiElement element, boolean useFullName) { 59 | if (element instanceof LattePhpVariable) { 60 | return ((LattePhpVariable) element).getVariableName(); 61 | } else { 62 | return ""; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/reference/references/LatteFilterReference.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.reference.references; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.util.TextRange; 5 | import com.intellij.psi.*; 6 | import org.nette.latte.psi.LatteMacroModifier; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class LatteFilterReference extends PsiReferenceBase implements PsiPolyVariantReference { 14 | 15 | private final String modifierName; 16 | private final Project project; 17 | 18 | public LatteFilterReference(@NotNull LatteMacroModifier element, TextRange textRange) { 19 | super(element, textRange); 20 | modifierName = element.getModifierName(); 21 | project = element.getProject(); 22 | } 23 | 24 | @NotNull 25 | @Override 26 | public ResolveResult[] multiResolve(boolean incompleteCode) { 27 | List results = new ArrayList<>(); 28 | //for (XmlAttributeValue attributeValue : LatteFileConfiguration.getAllMatchedXmlAttributeValues(project, "filter", modifierName)) { 29 | // results.add(new PsiElementResolveResult(attributeValue)); 30 | //} 31 | 32 | //final Collection modifiers = LatteIndexUtil.findFiltersByName(project, modifierName); 33 | //for (LatteMacroModifier modifier : modifiers) { 34 | // results.add(new PsiElementResolveResult(modifier)); 35 | //} 36 | return results.toArray(new ResolveResult[0]); 37 | } 38 | 39 | @Nullable 40 | @Override 41 | public PsiElement resolve() { 42 | ResolveResult[] resolveResults = multiResolve(false); 43 | return resolveResults.length == 1 ? resolveResults[0].getElement() : null; 44 | } 45 | 46 | @NotNull 47 | @Override 48 | public Object[] getVariants() { 49 | return new Object[0]; 50 | } 51 | 52 | @Override 53 | public boolean isReferenceTo(@NotNull PsiElement element) { 54 | if (element instanceof LatteMacroModifier) { 55 | return ((LatteMacroModifier) element).getModifierName().equals(modifierName); 56 | } 57 | return super.isReferenceTo(element); 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/reference/references/LatteMacroTagReference.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.reference.references; 2 | 3 | import com.intellij.openapi.util.TextRange; 4 | import com.intellij.psi.*; 5 | import org.nette.latte.psi.LatteMacroClassic; 6 | import org.nette.latte.psi.LatteMacroTag; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class LatteMacroTagReference extends PsiReferenceBase implements PsiPolyVariantReference { 14 | 15 | public LatteMacroTagReference(@NotNull LatteMacroTag element, TextRange textRange) { 16 | super(element, textRange, true); 17 | } 18 | 19 | @NotNull 20 | @Override 21 | public ResolveResult[] multiResolve(boolean incompleteCode) { 22 | PsiElement parent = getElement().getParent(); 23 | if (!(parent instanceof LatteMacroClassic)) { 24 | return new ResolveResult[0]; 25 | } 26 | 27 | List results = new ArrayList<>(); 28 | 29 | LatteMacroTag openTag = ((LatteMacroClassic) parent).getOpenTag(); 30 | if (openTag.getReference() != this) { 31 | results.add(new PsiElementResolveResult(openTag)); 32 | } 33 | 34 | LatteMacroTag closeTag = ((LatteMacroClassic) parent).getCloseTag(); 35 | if (closeTag != null && closeTag.getReference() != this) { 36 | results.add(new PsiElementResolveResult(closeTag)); 37 | } 38 | 39 | return results.toArray(new ResolveResult[0]); 40 | } 41 | 42 | @Nullable 43 | @Override 44 | public PsiElement resolve() { 45 | ResolveResult[] resolveResults = multiResolve(false); 46 | return resolveResults.length == 1 ? resolveResults[0].getElement() : null; 47 | } 48 | 49 | @NotNull 50 | @Override 51 | public Object[] getVariants() { 52 | return new Object[0]; 53 | } 54 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/reference/references/LatteXmlFunctionDeclarationReference.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.reference.references; 2 | 3 | import com.intellij.openapi.util.TextRange; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.PsiPolyVariantReference; 6 | import com.intellij.psi.PsiReferenceBase; 7 | import com.intellij.psi.ResolveResult; 8 | import com.intellij.psi.xml.XmlAttributeValue; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | public class LatteXmlFunctionDeclarationReference extends PsiReferenceBase implements PsiPolyVariantReference { 13 | 14 | private final String name; 15 | 16 | public LatteXmlFunctionDeclarationReference(@NotNull XmlAttributeValue element, TextRange textRange) { 17 | super(element, textRange); 18 | name = element.getValue(); 19 | } 20 | 21 | @NotNull 22 | @Override 23 | public ResolveResult[] multiResolve(boolean incompleteCode) { 24 | return ResolveResult.EMPTY_ARRAY; 25 | } 26 | 27 | @Nullable 28 | @Override 29 | public PsiElement resolve() { 30 | ResolveResult[] resolveResults = multiResolve(false); 31 | return resolveResults.length == 1 ? resolveResults[0].getElement() : null; 32 | } 33 | 34 | @NotNull 35 | @Override 36 | public Object[] getVariants() { 37 | return new Object[0]; 38 | } 39 | 40 | @Override 41 | public boolean isSoft() { 42 | return true; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/settings/BaseLatteSettings.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.settings; 2 | 3 | import org.nette.latte.config.LatteConfiguration; 4 | 5 | public class BaseLatteSettings { 6 | protected LatteConfiguration.Vendor vendor; 7 | protected String vendorName; 8 | 9 | BaseLatteSettings() { 10 | this(LatteConfiguration.Vendor.CUSTOM, ""); 11 | } 12 | 13 | BaseLatteSettings(LatteConfiguration.Vendor vendor, String vendorName) { 14 | this.vendor = vendor; 15 | this.vendorName = vendorName; 16 | } 17 | 18 | public LatteConfiguration.Vendor getVendor() { 19 | return vendor; 20 | } 21 | 22 | protected BaseLatteSettings setVendor(LatteConfiguration.Vendor vendor) { 23 | this.vendor = vendor; 24 | return this; 25 | } 26 | 27 | public void setVendorName(String vendorName) { 28 | this.vendorName = vendorName; 29 | } 30 | 31 | public String getVendorName() { 32 | return vendorName; 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/settings/LatteSettings.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.settings; 2 | 3 | import com.intellij.openapi.components.PersistentStateComponent; 4 | import com.intellij.openapi.components.State; 5 | import com.intellij.openapi.components.Storage; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.util.xmlb.XmlSerializerUtil; 8 | import com.intellij.util.xmlb.annotations.Tag; 9 | import org.nette.latte.config.LatteConfiguration; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | @State( 17 | name = "LattePluginSettings", 18 | storages = { 19 | @Storage("latte.xml") 20 | } 21 | ) 22 | public class LatteSettings implements PersistentStateComponent { 23 | 24 | public boolean enableXmlLoading = true; 25 | 26 | public boolean enableNette = true; 27 | 28 | public boolean enableNetteForms = true; 29 | 30 | public boolean enableDefaultVariables = true; 31 | 32 | public boolean enableCustomMacros = true; 33 | 34 | public boolean enableCustomModifiers = true; 35 | 36 | public boolean enableCustomFunctions = true; 37 | 38 | public List variableSettings = new ArrayList<>(); 39 | 40 | @Tag("customMacroSettings") 41 | public List tagSettings = new ArrayList<>(); 42 | 43 | @Tag("customModifierSettings") 44 | public List filterSettings = new ArrayList<>(); 45 | 46 | @Tag("customFunctionSettings") 47 | public List functionSettings = new ArrayList<>(); 48 | 49 | public static LatteSettings getInstance(Project project) { 50 | return project.getService(LatteSettings.class); 51 | } 52 | 53 | public boolean isEnabledSourceVendor(LatteConfiguration.Vendor vendor) { 54 | if (vendor == LatteConfiguration.Vendor.NETTE_APPLICATION) { 55 | return enableNette; 56 | } else if (vendor == LatteConfiguration.Vendor.NETTE_FORMS) { 57 | return enableNetteForms; 58 | } 59 | return true; 60 | } 61 | 62 | @Nullable 63 | @Override 64 | public LatteSettings getState() { 65 | // add initializing here if needed 66 | return this; 67 | } 68 | 69 | @Override 70 | public void loadState(@NotNull LatteSettings settings) { 71 | XmlSerializerUtil.copyBean(settings, this); 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/settings/LatteVariableSettings.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.settings; 2 | 3 | import com.intellij.util.xmlb.annotations.Attribute; 4 | import org.nette.latte.config.LatteConfiguration; 5 | import org.nette.latte.php.NettePhpType; 6 | 7 | import java.io.Serializable; 8 | import java.util.Objects; 9 | 10 | public class LatteVariableSettings extends BaseLatteSettings implements Serializable { 11 | 12 | private String varName; 13 | private String varType; 14 | 15 | public LatteVariableSettings() { 16 | super(); 17 | } 18 | 19 | public LatteVariableSettings(String varName, String varType) { 20 | this(varName, varType, LatteConfiguration.Vendor.OTHER, ""); 21 | } 22 | 23 | public LatteVariableSettings(String varName, String varType, LatteConfiguration.Vendor vendor, String vendorName) { 24 | super(vendor, vendorName); 25 | this.varName = varName; 26 | this.varType = varType; 27 | } 28 | 29 | public void setVarName(String varName) { 30 | this.varName = varName; 31 | } 32 | 33 | public void setVarType(String varType) { 34 | this.varType = varType; 35 | } 36 | 37 | public NettePhpType toPhpType() { 38 | return NettePhpType.create(varName, varType); 39 | } 40 | 41 | @Attribute("VarName") 42 | public String getVarName() { 43 | return varName; 44 | } 45 | 46 | @Attribute("VarType") 47 | public String getVarType() { 48 | return varType; 49 | } 50 | 51 | @Override 52 | public LatteVariableSettings setVendor(LatteConfiguration.Vendor vendor) { 53 | super.setVendor(vendor); 54 | return this; 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | return Objects.hash(varName, varType); 60 | } 61 | 62 | @Override 63 | public boolean equals(Object obj) { 64 | return obj instanceof LatteVariableSettings && 65 | Objects.equals(((LatteVariableSettings) obj).getVarName(), this.getVarName()) && 66 | Objects.equals(((LatteVariableSettings) obj).getVarType(), this.getVarType()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/syntaxHighlighter/LatteEditorHighlighter.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.syntaxHighlighter; 2 | 3 | 4 | import com.intellij.ide.highlighter.HtmlFileType; 5 | import com.intellij.lexer.Lexer; 6 | import com.intellij.openapi.editor.colors.EditorColorsScheme; 7 | import com.intellij.openapi.editor.colors.TextAttributesKey; 8 | import com.intellij.openapi.editor.ex.util.LayerDescriptor; 9 | import com.intellij.openapi.editor.ex.util.LayeredLexerEditorHighlighter; 10 | import com.intellij.openapi.fileTypes.LanguageFileType; 11 | import com.intellij.openapi.fileTypes.SyntaxHighlighter; 12 | import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; 13 | import com.intellij.openapi.project.Project; 14 | import com.intellij.openapi.vfs.VirtualFile; 15 | import com.intellij.psi.tree.IElementType; 16 | import org.nette.latte.lexer.LatteHtmlHighlightingLexer; 17 | import org.nette.latte.psi.LatteTypes; 18 | import org.jetbrains.annotations.NotNull; 19 | import org.jetbrains.annotations.Nullable; 20 | 21 | public class LatteEditorHighlighter extends LayeredLexerEditorHighlighter { 22 | public LatteEditorHighlighter(@Nullable Project project, @Nullable VirtualFile virtualFile, @NotNull EditorColorsScheme colors) { 23 | super(new LatteSyntaxHighlighter() { 24 | @Override 25 | public @NotNull Lexer getHighlightingLexer() { 26 | return new LatteHtmlHighlightingLexer(super.getHighlightingLexer()); 27 | } 28 | }, colors); 29 | 30 | final SyntaxHighlighter highlighter = getHighlighter(project, virtualFile); 31 | this.registerLayer(LatteTypes.T_TEXT, new LayerDescriptor(new SyntaxHighlighter() { 32 | @NotNull 33 | public Lexer getHighlightingLexer() { 34 | return highlighter.getHighlightingLexer(); 35 | } 36 | 37 | @NotNull 38 | public TextAttributesKey[] getTokenHighlights(IElementType tokenType) { 39 | return highlighter.getTokenHighlights(tokenType); 40 | } 41 | }, "")); 42 | } 43 | 44 | @NotNull 45 | private static SyntaxHighlighter getHighlighter(Project project, VirtualFile virtualFile) { 46 | LanguageFileType fileType = HtmlFileType.INSTANCE; 47 | SyntaxHighlighter highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(fileType, project, virtualFile); 48 | assert highlighter != null; 49 | 50 | return highlighter; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/syntaxHighlighter/LatteSyntaxHighlighterFactory.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.syntaxHighlighter; 2 | 3 | import com.intellij.openapi.fileTypes.SyntaxHighlighter; 4 | import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.openapi.vfs.VirtualFile; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | public class LatteSyntaxHighlighterFactory extends SyntaxHighlighterFactory { 11 | @NotNull 12 | @Override 13 | public SyntaxHighlighter getSyntaxHighlighter(@Nullable Project project, @Nullable VirtualFile virtualFile) { 14 | return new LatteSyntaxHighlighter(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/ui/LatteCustomFunctionSettingsForm.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/ui/LatteCustomMacroSettingsForm.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/ui/LatteCustomModifierSettingsForm.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/ui/LatteVariableSettingsForm.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/ui/PhpTypeColumn.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.ui; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.ui.ColoredTableCellRenderer; 5 | import com.intellij.ui.JBColor; 6 | import com.intellij.ui.SimpleTextAttributes; 7 | import com.intellij.util.ui.ColumnInfo; 8 | import org.nette.latte.php.NettePhpType; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import javax.swing.*; 12 | import javax.swing.table.TableCellRenderer; 13 | import java.awt.*; 14 | 15 | abstract class PhpTypeColumn extends ColumnInfo { 16 | 17 | private final Project project; 18 | 19 | PhpTypeColumn(String name, Project project) { 20 | super(name); 21 | this.project = project; 22 | } 23 | 24 | @Override 25 | public @Nullable TableCellRenderer getRenderer(T settings) { 26 | return new ColoredTableCellRenderer() { 27 | @Override 28 | protected void customizeCellRenderer(JTable table, Object value, 29 | boolean isSelected, boolean hasFocus, int row, int column) { 30 | if (value == null) { 31 | return; 32 | } 33 | 34 | NettePhpType type = NettePhpType.create((String) value); 35 | if (type.hasUndefinedClass(project)) { 36 | append((String) value, new SimpleTextAttributes(Font.PLAIN, JBColor.RED)); 37 | } else { 38 | append((String) value, new SimpleTextAttributes(Font.PLAIN, null)); 39 | } 40 | } 41 | }; 42 | } 43 | 44 | @Override 45 | public @Nullable String getTooltipText() { 46 | return "If you see a red font, some class is probably undefined."; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/ui/VendorTypeColumn.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.ui; 2 | 3 | import com.intellij.ui.ColoredTableCellRenderer; 4 | import com.intellij.ui.SimpleTextAttributes; 5 | import com.intellij.util.ui.ColumnInfo; 6 | import org.nette.latte.config.LatteConfiguration; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import javax.swing.*; 10 | import javax.swing.table.TableCellRenderer; 11 | 12 | abstract class VendorTypeColumn extends ColumnInfo { 13 | 14 | VendorTypeColumn(String name) { 15 | super(name); 16 | } 17 | 18 | @Override 19 | public @Nullable TableCellRenderer getRenderer(T settings) { 20 | return new ColoredTableCellRenderer() { 21 | @Override 22 | protected void customizeCellRenderer(JTable table, Object value, 23 | boolean isSelected, boolean hasFocus, int row, int column) { 24 | if (!(value instanceof LatteConfiguration.VendorResult)) { 25 | return; 26 | } 27 | 28 | LatteConfiguration.VendorResult vendor = (LatteConfiguration.VendorResult) value; 29 | if (vendor.vendor == LatteConfiguration.Vendor.OTHER) { 30 | append(vendor.vendorName, new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, vendor.vendor.getColor())); 31 | } else { 32 | append(vendor.vendor.getName(), new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, vendor.vendor.getColor())); 33 | } 34 | } 35 | }; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/utils/LatteHtmlUtil.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.utils; 2 | 3 | import com.intellij.psi.tree.TokenSet; 4 | import org.nette.latte.psi.LatteTypes; 5 | 6 | import java.util.Arrays; 7 | 8 | public class LatteHtmlUtil { 9 | public static TokenSet HTML_TOKENS = TokenSet.create(LatteTypes.T_TEXT, LatteTypes.T_HTML_CLOSE_TAG_OPEN, LatteTypes.T_HTML_OPEN_TAG_OPEN, LatteTypes.T_HTML_OPEN_TAG_CLOSE, LatteTypes.T_HTML_TAG_CLOSE); 10 | 11 | final private static String[] voidTags = new String[]{ 12 | "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr", "!doctype", 13 | "style", "script" // style and script are here only because LatteTopLexer.flex implementation 14 | }; 15 | 16 | public static boolean isVoidTag(String tagName) { 17 | return Arrays.asList(voidTags).contains(tagName.toLowerCase()); 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/utils/LatteMimeTypes.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.utils; 2 | 3 | public class LatteMimeTypes { 4 | 5 | final private static String[] defaultMimeTypes = new String[]{ 6 | "text/html", 7 | "text/xml", 8 | "application/xml", 9 | "text/css", 10 | "text/calendar", 11 | "text/javascript", 12 | "application/javascript", 13 | "text/plain", 14 | }; 15 | 16 | public static String[] getDefaultMimeTypes() { 17 | return defaultMimeTypes; 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/java/org/nette/latte/utils/LattePhpVariableDefinition.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.utils; 2 | 3 | import org.nette.latte.psi.elements.LattePhpVariableElement; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public class LattePhpVariableDefinition { 7 | 8 | private final boolean probablyUndefined; 9 | private final LattePhpVariableElement element; 10 | 11 | public LattePhpVariableDefinition(boolean probablyUndefined, @NotNull LattePhpVariableElement element) { 12 | this.probablyUndefined = probablyUndefined; 13 | this.element = element; 14 | } 15 | 16 | public boolean isProbablyUndefined() { 17 | return probablyUndefined; 18 | } 19 | 20 | public LattePhpVariableElement getElement() { 21 | return element; 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/resources/icons/Latte.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/main/resources/icons/Latte.png -------------------------------------------------------------------------------- /src/main/resources/icons/Latte.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/main/resources/icons/Latte.xcf -------------------------------------------------------------------------------- /src/main/resources/icons/Latte@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/main/resources/icons/Latte@2x.png -------------------------------------------------------------------------------- /src/main/resources/icons/Latte@2x.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/main/resources/icons/Latte@2x.xcf -------------------------------------------------------------------------------- /src/main/resources/icons/LatteXml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/main/resources/icons/LatteXml.png -------------------------------------------------------------------------------- /src/main/resources/icons/LatteXml.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/main/resources/icons/LatteXml.xcf -------------------------------------------------------------------------------- /src/main/resources/icons/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/main/resources/icons/Logo.png -------------------------------------------------------------------------------- /src/main/resources/icons/Macro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/main/resources/icons/Macro.png -------------------------------------------------------------------------------- /src/main/resources/icons/Macro.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/main/resources/icons/Macro.xcf -------------------------------------------------------------------------------- /src/main/resources/icons/Modifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/main/resources/icons/Modifier.png -------------------------------------------------------------------------------- /src/main/resources/icons/Modifier.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/main/resources/icons/Modifier.xcf -------------------------------------------------------------------------------- /src/main/resources/icons/NTag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/main/resources/icons/NTag.png -------------------------------------------------------------------------------- /src/main/resources/icons/NTag.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/main/resources/icons/NTag.xcf -------------------------------------------------------------------------------- /src/main/resources/inspectionDescriptions/LatteIterableType.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Detects errors around variables (unused, undefined, ...).

4 | 5 |

Detects errors around variables like `Multiple definitions`, `Unused variable`, `Undefined variable` etc.

6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/inspectionDescriptions/LatteMacroVar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Right syntax for 'var' definition is:

4 |
5 | {var type $foo = 'example value'} 6 | 7 |

Checking syntax in 'var' macro.

8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/inspectionDescriptions/LatteVarType.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Right syntax for 'varType' definition is:

4 |
5 | {varType type $foo} 6 | 7 |

Checking syntax in 'varType' macro.

8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/inspectionDescriptions/LatteVariablesProblems.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Detects errors around variables (unused, undefined, ...).

4 | 5 |

Detects errors around variables like `Multiple definitions`, `Unused variable`, `Undefined variable` etc.

6 | 7 | -------------------------------------------------------------------------------- /src/test/java/org/nette/latte/Assert.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte; 2 | 3 | import com.intellij.lexer.Lexer; 4 | import com.intellij.openapi.util.Pair; 5 | import com.intellij.psi.tree.IElementType; 6 | 7 | import static org.junit.Assert.assertEquals; 8 | import static org.junit.Assert.fail; 9 | 10 | public class Assert { 11 | /** 12 | * Checks that given lexer returns the correct tokens. 13 | * 14 | * @param lexer 15 | * @param expectedTokens 16 | */ 17 | public static void assertTokens(Lexer lexer, Pair[] expectedTokens) { 18 | int i; 19 | for (i = 0; lexer.getTokenType() != null; i++) { 20 | if (i == expectedTokens.length) fail("Too many tokens from lexer; unexpected " + lexer.getTokenType()); 21 | assertEquals("Wrong token type at index " + i, expectedTokens[i].first, lexer.getTokenType()); 22 | assertEquals("Wrong token text at index " + i, expectedTokens[i].second, lexer.getTokenText()); 23 | lexer.advance(); 24 | } 25 | if (i < expectedTokens.length) fail("Not enough tokens from lexer; expected " + expectedTokens[i].first + " but got nothing."); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/org/nette/latte/BasePsiParsingTestCase.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte; 2 | 3 | import com.intellij.openapi.util.io.FileUtil; 4 | import com.intellij.openapi.vfs.CharsetToolkit; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiFile; 7 | import com.intellij.psi.PsiRecursiveElementWalkingVisitor; 8 | import com.intellij.testFramework.ParsingTestCase; 9 | import com.intellij.testFramework.TestDataFile; 10 | import org.nette.latte.parser.LatteParserDefinition; 11 | import org.nette.latte.psi.LattePhpVariable; 12 | import org.jetbrains.annotations.NonNls; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | abstract public class BasePsiParsingTestCase extends ParsingTestCase { 21 | 22 | protected BasePsiParsingTestCase() { 23 | super("", "latte", new LatteParserDefinition()); 24 | } 25 | 26 | protected String loadFile(@NotNull @NonNls @TestDataFile String name) throws IOException { 27 | return FileUtil.loadFile(new File(myFullDataPath, name), CharsetToolkit.UTF8, true); 28 | } 29 | 30 | protected PsiFile parseFile(@NotNull String fileName) throws IOException { 31 | return parseFile(fileName, loadFile(fileName)); 32 | } 33 | 34 | protected List collectVariables(PsiElement parent) { 35 | List variables = new ArrayList<>(); 36 | parent.acceptChildren(new PsiRecursiveElementWalkingVisitor() { 37 | @Override 38 | public void visitElement(@NotNull PsiElement element) { 39 | if (element instanceof LattePhpVariable) { 40 | variables.add((LattePhpVariable) element); 41 | } else { 42 | super.visitElement(element); 43 | } 44 | } 45 | }); 46 | return variables; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/org/nette/latte/lexer/LatteHighlightingLexerTest.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.lexer; 2 | 3 | import com.intellij.lexer.Lexer; 4 | import com.intellij.openapi.util.Pair; 5 | import org.junit.Test; 6 | 7 | import static org.nette.latte.Assert.assertTokens; 8 | import static org.nette.latte.psi.LatteTypes.*; 9 | 10 | public class LatteHighlightingLexerTest { 11 | @Test 12 | @SuppressWarnings("unchecked") 13 | public void testMacroLexer() { 14 | Lexer lexer = new LatteHighlightingLexer(new LatteLookAheadLexer(new LatteLexer())); 15 | 16 | lexer.start("{include #blockName}"); 17 | assertTokens(lexer, new Pair[] { 18 | Pair.create(T_MACRO_OPEN_TAG_OPEN, "{"), 19 | Pair.create(T_MACRO_NAME, "include"), 20 | Pair.create(T_WHITESPACE, " "), 21 | Pair.create(T_BLOCK_NAME, "#"), 22 | Pair.create(T_BLOCK_NAME, "blockName"), 23 | Pair.create(T_MACRO_TAG_CLOSE, "}"), 24 | }); 25 | 26 | lexer.start("{= dump ()}"); 27 | assertTokens(lexer, new Pair[] { 28 | Pair.create(T_MACRO_OPEN_TAG_OPEN, "{"), 29 | Pair.create(T_MACRO_SHORTNAME, "="), 30 | Pair.create(T_WHITESPACE, " "), 31 | Pair.create(T_PHP_METHOD, "dump"), 32 | Pair.create(T_WHITESPACE, " "), 33 | Pair.create(T_PHP_LEFT_NORMAL_BRACE, "("), 34 | Pair.create(T_PHP_RIGHT_NORMAL_BRACE, ")"), 35 | Pair.create(T_MACRO_TAG_CLOSE, "}"), 36 | }); 37 | 38 | lexer.start("{= \\Foo\\Bar}"); 39 | assertTokens(lexer, new Pair[] { 40 | Pair.create(T_MACRO_OPEN_TAG_OPEN, "{"), 41 | Pair.create(T_MACRO_SHORTNAME, "="), 42 | Pair.create(T_WHITESPACE, " "), 43 | Pair.create(T_PHP_NAMESPACE_RESOLUTION, "\\"), 44 | Pair.create(T_PHP_NAMESPACE_REFERENCE, "Foo"), 45 | Pair.create(T_PHP_NAMESPACE_RESOLUTION, "\\"), 46 | Pair.create(T_PHP_NAMESPACE_REFERENCE, "Bar"), 47 | Pair.create(T_MACRO_TAG_CLOSE, "}"), 48 | }); 49 | 50 | lexer.start("{= \\Bar}"); 51 | assertTokens(lexer, new Pair[] { 52 | Pair.create(T_MACRO_OPEN_TAG_OPEN, "{"), 53 | Pair.create(T_MACRO_SHORTNAME, "="), 54 | Pair.create(T_WHITESPACE, " "), 55 | Pair.create(T_PHP_NAMESPACE_RESOLUTION, "\\"), 56 | Pair.create(T_PHP_NAMESPACE_REFERENCE, "Bar"), 57 | Pair.create(T_MACRO_TAG_CLOSE, "}"), 58 | }); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/org/nette/latte/lexer/LatteLookAheadLexerTest.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.lexer; 2 | 3 | import com.intellij.lexer.Lexer; 4 | import com.intellij.openapi.util.Pair; 5 | import org.junit.Test; 6 | 7 | import static org.nette.latte.Assert.assertTokens; 8 | import static org.nette.latte.psi.LatteTypes.*; 9 | 10 | public class LatteLookAheadLexerTest { 11 | @Test 12 | @SuppressWarnings("unchecked") 13 | public void testLinkMacroLexer() { 14 | Lexer lexer = new LatteLookAheadLexer(new LatteLexer()); 15 | 16 | lexer.start("{link default}"); 17 | assertTokens(lexer, new Pair[] { 18 | Pair.create(T_MACRO_OPEN_TAG_OPEN, "{"), 19 | Pair.create(T_MACRO_NAME, "link"), 20 | Pair.create(T_WHITESPACE, " "), 21 | Pair.create(T_LINK_DESTINATION, "default"), 22 | Pair.create(T_MACRO_TAG_CLOSE, "}"), 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/org/nette/latte/lexer/LatteMacroContentLexerAdapterTest.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.lexer; 2 | 3 | import com.intellij.lexer.Lexer; 4 | import com.intellij.openapi.util.Pair; 5 | import org.junit.Test; 6 | 7 | import static org.nette.latte.Assert.assertTokens; 8 | import static org.nette.latte.psi.LatteTypes.*; 9 | 10 | public class LatteMacroContentLexerAdapterTest { 11 | 12 | @Test 13 | @SuppressWarnings("unchecked") 14 | public void testMacroLexer() { 15 | Lexer lexer = new LatteMacroContentLexerAdapter(); 16 | 17 | lexer.start(" a "); 18 | assertTokens(lexer, new Pair[]{ 19 | Pair.create(T_WHITESPACE, " "), 20 | Pair.create(T_PHP_CONTENT, "a"), 21 | Pair.create(T_WHITESPACE, " "), 22 | }); 23 | 24 | lexer.start("$var"); 25 | assertTokens(lexer, new Pair[]{ 26 | Pair.create(T_PHP_CONTENT, "$var"), 27 | }); 28 | 29 | lexer.start("a()"); 30 | assertTokens(lexer, new Pair[]{ 31 | Pair.create(T_PHP_CONTENT, "a()"), 32 | }); 33 | 34 | lexer.start("a::b"); 35 | assertTokens(lexer, new Pair[]{ 36 | Pair.create(T_PHP_CONTENT, "a"), 37 | Pair.create(T_MACRO_ARGS, "::"), 38 | Pair.create(T_PHP_CONTENT, "b"), 39 | }); 40 | 41 | lexer.start("a\\b"); 42 | assertTokens(lexer, new Pair[]{ 43 | Pair.create(T_PHP_CONTENT, "a\\b"), 44 | }); 45 | 46 | lexer.start("$var|noescape"); 47 | assertTokens(lexer, new Pair[]{ 48 | Pair.create(T_PHP_CONTENT, "$var|noescape"), 49 | }); 50 | 51 | lexer.start("|test"); 52 | assertTokens(lexer, new Pair[]{ 53 | Pair.create(T_PHP_CONTENT, "|test"), 54 | }); 55 | 56 | lexer.start(" function() { } "); 57 | assertTokens(lexer, new Pair[]{ 58 | Pair.create(T_WHITESPACE, " "), 59 | Pair.create(T_PHP_CONTENT, "function() { } "), 60 | }); 61 | 62 | lexer.start("1"); 63 | assertTokens(lexer, new Pair[]{ 64 | Pair.create(T_PHP_CONTENT, "1"), 65 | }); 66 | 67 | lexer.start("1a"); 68 | assertTokens(lexer, new Pair[]{ 69 | Pair.create(T_PHP_CONTENT, "1a"), 70 | }); 71 | 72 | lexer.start("a1"); 73 | assertTokens(lexer, new Pair[]{ 74 | Pair.create(T_PHP_CONTENT, "a1"), 75 | }); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/test/java/org/nette/latte/parser/ParserTest.java: -------------------------------------------------------------------------------- 1 | package org.nette.latte.parser; 2 | 3 | import org.nette.latte.BasePsiParsingTestCase; 4 | import org.nette.latte.config.LatteConfiguration; 5 | import org.nette.latte.settings.LatteSettings; 6 | import org.junit.Test; 7 | 8 | import java.net.URL; 9 | 10 | public class ParserTest extends BasePsiParsingTestCase { 11 | 12 | @Override 13 | protected void setUp() throws Exception { 14 | super.setUp(); 15 | // initialize configuration with test configuration 16 | LatteConfiguration.getInstance(getProject()); 17 | 18 | getProject().registerService(LatteSettings.class); 19 | } 20 | 21 | @Override 22 | protected String getTestDataPath() { 23 | URL url = getClass().getClassLoader().getResource("data/parser"); 24 | assert url != null; 25 | return url.getFile(); 26 | } 27 | 28 | @Test 29 | public void testVariable() { 30 | doTest(true, true); 31 | } 32 | 33 | @Test 34 | public void testNBlock() { 35 | doTest(true, true); 36 | } 37 | 38 | @Test 39 | public void testUnknownInIf() { 40 | doTest(true, true); 41 | } 42 | 43 | @Test 44 | public void testClassDefinition() { 45 | doTest(true, true); 46 | } 47 | 48 | @Test 49 | public void testTypedDefinition() { 50 | doTest(true, true); 51 | } 52 | 53 | @Test 54 | public void testForeachDefinition() { 55 | doTest(true, true); 56 | } 57 | 58 | @Test 59 | public void testForeachReferenceDefinition() { 60 | doTest(true, true); 61 | } 62 | 63 | @Test 64 | public void testBlockDefinition() { 65 | doTest(true, true); 66 | } 67 | 68 | @Test 69 | public void testForDefinition() { 70 | doTest(true, true); 71 | } 72 | 73 | @Test 74 | public void testParametersDefinition() { 75 | doTest(true, true); 76 | } 77 | 78 | @Test 79 | public void testMacroFilters() { 80 | doTest(true, true); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/test/resources/data/inspections/variables/DefinitionsInAnotherContext.latte: -------------------------------------------------------------------------------- 1 | {var $foo = []} 2 | {if true} 3 | {var $foo = []} 4 | {$foo} 5 | {/if} 6 | -------------------------------------------------------------------------------- /src/test/resources/data/inspections/variables/MultipleDefinitions.latte: -------------------------------------------------------------------------------- 1 | {var $foo = []} 2 | {var $foo = []} 3 | {$foo} -------------------------------------------------------------------------------- /src/test/resources/data/inspections/variables/ProbablyUndefinedVariable.latte: -------------------------------------------------------------------------------- 1 | {var $foo = []} 2 | {foreach $foo as $bar} 3 | {= 123} 4 | {/foreach} 5 | {$bar} -------------------------------------------------------------------------------- /src/test/resources/data/inspections/variables/UndefinedVariable.latte: -------------------------------------------------------------------------------- 1 | {$foo} -------------------------------------------------------------------------------- /src/test/resources/data/inspections/variables/VariableInBlock.latte: -------------------------------------------------------------------------------- 1 | {var $foos = []} 2 |
3 | 4 | {define bar} 5 | {var $foos = []} 6 |
7 | {/define} -------------------------------------------------------------------------------- /src/test/resources/data/inspections/variables/VariableInNFor.latte: -------------------------------------------------------------------------------- 1 |
  • 2 | foo 3 |
  • -------------------------------------------------------------------------------- /src/test/resources/data/parser/BlockDefinition.latte: -------------------------------------------------------------------------------- 1 | {define input, string $name, int[] $value, $type = 'text'} 2 | 3 | {/define} -------------------------------------------------------------------------------- /src/test/resources/data/parser/ClassDefinition.latte: -------------------------------------------------------------------------------- 1 | {varType \PDO[][] $foo} 2 | {var $bar = $foo[0]} 3 | {var $pdo = $bar[0]} 4 | -------------------------------------------------------------------------------- /src/test/resources/data/parser/ForDefinition.latte: -------------------------------------------------------------------------------- 1 | {for $x = 0; $x < 25; $x++} 2 | 3 | {/for} 4 | -------------------------------------------------------------------------------- /src/test/resources/data/parser/ForDefinition.txt: -------------------------------------------------------------------------------- 1 | Latte file 2 | LattePairMacroImpl(PAIR_MACRO) 3 | LatteMacroOpenTagImpl(MACRO_OPEN_TAG) 4 | PsiElement(LatteTokenType.T_MACRO_OPEN_TAG_OPEN)('{') 5 | PsiElement(LatteTokenType.T_MACRO_NAME)('for') 6 | PsiWhiteSpace(' ') 7 | LatteMacroContentImpl(MACRO_CONTENT) 8 | LattePhpContentImpl(PHP_CONTENT) 9 | LattePhpStatementImpl(PHP_STATEMENT) 10 | LattePhpStatementFirstPartImpl(PHP_STATEMENT_FIRST_PART) 11 | LattePhpVariableImpl(PHP_VARIABLE)('$x') 12 | PsiElement(LatteTokenType.T_MACRO_ARGS_VAR)('$x') 13 | PsiWhiteSpace(' ') 14 | PsiElement(LatteTokenType.T_PHP_DEFINITION_OPERATOR)('=') 15 | PsiWhiteSpace(' ') 16 | PsiElement(LatteTokenType.T_MACRO_ARGS_NUMBER)('0') 17 | PsiElement(LatteTokenType.T_MACRO_ARGS)(';') 18 | PsiWhiteSpace(' ') 19 | LattePhpStatementImpl(PHP_STATEMENT) 20 | LattePhpStatementFirstPartImpl(PHP_STATEMENT_FIRST_PART) 21 | LattePhpVariableImpl(PHP_VARIABLE)('$x') 22 | PsiElement(LatteTokenType.T_MACRO_ARGS_VAR)('$x') 23 | PsiWhiteSpace(' ') 24 | PsiElement(LatteTokenType.T_PHP_RELATIONAL_OPERATOR)('<') 25 | PsiWhiteSpace(' ') 26 | PsiElement(LatteTokenType.T_MACRO_ARGS_NUMBER)('25') 27 | PsiElement(LatteTokenType.T_MACRO_ARGS)(';') 28 | PsiWhiteSpace(' ') 29 | LattePhpStatementImpl(PHP_STATEMENT) 30 | LattePhpStatementFirstPartImpl(PHP_STATEMENT_FIRST_PART) 31 | LattePhpVariableImpl(PHP_VARIABLE)('$x') 32 | PsiElement(LatteTokenType.T_MACRO_ARGS_VAR)('$x') 33 | PsiElement(LatteTokenType.T_PHP_UNARY_OPERATOR)('++') 34 | PsiElement(LatteTokenType.T_MACRO_TAG_CLOSE)('}') 35 | LatteOuterHtmlImpl(OUTER_HTML) 36 | PsiElement(LatteTokenType.T_TEXT)('\n\n') 37 | LatteMacroCloseTagImpl(MACRO_CLOSE_TAG) 38 | PsiElement(LatteTokenType.T_MACRO_CLOSE_TAG_OPEN)('{/') 39 | PsiElement(LatteTokenType.T_MACRO_NAME)('for') 40 | LatteMacroContentImpl(MACRO_CONTENT) 41 | 42 | PsiElement(LatteTokenType.T_MACRO_TAG_CLOSE)('}') 43 | LatteOuterHtmlImpl(OUTER_HTML) 44 | PsiElement(LatteTokenType.T_TEXT)('\n') -------------------------------------------------------------------------------- /src/test/resources/data/parser/ForeachDefinition.latte: -------------------------------------------------------------------------------- 1 | {var \PDO[] $foo = []} 2 | {foreach $foo as $bar} 3 | 4 | {/foreach} 5 | -------------------------------------------------------------------------------- /src/test/resources/data/parser/ForeachReferenceDefinition.latte: -------------------------------------------------------------------------------- 1 | {foreach [1, 2, 3, 4] as & $bar} 2 | 3 | {/foreach} 4 | -------------------------------------------------------------------------------- /src/test/resources/data/parser/MacroFilters.latte: -------------------------------------------------------------------------------- 1 | {= test|nowrap:1:null} -------------------------------------------------------------------------------- /src/test/resources/data/parser/MacroFilters.txt: -------------------------------------------------------------------------------- 1 | Latte file 2 | LatteUnpairedMacroImpl(UNPAIRED_MACRO) 3 | LatteMacroOpenTagImpl(MACRO_OPEN_TAG) 4 | PsiElement(LatteTokenType.T_MACRO_OPEN_TAG_OPEN)('{') 5 | PsiElement(LatteTokenType.T_MACRO_SHORTNAME)('=') 6 | PsiWhiteSpace(' ') 7 | LatteMacroContentImpl(MACRO_CONTENT) 8 | LattePhpContentImpl(PHP_CONTENT) 9 | PsiElement(LatteTokenType.T_PHP_IDENTIFIER)('test') 10 | PsiElement(LatteTokenType.T_PHP_MACRO_SEPARATOR)('|') 11 | LatteMacroModifierImpl(MACRO_MODIFIER)('nowrap:1:null') 12 | PsiElement(LatteTokenType.T_MACRO_FILTERS)('nowrap') 13 | PsiElement(LatteTokenType.T_PHP_COLON)(':') 14 | LatteMacroModifierPartImpl(MACRO_MODIFIER_PART) 15 | PsiElement(LatteTokenType.T_MACRO_ARGS_NUMBER)('1') 16 | PsiElement(LatteTokenType.T_PHP_COLON)(':') 17 | LatteMacroModifierPartImpl(MACRO_MODIFIER_PART) 18 | LattePhpTypeImpl(PHP_TYPE)('null') 19 | LattePhpTypePartImpl(PHP_TYPE_PART) 20 | PsiElement(LatteTokenType.T_PHP_NULL)('null') 21 | PsiElement(LatteTokenType.T_MACRO_TAG_CLOSE)('}') -------------------------------------------------------------------------------- /src/test/resources/data/parser/NBlock.latte: -------------------------------------------------------------------------------- 1 |
    2 | -------------------------------------------------------------------------------- /src/test/resources/data/parser/NBlock.txt: -------------------------------------------------------------------------------- 1 | Latte file 2 | LatteOuterHtmlImpl(OUTER_HTML) 3 | LatteHtmlPairTagImpl(HTML_PAIR_TAG) 4 | LatteHtmlOpenTagImpl(HTML_OPEN_TAG) 5 | PsiElement(LatteTokenType.T_HTML_OPEN_TAG_OPEN)('<') 6 | LatteHtmlTagContentImpl(HTML_TAG_CONTENT) 7 | PsiElement(LatteTokenType.T_TEXT)('div ') 8 | LatteNetteAttrImpl(NETTE_ATTR) 9 | PsiElement(LatteTokenType.T_HTML_TAG_NATTR_NAME)('n:block') 10 | PsiElement(LatteTokenType.T_HTML_TAG_ATTR_EQUAL_SIGN)('=') 11 | LatteNetteAttrValueImpl(NETTE_ATTR_VALUE) 12 | PsiElement(LatteTokenType.T_HTML_TAG_ATTR_DQ)('"') 13 | LatteMacroContentImpl(MACRO_CONTENT) 14 | LattePhpContentImpl(PHP_CONTENT) 15 | LattePhpStatementImpl(PHP_STATEMENT) 16 | LattePhpStatementFirstPartImpl(PHP_STATEMENT_FIRST_PART) 17 | LattePhpVariableImpl(PHP_VARIABLE)('$test') 18 | PsiElement(LatteTokenType.T_MACRO_ARGS_VAR)('$test') 19 | PsiElement(LatteTokenType.T_HTML_TAG_ATTR_DQ)('"') 20 | PsiElement(LatteTokenType.T_HTML_TAG_CLOSE)('>') 21 | LatteHtmlTagContainerImpl(HTML_TAG_CONTAINER) 22 | 23 | LatteHtmlCloseTagImpl(HTML_CLOSE_TAG) 24 | PsiElement(LatteTokenType.T_HTML_CLOSE_TAG_OPEN)('') 28 | LatteOuterHtmlImpl(OUTER_HTML) 29 | PsiElement(LatteTokenType.T_TEXT)('\n') -------------------------------------------------------------------------------- /src/test/resources/data/parser/ParametersDefinition.latte: -------------------------------------------------------------------------------- 1 | {parameters 2 | $a, 3 | ?int $b, 4 | ?\DateTime $c, 5 | int|string $d = 10 6 | } 7 | -------------------------------------------------------------------------------- /src/test/resources/data/parser/TypedDefinition.latte: -------------------------------------------------------------------------------- 1 | {var int[] $foo = [12]} 2 | {var $bar = $foo[0]} 3 | -------------------------------------------------------------------------------- /src/test/resources/data/parser/UnknownInIf.latte: -------------------------------------------------------------------------------- 1 | {if true}{? $var}{/if} 2 | -------------------------------------------------------------------------------- /src/test/resources/data/parser/UnknownInIf.txt: -------------------------------------------------------------------------------- 1 | Latte file 2 | LattePairMacroImpl(PAIR_MACRO) 3 | LatteMacroOpenTagImpl(MACRO_OPEN_TAG) 4 | PsiElement(LatteTokenType.T_MACRO_OPEN_TAG_OPEN)('{') 5 | PsiElement(LatteTokenType.T_MACRO_NAME)('if') 6 | PsiWhiteSpace(' ') 7 | LatteMacroContentImpl(MACRO_CONTENT) 8 | LattePhpContentImpl(PHP_CONTENT) 9 | PsiElement(LatteTokenType.T_PHP_KEYWORD)('true') 10 | PsiElement(LatteTokenType.T_MACRO_TAG_CLOSE)('}') 11 | LatteUnpairedMacroImpl(UNPAIRED_MACRO) 12 | LatteMacroOpenTagImpl(MACRO_OPEN_TAG) 13 | PsiElement(LatteTokenType.T_MACRO_OPEN_TAG_OPEN)('{') 14 | PsiElement(LatteTokenType.T_MACRO_NAME)('?') 15 | PsiWhiteSpace(' ') 16 | LatteMacroContentImpl(MACRO_CONTENT) 17 | LattePhpContentImpl(PHP_CONTENT) 18 | LattePhpStatementImpl(PHP_STATEMENT) 19 | LattePhpStatementFirstPartImpl(PHP_STATEMENT_FIRST_PART) 20 | LattePhpVariableImpl(PHP_VARIABLE)('$var') 21 | PsiElement(LatteTokenType.T_MACRO_ARGS_VAR)('$var') 22 | PsiElement(LatteTokenType.T_MACRO_TAG_CLOSE)('}') 23 | LatteMacroCloseTagImpl(MACRO_CLOSE_TAG) 24 | PsiElement(LatteTokenType.T_MACRO_CLOSE_TAG_OPEN)('{/') 25 | PsiElement(LatteTokenType.T_MACRO_NAME)('if') 26 | LatteMacroContentImpl(MACRO_CONTENT) 27 | 28 | PsiElement(LatteTokenType.T_MACRO_TAG_CLOSE)('}') 29 | LatteOuterHtmlImpl(OUTER_HTML) 30 | PsiElement(LatteTokenType.T_TEXT)('\n') -------------------------------------------------------------------------------- /src/test/resources/data/parser/Variable.latte: -------------------------------------------------------------------------------- 1 | {$foo} -------------------------------------------------------------------------------- /src/test/resources/data/parser/Variable.txt: -------------------------------------------------------------------------------- 1 | Latte file 2 | LatteUnpairedMacroImpl(UNPAIRED_MACRO) 3 | LatteMacroOpenTagImpl(MACRO_OPEN_TAG) 4 | PsiElement(LatteTokenType.T_MACRO_OPEN_TAG_OPEN)('{') 5 | LatteMacroContentImpl(MACRO_CONTENT) 6 | LattePhpContentImpl(PHP_CONTENT) 7 | LattePhpStatementImpl(PHP_STATEMENT) 8 | LattePhpStatementFirstPartImpl(PHP_STATEMENT_FIRST_PART) 9 | LattePhpVariableImpl(PHP_VARIABLE)('$foo') 10 | PsiElement(LatteTokenType.T_MACRO_ARGS_VAR)('$foo') 11 | PsiElement(LatteTokenType.T_MACRO_TAG_CLOSE)('}') -------------------------------------------------------------------------------- /src/test/resources/data/php/context/HtmlTag.latte: -------------------------------------------------------------------------------- 1 |
    {$name}
    -------------------------------------------------------------------------------- /src/test/resources/data/php/context/InBlock.latte: -------------------------------------------------------------------------------- 1 | {block foo} 2 | {var string $foo = 123} 3 | {/block} -------------------------------------------------------------------------------- /src/test/resources/data/php/context/NetteAttrComplexForeach.latte: -------------------------------------------------------------------------------- 1 |
    {$value}
    -------------------------------------------------------------------------------- /src/test/resources/data/php/context/NetteAttribute.latte: -------------------------------------------------------------------------------- 1 |
    -------------------------------------------------------------------------------- /src/test/resources/data/php/context/NetteAttributeForeach.latte: -------------------------------------------------------------------------------- 1 |
    -------------------------------------------------------------------------------- /src/test/resources/data/php/context/Variable.latte: -------------------------------------------------------------------------------- 1 | {var string $foo = 123} 2 | -------------------------------------------------------------------------------- /src/test/resources/data/php/context/VariableInNFor.latte: -------------------------------------------------------------------------------- 1 |
  • 2 | foo 3 |
  • -------------------------------------------------------------------------------- /src/test/resources/data/php/context/VariablesInDefine.latte: -------------------------------------------------------------------------------- 1 | {define input, $name, $value, $type = 'text'} 2 | 3 | {/define} -------------------------------------------------------------------------------- /src/test/resources/data/php/definition/BlockInIf.latte: -------------------------------------------------------------------------------- 1 | {varType float $activityLog} 2 | 3 | {if true} 4 | {$activityLog} 5 | {/if} -------------------------------------------------------------------------------- /src/test/resources/data/php/definition/BlockWithNAttr.latte: -------------------------------------------------------------------------------- 1 | 2 | {block} 3 | {var $val = array()} 4 | {$val} 5 | {/block} 6 | 7 |
    8 | {$value} 9 |
    10 | {$value} -------------------------------------------------------------------------------- /src/test/resources/data/php/definition/OtherVariables.latte: -------------------------------------------------------------------------------- 1 | {varType float $activityLog} 2 | {var $activityLog = 123} 3 | 4 | {if true} 5 | {$activityLog} 6 | {/if} -------------------------------------------------------------------------------- /src/test/resources/data/php/definition/Variable.latte: -------------------------------------------------------------------------------- 1 | {varType App\Users\UserAdmin[] $admins} 2 |
    {$admins}
    -------------------------------------------------------------------------------- /src/test/resources/data/php/definition/VariableInNFor.latte: -------------------------------------------------------------------------------- 1 |
  • 2 | foo 3 |
  • -------------------------------------------------------------------------------- /src/test/resources/data/php/definition/VariableInside.latte: -------------------------------------------------------------------------------- 1 | 2 | {block} 3 | {var $val = array()} 4 | {$val} 5 | {/block} -------------------------------------------------------------------------------- /src/test/resources/data/php/definitionBefore/DefinitionInBlock.latte: -------------------------------------------------------------------------------- 1 | {varType float $activityLog} 2 | {var $activityLog = 123} 3 | 4 | {if true} 5 | {$activityLog} 6 | {/if} -------------------------------------------------------------------------------- /src/test/resources/data/php/definitionBefore/SimpleDefinition.latte: -------------------------------------------------------------------------------- 1 | {var $foo = 123} 2 | {$foo} -------------------------------------------------------------------------------- /src/test/resources/data/php/isDefinition/DefinitionInNForeach.latte: -------------------------------------------------------------------------------- 1 | {var $foos = []} 2 |
    -------------------------------------------------------------------------------- /src/test/resources/data/php/isDefinition/DefinitionInNForeachWithBefore.latte: -------------------------------------------------------------------------------- 1 | {var $foos = []} 2 |
    3 | 4 | {define bar} 5 | {var $foos = []} 6 |
    7 | {/define} -------------------------------------------------------------------------------- /src/test/resources/data/php/isDefinition/VarTypeDefinition.latte: -------------------------------------------------------------------------------- 1 | {varType string $foo} 2 | {var $foo = 'bar'} 3 | {$foo} -------------------------------------------------------------------------------- /src/test/resources/data/php/variables/variableType/ArrayDefinition.latte: -------------------------------------------------------------------------------- 1 | {var $foo = []} 2 | {$foo} 3 | -------------------------------------------------------------------------------- /src/test/resources/data/php/variables/variableType/BlockDefinition.latte: -------------------------------------------------------------------------------- 1 | {define input, float $name, int[] $value, $type = 'text'} 2 | 3 | {/define} -------------------------------------------------------------------------------- /src/test/resources/data/php/variables/variableType/ClassDefinition.latte: -------------------------------------------------------------------------------- 1 | {varType \PDO[][] $foo} 2 | {var $bar = $foo[0]} 3 | {var $pdo = $bar[0]} 4 | -------------------------------------------------------------------------------- /src/test/resources/data/php/variables/variableType/ForDefinition.latte: -------------------------------------------------------------------------------- 1 | {for $x = 0; $x < 25; $x++} 2 | 3 | {/for} 4 | -------------------------------------------------------------------------------- /src/test/resources/data/php/variables/variableType/ForeachArrowDefinition.latte: -------------------------------------------------------------------------------- 1 | {var \PDO[][] $foo = []} 2 | {foreach $foo as $key => $bar} 3 | 4 | {/foreach} 5 | -------------------------------------------------------------------------------- /src/test/resources/data/php/variables/variableType/ForeachArrowNestedArrayDefinition.latte: -------------------------------------------------------------------------------- 1 | {var \PDO[][] $foo = []} 2 | {foreach $foo as $key => [$bar, $test]} 3 | 4 | {/foreach} 5 | -------------------------------------------------------------------------------- /src/test/resources/data/php/variables/variableType/ForeachDefinition.latte: -------------------------------------------------------------------------------- 1 | {var \PDO[] $foo = []} 2 | {foreach $foo as $bar} 3 | 4 | {/foreach} 5 | -------------------------------------------------------------------------------- /src/test/resources/data/php/variables/variableType/ForeachNestedArrayDefinition.latte: -------------------------------------------------------------------------------- 1 | {var \PDO[][] $foo = []} 2 | {foreach $foo as [$bar, $test]} 3 | 4 | {/foreach} 5 | -------------------------------------------------------------------------------- /src/test/resources/data/php/variables/variableType/ForeachReferenceDefinition.latte: -------------------------------------------------------------------------------- 1 | {var \PDO[] $foo = []} 2 | {foreach $foo as & $bar} 3 | 4 | {/foreach} 5 | -------------------------------------------------------------------------------- /src/test/resources/data/php/variables/variableType/MethodDefinition.latte: -------------------------------------------------------------------------------- 1 | {var \DateTime[] $foo = []} 2 | {var $bar = $foo[0]->format("test")} 3 | -------------------------------------------------------------------------------- /src/test/resources/data/php/variables/variableType/NForeachArrowDefinition.latte: -------------------------------------------------------------------------------- 1 | {var \PDO[][] $foo = []} 2 |

    3 | 4 |

    5 | -------------------------------------------------------------------------------- /src/test/resources/data/php/variables/variableType/ParametersDefinition.latte: -------------------------------------------------------------------------------- 1 | {parameters 2 | $a, 3 | ?int $b, 4 | ?\DateTime $c, 5 | int|string $d = 10 6 | } 7 | -------------------------------------------------------------------------------- /src/test/resources/data/php/variables/variableType/TypedDefinition.latte: -------------------------------------------------------------------------------- 1 | {var int[] $foo = [12]} 2 | {var $bar = $foo[0]} 3 | -------------------------------------------------------------------------------- /src/test/resources/data/ss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rixafy/LatteSupport/fab33749a17c38eaf9a159d5ca84a8dfbd07b0cd/src/test/resources/data/ss --------------------------------------------------------------------------------