├── .github
├── PULL_REQUEST_TEMPLATE.md
├── dependabot.yml
└── workflows
│ ├── gradle.yml
│ └── release.yml
├── .gitignore
├── ARCHITECTURE.md
├── LICENSE
├── README.md
├── build.gradle
├── developer-cert-of-origin.txt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── historical-contributors-agreement.txt
├── images
├── ambig-right-click.png
├── ambig1.png
├── ambig2.png
├── color-prefs.png
├── completion.png
├── def-literals.png
├── error-popup.png
├── findusages.png
├── java-grammar.png
├── lexer-templates.png
├── live-preview-error.png
├── live-preview.png
├── lookahead1.png
├── parse-region.png
├── per-file-config.png
├── profiler.png
├── pycharm.png
├── token-tooltips.png
├── tool-console.png
└── unicode.png
├── intellij-plugin-v4.iml
├── scripts
└── github_release_notes.py
└── src
├── main
├── antlr
│ └── org
│ │ └── antlr
│ │ └── intellij
│ │ └── plugin
│ │ └── parser
│ │ ├── ANTLRv4Lexer.g4
│ │ ├── ANTLRv4Parser.g4
│ │ └── LexBasic.g4
├── java
│ └── org
│ │ └── antlr
│ │ └── intellij
│ │ ├── adaptor
│ │ └── parser
│ │ │ └── PsiElementFactory.java
│ │ └── plugin
│ │ ├── ANTLRv4ASTFactory.java
│ │ ├── ANTLRv4Commenter.java
│ │ ├── ANTLRv4ExternalAnnotator.java
│ │ ├── ANTLRv4FileRoot.java
│ │ ├── ANTLRv4FileType.java
│ │ ├── ANTLRv4FileTypeFactory.java
│ │ ├── ANTLRv4FindUsagesProvider.java
│ │ ├── ANTLRv4IconProvider.java
│ │ ├── ANTLRv4Language.java
│ │ ├── ANTLRv4ParserDefinition.java
│ │ ├── ANTLRv4PluginController.java
│ │ ├── ANTLRv4SyntaxHighlighter.java
│ │ ├── ANTLRv4SyntaxHighlighterFactory.java
│ │ ├── ANTLRv4TokenTypes.java
│ │ ├── Icons.java
│ │ ├── PluginIgnoreMissingTokensFileErrorManager.java
│ │ ├── Utils.java
│ │ ├── actions
│ │ ├── AnnotationIntentActionsFactory.java
│ │ ├── ChooseExtractedRuleName.java
│ │ ├── ConfigureANTLRAction.java
│ │ ├── ExtractRuleAction.java
│ │ ├── GenerateLexerRulesForLiteralsAction.java
│ │ ├── GenerateParserAction.java
│ │ ├── InlineRuleAction.java
│ │ ├── MyActionUtils.java
│ │ ├── TestRuleAction.java
│ │ └── UniquifyRuleRefs.java
│ │ ├── adaptors
│ │ ├── ANTLRv4GrammarParser.java
│ │ ├── ANTLRv4LexerAdaptor.java
│ │ └── ANTLRv4LexerState.java
│ │ ├── configdialogs
│ │ ├── ANTLRv4ColorsPage.java
│ │ ├── ANTLRv4GrammarProperties.java
│ │ ├── ANTLRv4GrammarPropertiesComponent.java
│ │ ├── ANTLRv4GrammarPropertiesStore.java
│ │ ├── ANTLRv4ProjectSettings.java
│ │ ├── CaseChangingStrategyConverter.java
│ │ ├── ConfigANTLRDialogPanel.form
│ │ └── ConfigANTLRPerGrammar.java
│ │ ├── editor
│ │ └── ANTLRv4BraceMatcher.java
│ │ ├── folding
│ │ ├── ANTLRv4FoldingBuilder.java
│ │ └── ANTLRv4FoldingSettings.java
│ │ ├── generators
│ │ ├── LiteralChooser.java
│ │ ├── LiteralChooserObject.java
│ │ └── LiteralChooserRenderer.java
│ │ ├── parsing
│ │ ├── CaseChangingCharStream.java
│ │ ├── CaseChangingStrategy.java
│ │ ├── LexerWatchdog.java
│ │ ├── LoadGrammarsToolListener.java
│ │ ├── ParsingResult.java
│ │ ├── ParsingUtils.java
│ │ ├── PreviewInterpreterRuleContext.java
│ │ ├── PreviewParser.java
│ │ ├── RunANTLRListener.java
│ │ ├── RunANTLROnGrammarFile.java
│ │ └── TokenStreamSubset.java
│ │ ├── preview
│ │ ├── AltLabelTextProvider.java
│ │ ├── CancelParserAction.java
│ │ ├── HierarchyViewer.java
│ │ ├── InputPanel.form
│ │ ├── InputPanel.java
│ │ ├── ParseTreeContextualMenu.java
│ │ ├── ParsingResultSelectionListener.java
│ │ ├── PreviewEditorMouseListener.java
│ │ ├── PreviewPanel.java
│ │ ├── PreviewState.java
│ │ ├── ShowAmbigTreesDialog.form
│ │ ├── ShowAmbigTreesDialog.java
│ │ ├── TrackpadZoomingTreeView.java
│ │ ├── UberTreeViewer.java
│ │ └── WrappedFlowLayout.java
│ │ ├── profiler
│ │ ├── ExpertProfilerTableDataModel.java
│ │ ├── ProfilerPanel.form
│ │ ├── ProfilerPanel.java
│ │ ├── ProfilerTableDataModel.java
│ │ └── SimpleProfilerTableDataModel.java
│ │ ├── psi
│ │ ├── ANTLRv4IndexPatternBuilder.java
│ │ ├── AtAction.java
│ │ ├── ChannelSpecNode.java
│ │ ├── GrammarElementRef.java
│ │ ├── GrammarElementRefNode.java
│ │ ├── GrammarSpecNode.java
│ │ ├── LexerRuleRefNode.java
│ │ ├── LexerRuleSpecNode.java
│ │ ├── ModeSpecNode.java
│ │ ├── MyPsiUtils.java
│ │ ├── ParserRuleRefNode.java
│ │ ├── ParserRuleSpecNode.java
│ │ ├── RuleSpecNode.java
│ │ ├── RulesNode.java
│ │ ├── StringLiteralElement.java
│ │ ├── StringLiteralRef.java
│ │ └── TokenSpecNode.java
│ │ ├── refactor
│ │ ├── ANTLRv4RefactoringSupport.java
│ │ └── RefactorUtils.java
│ │ ├── resolve
│ │ ├── ImportResolver.java
│ │ └── TokenVocabResolver.java
│ │ ├── structview
│ │ ├── ANTLRv4ItemPresentation.java
│ │ ├── ANTLRv4StructureViewElement.java
│ │ ├── ANTLRv4StructureViewFactory.java
│ │ └── ANTLRv4StructureViewModel.java
│ │ ├── templates
│ │ ├── ANTLRGenericContext.java
│ │ ├── ANTLRLiveTemplateContext.java
│ │ ├── ANTLRLiveTemplatesProvider.java
│ │ └── OutsideRuleContext.java
│ │ └── validation
│ │ ├── AddTokenDefinitionFix.java
│ │ ├── CreateRuleFix.java
│ │ ├── GrammarInfoMessage.java
│ │ ├── GrammarIssue.java
│ │ ├── GrammarIssuesCollector.java
│ │ └── GrammarIssuesCollectorToolListener.java
└── resources
│ ├── META-INF
│ ├── plugin.xml
│ └── pluginIcon.svg
│ ├── colorSchemes
│ ├── ANTLRv4Darcula.xml
│ └── ANTLRv4Default.xml
│ ├── icons
│ └── org
│ │ └── antlr
│ │ └── intellij
│ │ └── plugin
│ │ ├── antlr-icon.idraw
│ │ ├── antlr-tiny-icon.idraw
│ │ ├── antlr.png
│ │ ├── antlr.svg
│ │ ├── antlr@2x.png
│ │ ├── icons.graffle
│ │ ├── lexer-rule.png
│ │ ├── lexer-rule.svg
│ │ ├── lexer-rule@2x.png
│ │ ├── mode.png
│ │ ├── mode.svg
│ │ ├── mode@2x.png
│ │ ├── parser-rule.png
│ │ ├── parser-rule.svg
│ │ ├── parser-rule@2x.png
│ │ ├── toolWindowAntlr.svg
│ │ └── toolWindowAntlr_dark.svg
│ ├── liveTemplates
│ └── lexer
│ │ └── user.xml
│ └── templates
│ └── org
│ └── antlr
│ └── intellij
│ └── plugin
│ └── gen
│ └── Java.stg
└── test
├── java
└── org
│ └── antlr
│ └── intellij
│ └── plugin
│ ├── ANTLRv4ExternalAnnotatorTest.java
│ ├── TestUtils.java
│ ├── actions
│ └── AnnotationIntentActionsFactoryTest.java
│ ├── configdialogs
│ ├── ANTLRv4GrammarPropertiesStoreTest.java
│ ├── ANTLRv4GrammarPropertiesTest.java
│ └── ConfigANTLRPerGrammarTest.java
│ ├── editor
│ ├── Issue540Test.java
│ ├── Issue559Test.java
│ └── MockToolWindow.java
│ ├── folding
│ └── ANTLRv4FoldingBuilderTest.java
│ ├── parsing
│ ├── Issue374Test.java
│ ├── Issue403Test.java
│ └── RunANTLROnGrammarFileTest.java
│ ├── psi
│ └── GrammarElementRefTest.java
│ └── validation
│ ├── AddTokenDefinitionFixTest.java
│ └── CreateRuleFixTest.java
└── resources
├── editor
├── T1.g4
└── T2.g4
├── parser
└── SqlBase.g4
├── quickfixes
└── CreateRuleFix
│ └── missingRule.g4
└── references
├── FooLexer.g4
├── FooParser.g4
├── FooParser2.g4
├── Modes.g4
├── SimpleGrammar.g4
├── SimpleGrammar2.g4
├── imported.g4
├── imported2.g4
├── imported3.g4
└── importing.g4
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | @@ -1,5 +1,23 @@
2 |
22 |
23 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Dependabot configuration:
2 | # https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates
3 |
4 | version: 2
5 | updates:
6 | - package-ecosystem: "gradle"
7 | directory: "/"
8 | schedule:
9 | interval: "daily"
10 |
--------------------------------------------------------------------------------
/.github/workflows/gradle.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Gradle
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
3 |
4 | name: Java CI
5 |
6 | on: [ push, pull_request ]
7 |
8 | jobs:
9 | build:
10 |
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | fail-fast: false
15 | matrix:
16 | env:
17 | # see https://www.jetbrains.com/idea/download/previous.html
18 | # and https://www.jetbrains.com/intellij-repository/snapshots/
19 | - IDEA_VERSION: IC-2022.3 # Oldest supported version
20 | - IDEA_VERSION: IC-2023.1
21 | - IDEA_VERSION: IC-2023.3.2
22 |
23 | steps:
24 | - uses: actions/checkout@v3
25 | - name: Set up JDK 17
26 | uses: actions/setup-java@v3
27 | with:
28 | java-version: 17
29 | distribution: temurin
30 | - name: Build with Gradle
31 | run: |
32 | ./gradlew -PideaVersion=${IDEA_VERSION} check buildPlugin
33 | env: ${{ matrix.env }}
34 | - name: Archive distribution artifact
35 | uses: actions/upload-artifact@v3
36 | with:
37 | name: "antlr-intellij-development"
38 | path: build/distributions/antlr-intellij-plugin-v4-*.zip
39 | if: matrix.env.IDEA_VERSION == 'IC-2022.3'
40 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Gradle
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
3 |
4 | name: Java CI for releases
5 |
6 | on:
7 | release:
8 | types:
9 | - published
10 |
11 | jobs:
12 | build:
13 |
14 | runs-on: ubuntu-latest
15 |
16 | strategy:
17 | matrix:
18 | env:
19 | # see https://www.jetbrains.com/idea/download/previous.html
20 | # and https://www.jetbrains.com/intellij-repository/snapshots/
21 | - IDEA_VERSION: IC-2022.3.3
22 | SINCE_VERSION: 223
23 | UNTIL_VERSION: 230.*
24 | VERSION_SUFFIX: "-2022"
25 | - IDEA_VERSION: IC-2023.1
26 | SINCE_VERSION: 230
27 | UNTIL_VERSION: 240.*
28 | VERSION_SUFFIX: "-2023"
29 | - IDEA_VERSION: IC-2023.1
30 | SINCE_VERSION: 240
31 | VERSION_SUFFIX:
32 |
33 | steps:
34 | - uses: actions/checkout@v3
35 | - name: Set up JDK 17
36 | uses: actions/setup-java@v3
37 | with:
38 | java-version: 17
39 | distribution: temurin
40 |
41 | - name: Build with Gradle
42 | run: |
43 | ./gradlew -PideaVersion=${IDEA_VERSION} -PsinceBuildVersion=${SINCE_VERSION} -PuntilBuildVersion=${UNTIL_VERSION} -PpluginVersion=${GITHUB_REF_NAME}${VERSION_SUFFIX} check buildPlugin
44 | env: ${{ matrix.env }}
45 |
46 | - name: Archive distribution artifact
47 | uses: actions/upload-artifact@v3
48 | with:
49 | name: "antlr-intellij${{matrix.env.VERSION_SUFFIX}}"
50 | path: build/distributions/antlr-intellij-plugin-v4-*.zip
51 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build intermediate
2 | /gen/
3 |
4 | # Build output
5 | /out/
6 | /build/
7 |
8 | # downloaded libs/resources
9 | /lib/
10 |
11 | .gradle/
12 |
13 | *.pyc
14 | bilder.py
15 | intellij-plugin-v4.iml
16 |
17 | # Per-user settings
18 | # https://intellij-support.jetbrains.com/entries/23393067
19 |
20 | .idea/scopes/
21 | .idea/modules/
22 | .idea/copyright/
23 | .idea/libraries/
24 | .idea/codeStyles/
25 | .idea/inspectionProfiles/
26 |
27 | .idea/ant.xml
28 | .idea/vcs.xml
29 | .idea/misc.xml
30 | .idea/tasks.xml
31 | .idea/gradle.xml
32 | .idea/kotlinc.xml
33 | .idea/modules.xml
34 | .idea/compiler.xml
35 | .idea/encodings.xml
36 | .idea/workspace.xml
37 | .idea/uiDesigner.xml
38 | .idea/dbnavigator.xml
39 | .idea/preferred-vcs.xml
40 | .idea/codeStyleSettings.xml
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/ARCHITECTURE.md:
--------------------------------------------------------------------------------
1 | # Plugin architecture
2 |
3 | ## Build
4 |
5 | Gradle is used to build the project. [`gradle-intellij-plugin`][1] is used to pull
6 | any given version of IntelliJ to add its JARs to the classpath, build forms,
7 | publish to the marketplace etc.
8 |
9 | GitHub Actions are used for continuous integration, see files in `.github/workflows`.
10 |
11 | ## Lexing/parsing
12 |
13 | An ANTLR v4 grammar in `src/main/antlr` is used to generate a lexer/parser.
14 | `ANTLRv4ParserDefinition` uses the [`antlr4-intellij-adaptor` library][2] to
15 | delegate parsing/lexing to these generated classes.
16 |
17 | Syntax highlighting is also using the generated lexer (by delegation) in
18 | `org.antlr.intellij.plugin.ANTLRv4SyntaxHighlighter.getHighlightingLexer`.
19 |
20 | ## Error checking
21 |
22 | The plugin embeds a complete version of ANTLR v4. To highlight warnings in the
23 | editor, the file is parsed again in `ANTLRv4ExternalAnnotator`, but this time
24 | using the "official" parser. The annotator constructs a `org.antlr.v4.Tool`
25 | with all the flags configured in the `Configure ANTLR...` dialog.
26 | `GrammarIssuesCollector` sets up an error listener, then processes all the issues
27 | reported by the `Tool` to show them in the editor.
28 |
29 | ## Preview window
30 |
31 | Contrary to ANTLRWorks, the IntelliJ plugin does not run the actual generated
32 | parser to test a grammar. Instead, it uses [ANTLR interpreters][3]. This is
33 | mainly because the IDE classpath and the project classpath are totally different,
34 | meaning generated parsers and their custom code and dependencies are not
35 | available from the IDE process.
36 |
37 | The interpreter provides a convenient way to "run" grammars without needing
38 | any generated code. A major drawback of this approach is that custom code will
39 | not be executed: `@members`, actions, predicates...
40 |
41 | The entry point for the preview window is `PreviewPanel`, which holds the main
42 | Swing component displayed in the tool window. It uses `ANTLRv4PluginController`
43 | to maintain a cache of parsed grammars that can be previewed. Everytime the
44 | editor switches to another .g4 grammar, the preview is updated accordingly:
45 | the input text and selected rule are restored to their previous state (if any),
46 | and the interpreter results are updated. Interpreter results include profiling
47 | data, a list of tokens and a tree of matched rules and terminal nodes (both
48 | in graphical form and in JTree form).
49 |
50 | `PreviewPanel` acts as an orchestrator between inputs (grammar changed event,
51 | input text changed event) and outputs (profiler, token list, parse tree etc.).
52 |
53 | Since the preview panel has full control over the interpreter, it can monitor
54 | the parsing phase to detect potential infinite loops caused by bad grammars,
55 | thus preventing IDE freezes or OutOfMemoryExceptions.
56 |
57 | [1]: https://github.com/JetBrains/gradle-intellij-plugin
58 | [2]: https://github.com/antlr/antlr4-intellij-adaptor/
59 | [3]: https://github.com/antlr/antlr4/blob/master/doc/interpreters.md
60 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013, Terence Parr
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification,
5 | are permitted provided that the following conditions are met:
6 |
7 | Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | Redistributions in binary form must reproduce the above copyright notice, this
11 | list of conditions and the following disclaimer in the documentation and/or
12 | other materials provided with the distribution.
13 |
14 | Neither the name of the {organization} nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | mavenCentral()
4 | }
5 | }
6 |
7 | plugins {
8 | id "org.jetbrains.intellij" version "1.17.4"
9 | }
10 |
11 | wrapper {
12 | gradleVersion = '7.5'
13 | }
14 |
15 | group 'antlr'
16 | version pluginVersion
17 |
18 | apply plugin: 'java'
19 | apply plugin: 'org.jetbrains.intellij'
20 | apply plugin: 'antlr'
21 |
22 | compileJava {
23 | sourceCompatibility = '17'
24 | targetCompatibility = '17'
25 | }
26 |
27 | intellij {
28 | version = ideaVersion
29 |
30 | pluginName = 'antlr-intellij-plugin-v4'
31 | downloadSources = true
32 | updateSinceUntilBuild = true
33 |
34 | patchPluginXml {
35 | sinceBuild = sinceBuildVersion
36 | untilBuild = untilBuildVersion
37 | }
38 | }
39 |
40 | repositories {
41 | mavenCentral()
42 | mavenLocal()
43 | maven { // Gets snapshots of antlr if needed
44 | url "https://oss.sonatype.org/content/repositories/snapshots/"
45 | }
46 | }
47 |
48 | dependencies {
49 | antlr("org.antlr:antlr4:$antlr4Version") { // use ANTLR version 4
50 | exclude group:'com.ibm.icu', module:'icu4j'
51 | }
52 | implementation "org.antlr:antlr4-intellij-adaptor:0.1"
53 | implementation group: 'org.jfree', name: 'org.jfree.svg', version: '5.0.6'
54 | testImplementation group: 'junit', name: 'junit', version: '4.13.2'
55 | testImplementation group: 'org.mockito', name: 'mockito-core', version: '5.15.2'
56 | }
57 |
58 | generateGrammarSource {
59 | include("**/ANTLRv4*.g4")
60 |
61 | arguments += [
62 | "-package", "org.antlr.intellij.plugin.parser",
63 | "-lib", "src/main/antlr/org/antlr/intellij/plugin/parser",
64 | "-Xexact-output-dir"
65 | ]
66 | }
67 |
68 | test {
69 | testLogging {
70 | events "failed"
71 | exceptionFormat "full"
72 | }
73 | }
74 |
75 | runIde {
76 | jvmArgs '-Xmx8G'
77 | }
78 |
--------------------------------------------------------------------------------
/developer-cert-of-origin.txt:
--------------------------------------------------------------------------------
1 | As of 1.18, the ANTLR plugin uses the Linux Foundation's Developer
2 | Certificate of Origin, DCO, version 1.1. See either
3 | https://developercertificate.org/ or the text below.
4 |
5 | Each commit requires a "signature", which is simple as
6 | using `-s` (not `-S`) to the git commit command:
7 |
8 | git commit -s -m 'This is my commit message'
9 |
10 | Github's pull request process enforces the sig and gives
11 | instructions on how to fix any commits that lack the sig.
12 | See https://github.com/apps/dco for more info.
13 |
14 | No signature is required in this file (unlike the
15 | previous contributor's certificate of origin.)
16 |
17 | ----- https://developercertificate.org/ ------
18 |
19 | Developer Certificate of Origin
20 | Version 1.1
21 |
22 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
23 |
24 | Everyone is permitted to copy and distribute verbatim copies of this
25 | license document, but changing it is not allowed.
26 |
27 |
28 | Developer's Certificate of Origin 1.1
29 |
30 | By making a contribution to this project, I certify that:
31 |
32 | (a) The contribution was created in whole or in part by me and I
33 | have the right to submit it under the open source license
34 | indicated in the file; or
35 |
36 | (b) The contribution is based upon previous work that, to the best
37 | of my knowledge, is covered under an appropriate open source
38 | license and I have the right under that license to submit that
39 | work with modifications, whether created in whole or in part
40 | by me, under the same open source license (unless I am
41 | permitted to submit under a different license), as indicated
42 | in the file; or
43 |
44 | (c) The contribution was provided directly to me by some other
45 | person who certified (a), (b) or (c) and I have not modified
46 | it.
47 |
48 | (d) I understand and agree that this project and the contribution
49 | are public and that a record of the contribution (including all
50 | personal information I submit with it, including my sign-off) is
51 | maintained indefinitely and may be redistributed consistent with
52 | this project or the open source license(s) involved.
53 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Overridden by Gradle during releases
2 | pluginVersion=1.24
3 |
4 | # e.g. IC-2016.3.3, IU-2018.2.5 etc
5 | # For a list of possible values, refer to the section 'com.jetbrains.intellij.idea' at
6 | # https://www.jetbrains.com/idea/download/other.html
7 |
8 | # Oldest version currently supported
9 | ideaVersion=IC-2022.3
10 |
11 | #ideaVersion=IC-2023.1
12 |
13 | # The version of ANTLR v4 that will be used to generate the parser
14 | antlr4Version=4.13.2
15 |
16 | # Lower platform version supported by this build. Leave empty to keep the default value in plugin.xml.
17 | sinceBuildVersion=
18 | # Upper platform version supported by this build. Leave empty to support latest versions.
19 | untilBuildVersion=
20 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/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-7.6-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if %ERRORLEVEL% equ 0 goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if %ERRORLEVEL% equ 0 goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | set EXIT_CODE=%ERRORLEVEL%
84 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
85 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
86 | exit /b %EXIT_CODE%
87 |
88 | :mainEnd
89 | if "%OS%"=="Windows_NT" endlocal
90 |
91 | :omega
92 |
--------------------------------------------------------------------------------
/historical-contributors-agreement.txt:
--------------------------------------------------------------------------------
1 | ANTLR Project Contributors Certification of Origin and Rights
2 |
3 | All contributors to ANTLR v4 must formally agree to abide by this
4 | certificate of origin by signing on the bottom with their github
5 | userid, full name, email address (you can obscure your e-mail, but it
6 | must be computable by human), and date.
7 |
8 | By signing this agreement, you are warranting and representing that
9 | you have the right to release code contributions or other content free
10 | of any obligations to third parties and are granting Terence Parr and
11 | ANTLR project contributors, henceforth referred to as The ANTLR
12 | Project, a license to incorporate it into The ANTLR Project tools
13 | (such as ANTLRWorks and StringTemplate) or related works under the BSD
14 | license. You understand that The ANTLR Project may or may not
15 | incorporate your contribution and you warrant and represent the
16 | following:
17 |
18 | 1. I am the creator of all my contributions. I am the author of all
19 | contributed work submitted and further warrant and represent that
20 | such work is my original creation and I have the right to license
21 | it to The ANTLR Project for release under the 3-clause BSD
22 | license. I hereby grant The ANTLR Project a nonexclusive,
23 | irrevocable, royalty-free, worldwide license to reproduce,
24 | distribute, prepare derivative works, and otherwise use this
25 | contribution as part of the ANTLR project, associated
26 | documentation, books, and tools at no cost to The ANTLR Project.
27 |
28 | 2. I have the right to submit. This submission does not violate the
29 | rights of any person or entity and that I have legal authority over
30 | this submission and to make this certification.
31 |
32 | 3. If I violate another's rights, liability lies with me. I agree to
33 | defend, indemnify, and hold The ANTLR Project and ANTLR users
34 | harmless from any claim or demand, including reasonable attorney
35 | fees, made by any third party due to or arising out of my violation
36 | of these terms and conditions or my violation of the rights of
37 | another person or entity.
38 |
39 | 4. I understand and agree that this project and the contribution are
40 | public and that a record of the contribution (including all
41 | personal information I submit with it, including my sign-off) is
42 | maintained indefinitely and may be redistributed consistent with
43 | this project or the open source license indicated in the file.
44 |
45 | I have read this agreement and do so certify by adding my signoff to
46 | the end of the following contributors list.
47 |
48 | CONTRIBUTORS:
49 |
50 | YYYY/MM/DD, github id, Full name, email
51 | 2012/07/12, parrt, Terence Parr, parrt@antlr.org
52 | 2014/01/30, sharwell, Sam Harwell, sam@tunnelvisionlabs.com
53 | 2014/04/04, migulorama, Miguel Marques, migulorama@gmail.com
54 | 2014/04/21, mhordecki, Mike Hordecki, mike@hordecki.com
55 | 2014/12/22, ponomandr, Andrey Ponomarev, ponomandr@gmail.com
56 | 2015/02/07, jasonnn, Jason Markham, jasonmarkham@gmail.com
57 | 2015/03/26, alekum, Alexey Kuzmenko, rojaster@yandex.ru(1ikb3zz@gmail.com)
58 | 2015/07/30, maccimo, Maxim Degtyarev, mdegtyarev@gmail.com
59 | 2015/08/12, bjansen, Bastien Jansen, bastien.jansen@gmx.com
60 | 2016/01/08, jwhiting, James Whiting, james.whiting@gmail.com
61 | 2018/10/24, brizjin, Ivan Bryzzhin, brizjin@gmail.com
62 | 2019/06/29, alexkli, Alexander Klimetschek, aklimets@adobe.com
63 | 2019/07/10, wojciszek, Wojciech Kruczkowski, kruczkowski.wojciech@gmail.com
64 | 2019/11/24, nopeslide, Uffke Drechsler, nopeslide@web.de
65 | 2020/12/05, roggenbrot, Sascha Dais, sdais@gmx.net
66 | 2021/11/04, OleksiiKovalov, Oleksii Kovalov, Oleksii.Kovalov@outlook.com
67 |
68 |
--------------------------------------------------------------------------------
/images/ambig-right-click.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/ambig-right-click.png
--------------------------------------------------------------------------------
/images/ambig1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/ambig1.png
--------------------------------------------------------------------------------
/images/ambig2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/ambig2.png
--------------------------------------------------------------------------------
/images/color-prefs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/color-prefs.png
--------------------------------------------------------------------------------
/images/completion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/completion.png
--------------------------------------------------------------------------------
/images/def-literals.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/def-literals.png
--------------------------------------------------------------------------------
/images/error-popup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/error-popup.png
--------------------------------------------------------------------------------
/images/findusages.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/findusages.png
--------------------------------------------------------------------------------
/images/java-grammar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/java-grammar.png
--------------------------------------------------------------------------------
/images/lexer-templates.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/lexer-templates.png
--------------------------------------------------------------------------------
/images/live-preview-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/live-preview-error.png
--------------------------------------------------------------------------------
/images/live-preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/live-preview.png
--------------------------------------------------------------------------------
/images/lookahead1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/lookahead1.png
--------------------------------------------------------------------------------
/images/parse-region.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/parse-region.png
--------------------------------------------------------------------------------
/images/per-file-config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/per-file-config.png
--------------------------------------------------------------------------------
/images/profiler.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/profiler.png
--------------------------------------------------------------------------------
/images/pycharm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/pycharm.png
--------------------------------------------------------------------------------
/images/token-tooltips.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/token-tooltips.png
--------------------------------------------------------------------------------
/images/tool-console.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/tool-console.png
--------------------------------------------------------------------------------
/images/unicode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/images/unicode.png
--------------------------------------------------------------------------------
/intellij-plugin-v4.iml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/scripts/github_release_notes.py:
--------------------------------------------------------------------------------
1 | # Get github issues / PR for a release
2 | # Exec with "python github_release_notes.py YOUR_GITHUB_API_ACCESS_TOKEN 1.19"
3 |
4 | import sys
5 | from collections import Counter
6 | from github import Github
7 |
8 | TOKEN=sys.argv[1]
9 | MILESTONE=sys.argv[2]
10 | g = Github(login_or_token=TOKEN)
11 |
12 | # Then play with your Github objects:
13 | org = g.get_organization("antlr")
14 | repo = org.get_repo("intellij-plugin-v4")
15 | milestone = [x for x in repo.get_milestones() if x.title==MILESTONE]
16 | milestone = milestone[0]
17 |
18 | issues = repo.get_issues(state="closed", milestone=milestone, sort="created", direction="desc")
19 |
20 | # dump bugs fixed
21 | print()
22 | print("## Issues fixed")
23 | for x in issues:
24 | labels = [l.name for l in x.labels]
25 | if x.pull_request is None and not ("type:improvement" in labels or "type:feature" in labels):
26 | print("* [%s](%s) (%s)" % (x.title, x.html_url, ", ".join([l.name for l in x.labels])))
27 |
28 | # dump improvements closed for this release (issues or pulls)
29 | print()
30 | print("## Improvements, features")
31 | for x in issues:
32 | labels = [l.name for l in x.labels]
33 | if ("type:enhancement" in labels or "type:feature" in labels):
34 | print("* [%s](%s) (%s)" % (x.title, x.html_url, ", ".join(labels)))
35 |
36 | # dump PRs closed for this release
37 | print()
38 | print("## Pull requests")
39 | for x in issues:
40 | labels = [l.name for l in x.labels]
41 | if x.pull_request is not None:
42 | print("* [%s](%s) (%s)" % (x.title, x.html_url, ", ".join(labels)))
43 |
44 | # dump contributors
45 | print()
46 | print("## Contributors")
47 | user_counts = Counter([x.user.login for x in issues])
48 | users = {x.user.login:x.user for x in issues}
49 | for login,count in user_counts.most_common(10000):
50 | name = users[login].name
51 | logins = f" ({users[login].login})"
52 | if name is None:
53 | name = users[login].login
54 | logins = ""
55 | print(f"* {count:3d} items: [{name}]({users[login].html_url}){logins}")
56 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/adaptor/parser/PsiElementFactory.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.adaptor.parser;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.psi.PsiElement;
5 |
6 | /**
7 | * This interface supports constructing a {@link PsiElement} from an {@link ASTNode}.
8 | */
9 | public interface PsiElementFactory {
10 | PsiElement createElement(ASTNode node);
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/ANTLRv4ASTFactory.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.extapi.psi.ASTWrapperPsiElement;
4 | import com.intellij.lang.ASTFactory;
5 | import com.intellij.lang.ASTNode;
6 | import com.intellij.psi.PsiElement;
7 | import com.intellij.psi.impl.source.tree.CompositeElement;
8 | import com.intellij.psi.impl.source.tree.FileElement;
9 | import com.intellij.psi.impl.source.tree.LeafElement;
10 | import com.intellij.psi.impl.source.tree.LeafPsiElement;
11 | import com.intellij.psi.tree.IElementType;
12 | import com.intellij.psi.tree.IFileElementType;
13 | import org.antlr.intellij.adaptor.parser.PsiElementFactory;
14 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
15 | import org.antlr.intellij.plugin.parser.ANTLRv4Parser;
16 | import org.antlr.intellij.plugin.psi.*;
17 |
18 | import java.util.HashMap;
19 | import java.util.Map;
20 |
21 | public class ANTLRv4ASTFactory extends ASTFactory {
22 | private static final Map ruleElementTypeToPsiFactory = new HashMap<>();
23 | static {
24 | // later auto gen with tokens from some spec in grammar?
25 | ruleElementTypeToPsiFactory.put(ANTLRv4TokenTypes.RULE_ELEMENT_TYPES.get(ANTLRv4Parser.RULE_rules), RulesNode.Factory.INSTANCE);
26 | ruleElementTypeToPsiFactory.put(ANTLRv4TokenTypes.RULE_ELEMENT_TYPES.get(ANTLRv4Parser.RULE_parserRuleSpec), ParserRuleSpecNode.Factory.INSTANCE);
27 | ruleElementTypeToPsiFactory.put(ANTLRv4TokenTypes.RULE_ELEMENT_TYPES.get(ANTLRv4Parser.RULE_lexerRule), LexerRuleSpecNode.Factory.INSTANCE);
28 | ruleElementTypeToPsiFactory.put(ANTLRv4TokenTypes.RULE_ELEMENT_TYPES.get(ANTLRv4Parser.RULE_grammarSpec), GrammarSpecNode.Factory.INSTANCE);
29 | ruleElementTypeToPsiFactory.put(ANTLRv4TokenTypes.RULE_ELEMENT_TYPES.get(ANTLRv4Parser.RULE_modeSpec), ModeSpecNode.Factory.INSTANCE);
30 | ruleElementTypeToPsiFactory.put(ANTLRv4TokenTypes.RULE_ELEMENT_TYPES.get(ANTLRv4Parser.RULE_action), AtAction.Factory.INSTANCE);
31 | ruleElementTypeToPsiFactory.put(ANTLRv4TokenTypes.RULE_ELEMENT_TYPES.get(ANTLRv4Parser.RULE_identifier), TokenSpecNode.Factory.INSTANCE);
32 | }
33 |
34 | /** Create a FileElement for root or a parse tree CompositeElement (not
35 | * PSI) for the token. This impl is more or less the default.
36 | */
37 | @Override
38 | public CompositeElement createComposite(IElementType type) {
39 | if (type instanceof IFileElementType) {
40 | return new FileElement(type, null);
41 | }
42 | return new CompositeElement(type);
43 | }
44 |
45 | /** Create PSI nodes out of tokens so even parse tree sees them as such.
46 | * Does not see whitespace tokens.
47 | */
48 | @Override
49 | public LeafElement createLeaf(IElementType type, CharSequence text) {
50 | LeafElement t;
51 | if ( type == ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.RULE_REF) ) {
52 | t = new ParserRuleRefNode(type, text);
53 | }
54 | else if ( type == ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.TOKEN_REF) ) {
55 | t = new LexerRuleRefNode(type, text);
56 | }
57 | else if ( type == ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.STRING_LITERAL) ) {
58 | t = new StringLiteralElement(type, text);
59 | }
60 | else {
61 | t = new LeafPsiElement(type, text);
62 | }
63 | return t;
64 | }
65 |
66 | public static PsiElement createInternalParseTreeNode(ASTNode node) {
67 | PsiElement t;
68 | IElementType tokenType = node.getElementType();
69 | PsiElementFactory factory = ruleElementTypeToPsiFactory.get(tokenType);
70 | if (factory != null) {
71 | t = factory.createElement(node);
72 | }
73 | else {
74 | t = new ASTWrapperPsiElement(node);
75 | }
76 |
77 | return t;
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/ANTLRv4Commenter.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.lang.CodeDocumentationAwareCommenter;
4 | import com.intellij.psi.PsiComment;
5 | import com.intellij.psi.tree.IElementType;
6 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
7 | import org.jetbrains.annotations.Nullable;
8 |
9 | /**
10 | * Created by jason on 1/7/15.
11 | */
12 |
13 | //DOC_COMMENT
14 | // : '/**' .*? ('*/' | EOF)
15 | // ;
16 | //BLOCK_COMMENT
17 | // : '/*' .*? ('*/' | EOF) -> channel(HIDDEN)
18 | // ;
19 | //
20 | //LINE_COMMENT
21 | // : '//' ~[\r\n]* -> channel(HIDDEN)
22 | // ;
23 |
24 | public class ANTLRv4Commenter implements CodeDocumentationAwareCommenter {
25 | @Nullable
26 | @Override
27 | public String getLineCommentPrefix() {
28 | return "//";
29 | }
30 |
31 | @Nullable
32 | @Override
33 | public String getBlockCommentPrefix() {
34 | return "/*";
35 | }
36 |
37 | @Nullable
38 | @Override
39 | public String getBlockCommentSuffix() {
40 | return "*/";
41 | }
42 |
43 | @Nullable
44 | @Override
45 | public String getCommentedBlockCommentPrefix() {
46 | return null;
47 | }
48 |
49 | @Nullable
50 | @Override
51 | public String getCommentedBlockCommentSuffix() {
52 | return null;
53 | }
54 |
55 | @Nullable
56 | @Override
57 | public IElementType getLineCommentTokenType() {
58 | return ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.LINE_COMMENT);
59 | }
60 |
61 | @Nullable
62 | @Override
63 | public IElementType getBlockCommentTokenType() {
64 | return ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.BLOCK_COMMENT);
65 |
66 | }
67 |
68 | @Nullable
69 | @Override
70 | public IElementType getDocumentationCommentTokenType() {
71 | return ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.DOC_COMMENT);
72 | }
73 |
74 | @Nullable
75 | @Override
76 | public String getDocumentationCommentPrefix() {
77 | return "/**";
78 | }
79 |
80 | @Nullable
81 | @Override
82 | public String getDocumentationCommentLinePrefix() {
83 | //TODO: this isnt specified in the grammar. remove?
84 | return "*";
85 | }
86 |
87 | @Nullable
88 | @Override
89 | public String getDocumentationCommentSuffix() {
90 | return "*/";
91 | }
92 |
93 | @Override
94 | public boolean isDocumentationComment(PsiComment element) {
95 | return element != null && element.getTokenType() == getDocumentationCommentTokenType();
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/ANTLRv4FileRoot.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.extapi.psi.PsiFileBase;
4 | import com.intellij.openapi.fileTypes.FileType;
5 | import com.intellij.psi.FileViewProvider;
6 | import org.jetbrains.annotations.NotNull;
7 |
8 | public class ANTLRv4FileRoot extends PsiFileBase {
9 | public ANTLRv4FileRoot(@NotNull FileViewProvider viewProvider) {
10 | super(viewProvider, ANTLRv4Language.INSTANCE);
11 | }
12 |
13 | @NotNull
14 | @Override
15 | public FileType getFileType() {
16 | return ANTLRv4FileType.INSTANCE;
17 | }
18 |
19 | @Override
20 | public String toString() {
21 | return "ANTLR v4 grammar file";
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/ANTLRv4FileType.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.openapi.fileTypes.LanguageFileType;
4 | import org.jetbrains.annotations.NotNull;
5 | import org.jetbrains.annotations.Nullable;
6 |
7 | import javax.swing.*;
8 |
9 | public class ANTLRv4FileType extends LanguageFileType {
10 | public static final ANTLRv4FileType INSTANCE = new ANTLRv4FileType();
11 |
12 | private ANTLRv4FileType() {
13 | super(ANTLRv4Language.INSTANCE);
14 | }
15 |
16 | @NotNull
17 | @Override
18 | public String getName() {
19 | return "ANTLR v4 grammar file";
20 | }
21 |
22 | @NotNull
23 | @Override
24 | public String getDescription() {
25 | return "ANTLR v4 grammar file";
26 | }
27 |
28 | @NotNull
29 | @Override
30 | public String getDefaultExtension() {
31 | return "g4";
32 | }
33 |
34 | @Nullable
35 | @Override
36 | public Icon getIcon() {
37 | return Icons.FILE;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/ANTLRv4FileTypeFactory.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.openapi.fileTypes.FileTypeConsumer;
4 | import com.intellij.openapi.fileTypes.FileTypeFactory;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | public class ANTLRv4FileTypeFactory extends FileTypeFactory{
8 | @Override
9 | public void createFileTypes(@NotNull FileTypeConsumer fileTypeConsumer) {
10 | fileTypeConsumer.consume(ANTLRv4FileType.INSTANCE, "g4");
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/ANTLRv4FindUsagesProvider.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.lang.cacheBuilder.WordsScanner;
4 | import com.intellij.lang.findUsages.FindUsagesProvider;
5 | import com.intellij.psi.PsiElement;
6 | import com.intellij.psi.util.PsiTreeUtil;
7 | import org.antlr.intellij.plugin.psi.*;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.jetbrains.annotations.Nullable;
10 |
11 | public class ANTLRv4FindUsagesProvider implements FindUsagesProvider {
12 | @Override
13 | public boolean canFindUsagesFor(@NotNull PsiElement psiElement) {
14 | return psiElement instanceof RuleSpecNode;
15 | }
16 |
17 | @Nullable
18 | @Override
19 | public WordsScanner getWordsScanner() {
20 | return null; // seems ok as JavaFindUsagesProvider does same thing
21 | }
22 |
23 | @Nullable
24 | @Override
25 | public String getHelpId(@NotNull PsiElement element) {
26 | return null;
27 | }
28 |
29 | @NotNull
30 | @Override
31 | public String getType(@NotNull PsiElement element) {
32 | if (element instanceof ParserRuleSpecNode) {
33 | return "parser rule";
34 | }
35 | if (element instanceof LexerRuleSpecNode) {
36 | return "lexer rule";
37 | }
38 | if (element instanceof ModeSpecNode) {
39 | return "mode";
40 | }
41 | if (element instanceof TokenSpecNode) {
42 | return "token";
43 | }
44 | if (element instanceof ChannelSpecNode) {
45 | return "channel";
46 | }
47 | return "n/a";
48 | }
49 |
50 | @NotNull
51 | @Override
52 | public String getDescriptiveName(@NotNull PsiElement element) {
53 | PsiElement rule = PsiTreeUtil.findChildOfAnyType(element, LexerRuleRefNode.class, ParserRuleRefNode.class);
54 | if ( rule!=null ) return rule.getText();
55 | return "n/a";
56 | }
57 |
58 | @NotNull
59 | @Override
60 | public String getNodeText(@NotNull PsiElement element, boolean useFullName) {
61 | return getDescriptiveName(element);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/ANTLRv4IconProvider.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.ide.IconProvider;
4 | import com.intellij.psi.PsiElement;
5 | import org.antlr.intellij.plugin.psi.LexerRuleRefNode;
6 | import org.antlr.intellij.plugin.psi.ModeSpecNode;
7 | import org.antlr.intellij.plugin.psi.ParserRuleRefNode;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.jetbrains.annotations.Nullable;
10 |
11 | import javax.swing.*;
12 |
13 | public class ANTLRv4IconProvider extends IconProvider {
14 |
15 | @Nullable
16 | @Override
17 | public Icon getIcon(@NotNull PsiElement element, int flags) {
18 | if ( element instanceof LexerRuleRefNode ) {
19 | return Icons.LEXER_RULE;
20 | }
21 | else if ( element instanceof ParserRuleRefNode ) {
22 | return Icons.PARSER_RULE;
23 | }
24 | else if ( element instanceof ANTLRv4FileRoot ) {
25 | return Icons.FILE;
26 | }
27 | else if ( element instanceof ModeSpecNode ) {
28 | return Icons.MODE;
29 | }
30 | return null;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/ANTLRv4Language.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.lang.Language;
4 |
5 | public class ANTLRv4Language extends Language {
6 | public static final ANTLRv4Language INSTANCE = new ANTLRv4Language();
7 |
8 | private ANTLRv4Language() {
9 | super("ANTLRv4");
10 | }
11 |
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/ANTLRv4ParserDefinition.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.lang.ParserDefinition;
5 | import com.intellij.lang.PsiParser;
6 | import com.intellij.lexer.Lexer;
7 | import com.intellij.openapi.project.Project;
8 | import com.intellij.psi.FileViewProvider;
9 | import com.intellij.psi.PsiElement;
10 | import com.intellij.psi.PsiFile;
11 | import com.intellij.psi.tree.IFileElementType;
12 | import com.intellij.psi.tree.TokenSet;
13 | import org.antlr.intellij.plugin.adaptors.ANTLRv4GrammarParser;
14 | import org.antlr.intellij.plugin.adaptors.ANTLRv4LexerAdaptor;
15 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
16 | import org.jetbrains.annotations.NotNull;
17 |
18 | /** The general interface between IDEA and ANTLR. */
19 | public class ANTLRv4ParserDefinition implements ParserDefinition {
20 | public static final IFileElementType FILE =
21 | new IFileElementType(ANTLRv4Language.INSTANCE);
22 |
23 | @NotNull
24 | @Override
25 | public Lexer createLexer(Project project) {
26 | ANTLRv4Lexer lexer = new ANTLRv4Lexer(null);
27 | return new ANTLRv4LexerAdaptor(lexer);
28 | }
29 |
30 | @NotNull
31 | public PsiParser createParser(final Project project) {
32 | return new ANTLRv4GrammarParser();
33 | }
34 |
35 | @NotNull
36 | public TokenSet getWhitespaceTokens() {
37 | return ANTLRv4TokenTypes.WHITESPACES;
38 | }
39 |
40 | @NotNull
41 | public TokenSet getCommentTokens() {
42 | return ANTLRv4TokenTypes.COMMENTS;
43 | }
44 |
45 | @NotNull
46 | public TokenSet getStringLiteralElements() {
47 | return TokenSet.EMPTY;
48 | }
49 |
50 | @Override
51 | public IFileElementType getFileNodeType() {
52 | return FILE;
53 | }
54 |
55 | @Override
56 | public PsiFile createFile(FileViewProvider viewProvider) {
57 | return new ANTLRv4FileRoot(viewProvider);
58 | }
59 |
60 | public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) {
61 | return SpaceRequirements.MAY;
62 | }
63 |
64 | /** Convert from internal parse node (AST they call it) to final PSI node. This
65 | * converts only internal rule nodes apparently, not leaf nodes. Leaves
66 | * are just tokens I guess.
67 | */
68 | @NotNull
69 | public PsiElement createElement(ASTNode node) {
70 | return ANTLRv4ASTFactory.createInternalParseTreeNode(node);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/ANTLRv4SyntaxHighlighter.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.lexer.Lexer;
4 | import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
5 | import com.intellij.openapi.editor.HighlighterColors;
6 | import com.intellij.openapi.editor.colors.TextAttributesKey;
7 | import com.intellij.openapi.fileTypes.SyntaxHighlighterBase;
8 | import com.intellij.psi.tree.IElementType;
9 | import org.antlr.intellij.plugin.adaptors.ANTLRv4LexerAdaptor;
10 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | import static com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey;
14 |
15 | public class ANTLRv4SyntaxHighlighter extends SyntaxHighlighterBase {
16 | public static final TextAttributesKey KEYWORD =
17 | createTextAttributesKey("ANTLRv4_KEYWORD", DefaultLanguageHighlighterColors.KEYWORD);
18 | public static final TextAttributesKey RULENAME =
19 | createTextAttributesKey("ANTLRv4_RULENAME", DefaultLanguageHighlighterColors.PARAMETER);
20 | public static final TextAttributesKey TOKENNAME =
21 | createTextAttributesKey("ANTLRv4_TOKENNAME", DefaultLanguageHighlighterColors.INSTANCE_FIELD);
22 | public static final TextAttributesKey STRING =
23 | createTextAttributesKey("ANTLRv4_STRING", DefaultLanguageHighlighterColors.STRING);
24 | public static final TextAttributesKey LINE_COMMENT =
25 | createTextAttributesKey("ANTLRv4_LINE_COMMENT", DefaultLanguageHighlighterColors.LINE_COMMENT);
26 | public static final TextAttributesKey DOC_COMMENT =
27 | createTextAttributesKey("ANTLRv4_DOC_COMMENT", DefaultLanguageHighlighterColors.DOC_COMMENT);
28 | public static final TextAttributesKey BLOCK_COMMENT =
29 | createTextAttributesKey("ANTLRv4_BLOCK_COMMENT", DefaultLanguageHighlighterColors.BLOCK_COMMENT);
30 |
31 | private static final TextAttributesKey[] BAD_CHAR_KEYS = pack(HighlighterColors.BAD_CHARACTER);
32 | private static final TextAttributesKey[] STRING_KEYS = pack(STRING);
33 | private static final TextAttributesKey[] COMMENT_KEYS = new TextAttributesKey[] {LINE_COMMENT, DOC_COMMENT, BLOCK_COMMENT};
34 | private static final TextAttributesKey[] EMPTY_KEYS = new TextAttributesKey[0];
35 |
36 | @NotNull
37 | @Override
38 | public Lexer getHighlightingLexer() {
39 | ANTLRv4Lexer lexer = new ANTLRv4Lexer(null);
40 | return new ANTLRv4LexerAdaptor(lexer);
41 | }
42 |
43 | @NotNull
44 | @Override
45 | public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
46 | if ( ANTLRv4TokenTypes.KEYWORDS.contains(tokenType) ){
47 | return pack(KEYWORD);
48 | }
49 |
50 | if ( tokenType == ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.TOKEN_REF) ) {
51 | return pack(TOKENNAME);
52 | }
53 | else if ( tokenType == ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.RULE_REF) ) {
54 | return pack(RULENAME);
55 | }
56 | else if (tokenType == ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.STRING_LITERAL)
57 | || tokenType == ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.UNTERMINATED_STRING_LITERAL)) {
58 | return STRING_KEYS;
59 | }
60 | else if (tokenType == ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.BLOCK_COMMENT)) {
61 | return COMMENT_KEYS;
62 | }
63 | else if (tokenType == ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.DOC_COMMENT)) {
64 | return COMMENT_KEYS;
65 | }
66 | else if (tokenType == ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.LINE_COMMENT)) {
67 | return COMMENT_KEYS;
68 | }
69 | else if (tokenType == ANTLRv4TokenTypes.BAD_TOKEN_TYPE) {
70 | return BAD_CHAR_KEYS;
71 | }
72 | else {
73 | return EMPTY_KEYS;
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/ANTLRv4SyntaxHighlighterFactory.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
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 |
9 | public class ANTLRv4SyntaxHighlighterFactory extends SyntaxHighlighterFactory {
10 | @NotNull
11 | @Override
12 | public SyntaxHighlighter getSyntaxHighlighter(Project project, VirtualFile virtualFile) {
13 | return new ANTLRv4SyntaxHighlighter();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/ANTLRv4TokenTypes.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.psi.tree.IElementType;
4 | import com.intellij.psi.tree.TokenSet;
5 | import org.antlr.intellij.adaptor.lexer.PSIElementTypeFactory;
6 | import org.antlr.intellij.adaptor.lexer.RuleIElementType;
7 | import org.antlr.intellij.adaptor.lexer.TokenIElementType;
8 | import org.antlr.intellij.plugin.adaptors.ANTLRv4LexerAdaptor;
9 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
10 | import org.antlr.intellij.plugin.parser.ANTLRv4Parser;
11 | import org.intellij.lang.annotations.MagicConstant;
12 |
13 | import java.util.List;
14 |
15 | public class ANTLRv4TokenTypes {
16 | public static IElementType BAD_TOKEN_TYPE = new IElementType("BAD_TOKEN", ANTLRv4Language.INSTANCE);
17 |
18 | static {
19 | ANTLRv4LexerAdaptor.initializeElementTypeFactory();
20 | }
21 |
22 | public static final List TOKEN_ELEMENT_TYPES =
23 | PSIElementTypeFactory.getTokenIElementTypes(ANTLRv4Language.INSTANCE);
24 | public static final List RULE_ELEMENT_TYPES =
25 | PSIElementTypeFactory.getRuleIElementTypes(ANTLRv4Language.INSTANCE);
26 |
27 | public static final TokenSet COMMENTS =
28 | PSIElementTypeFactory.createTokenSet(
29 | ANTLRv4Language.INSTANCE,
30 | ANTLRv4Lexer.DOC_COMMENT,
31 | ANTLRv4Lexer.BLOCK_COMMENT,
32 | ANTLRv4Lexer.LINE_COMMENT);
33 |
34 | public static final TokenSet WHITESPACES =
35 | PSIElementTypeFactory.createTokenSet(
36 | ANTLRv4Language.INSTANCE,
37 | ANTLRv4Lexer.WS);
38 |
39 | public static final TokenSet KEYWORDS =
40 | PSIElementTypeFactory.createTokenSet(
41 | ANTLRv4Language.INSTANCE,
42 | ANTLRv4Lexer.LEXER,ANTLRv4Lexer.PROTECTED,ANTLRv4Lexer.IMPORT,ANTLRv4Lexer.CATCH,
43 | ANTLRv4Lexer.PRIVATE,ANTLRv4Lexer.FRAGMENT,ANTLRv4Lexer.PUBLIC,ANTLRv4Lexer.MODE,
44 | ANTLRv4Lexer.FINALLY,ANTLRv4Lexer.RETURNS,ANTLRv4Lexer.THROWS,ANTLRv4Lexer.GRAMMAR,
45 | ANTLRv4Lexer.LOCALS,ANTLRv4Lexer.PARSER);
46 |
47 | public static RuleIElementType getRuleElementType(@MagicConstant(valuesFromClass = ANTLRv4Parser.class)int ruleIndex){
48 | return RULE_ELEMENT_TYPES.get(ruleIndex);
49 | }
50 | public static TokenIElementType getTokenElementType(@MagicConstant(valuesFromClass = ANTLRv4Lexer.class)int ruleIndex){
51 | return TOKEN_ELEMENT_TYPES.get(ruleIndex);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/Icons.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.openapi.application.ApplicationInfo;
4 | import com.intellij.openapi.util.IconLoader;
5 |
6 | import javax.swing.*;
7 |
8 | public class Icons {
9 | public static final Icon FILE = IconLoader.getIcon("/icons/org/antlr/intellij/plugin/antlr.png");
10 | public static final Icon LEXER_RULE = IconLoader.getIcon("/icons/org/antlr/intellij/plugin/lexer-rule.png");
11 | public static final Icon PARSER_RULE = IconLoader.getIcon("/icons/org/antlr/intellij/plugin/parser-rule.png");
12 | public static final Icon MODE = IconLoader.getIcon("/icons/org/antlr/intellij/plugin/mode.png");
13 |
14 | public static Icon getToolWindow() {
15 | // IntelliJ 2018.2+ has monochrome icons for tool windows so let's use one too
16 | if (ApplicationInfo.getInstance().getBuild().getBaselineVersion() >= 182) {
17 | return IconLoader.getIcon("/icons/org/antlr/intellij/plugin/toolWindowAntlr.svg");
18 | }
19 |
20 | return IconLoader.getIcon("/icons/org/antlr/intellij/plugin/antlr.png");
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/PluginIgnoreMissingTokensFileErrorManager.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import org.antlr.v4.Tool;
4 | import org.antlr.v4.tool.ANTLRMessage;
5 | import org.antlr.v4.tool.ErrorManager;
6 | import org.antlr.v4.tool.ErrorType;
7 |
8 | public class PluginIgnoreMissingTokensFileErrorManager extends ErrorManager {
9 | public PluginIgnoreMissingTokensFileErrorManager(Tool tool) {
10 | super(tool);
11 | }
12 |
13 | @Override
14 | public void emit(ErrorType etype, ANTLRMessage msg) {
15 | if ( etype==ErrorType.CANNOT_FIND_TOKENS_FILE_REFD_IN_GRAMMAR ||
16 | etype==ErrorType.CANNOT_FIND_TOKENS_FILE_GIVEN_ON_CMDLINE )
17 | {
18 | return; // ignore these
19 | }
20 | super.emit(etype, msg);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/Utils.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.util.containers.Predicate;
4 |
5 | import java.util.ArrayList;
6 | import java.util.Collection;
7 | import java.util.List;
8 |
9 | public class Utils {
10 | public static List filter(Collection data, Predicate pred) {
11 | if ( data==null ) return null;
12 | List filtered = new ArrayList<>();
13 | for (T x : data) {
14 | if ( pred.apply(x) ) filtered.add(x);
15 | }
16 | return filtered;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/actions/AnnotationIntentActionsFactory.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.actions;
2 |
3 | import com.intellij.codeInsight.intention.IntentionAction;
4 | import com.intellij.openapi.util.TextRange;
5 | import com.intellij.psi.PsiFile;
6 | import org.antlr.intellij.plugin.validation.AddTokenDefinitionFix;
7 | import org.antlr.intellij.plugin.validation.CreateRuleFix;
8 | import org.antlr.v4.tool.ErrorType;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | import java.util.Optional;
12 |
13 | public class AnnotationIntentActionsFactory {
14 | @NotNull
15 | public static Optional getFix(TextRange textRange, ErrorType errorType, PsiFile file) {
16 | if (errorType == ErrorType.IMPLICIT_TOKEN_DEFINITION) {
17 | return Optional.of(new AddTokenDefinitionFix(textRange));
18 | }
19 | else if ( errorType==ErrorType.UNDEFINED_RULE_REF ) {
20 | return Optional.of(new CreateRuleFix(textRange, file));
21 | }
22 | return Optional.empty();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/actions/ChooseExtractedRuleName.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.actions;
2 |
3 | import com.intellij.openapi.project.Project;
4 | import com.intellij.openapi.ui.DialogWrapper;
5 | import com.intellij.ui.components.JBTextField;
6 | import org.jetbrains.annotations.Nullable;
7 |
8 | import javax.swing.*;
9 | import java.awt.*;
10 |
11 | public class ChooseExtractedRuleName extends DialogWrapper {
12 | JBTextField nameField;
13 | public String ruleName;
14 |
15 | protected ChooseExtractedRuleName(@Nullable Project project) {
16 | super(project, true);
17 | init();
18 | }
19 |
20 | @Override
21 | protected void doOKAction() {
22 | super.doOKAction();
23 | ruleName = nameField.getText();
24 | }
25 |
26 | @Override
27 | protected JComponent createCenterPanel() {
28 | nameField = new JBTextField("newRule");
29 | double h = nameField.getSize().getHeight();
30 | nameField.setPreferredSize(new Dimension(250,(int)h));
31 | setTitle("Name the extracted rule");
32 | nameField.selectAll();
33 | return nameField;
34 | }
35 |
36 | @Nullable
37 | @Override
38 | public JComponent getPreferredFocusedComponent() {
39 | return nameField;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/actions/ConfigureANTLRAction.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.actions;
2 |
3 | import com.intellij.openapi.actionSystem.ActionUpdateThread;
4 | import com.intellij.openapi.actionSystem.AnAction;
5 | import com.intellij.openapi.actionSystem.AnActionEvent;
6 | import com.intellij.openapi.diagnostic.Logger;
7 | import com.intellij.openapi.project.DumbAware;
8 | import com.intellij.openapi.ui.DialogWrapper;
9 | import com.intellij.openapi.vfs.VirtualFile;
10 | import org.antlr.intellij.plugin.configdialogs.ConfigANTLRPerGrammar;
11 | import org.antlr.v4.Tool;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | public class ConfigureANTLRAction extends AnAction implements DumbAware {
15 | public static final Logger LOG = Logger.getInstance("ConfigureANTLRAction");
16 |
17 | @Override
18 | public void update(AnActionEvent e) {
19 | MyActionUtils.selectedFileIsGrammar(e);
20 | }
21 |
22 | @Override
23 | public @NotNull ActionUpdateThread getActionUpdateThread() {
24 | return ActionUpdateThread.BGT;
25 | }
26 |
27 | @Override
28 | public void actionPerformed(AnActionEvent e) {
29 | if ( e.getProject()==null ) {
30 | LOG.error("actionPerformed no project for "+e);
31 | return; // whoa!
32 | }
33 | VirtualFile grammarFile = MyActionUtils.getGrammarFileFromEvent(e);
34 | if ( grammarFile==null ) return;
35 | LOG.info("actionPerformed "+grammarFile);
36 |
37 | ConfigANTLRPerGrammar configDialog = ConfigANTLRPerGrammar.getDialogForm(e.getProject(), grammarFile.getPath());
38 | configDialog.getPeer().setTitle("Configure ANTLR Tool "+ Tool.VERSION+" for "+ grammarFile.getName());
39 |
40 | configDialog.show();
41 |
42 | if ( configDialog.getExitCode()==DialogWrapper.OK_EXIT_CODE ) {
43 | configDialog.saveValues(e.getProject(), grammarFile.getPath());
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/adaptors/ANTLRv4GrammarParser.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.adaptors;
2 |
3 | import com.intellij.psi.tree.IElementType;
4 | import com.intellij.psi.tree.IFileElementType;
5 | import org.antlr.intellij.adaptor.parser.ANTLRParserAdaptor;
6 | import org.antlr.intellij.plugin.ANTLRv4Language;
7 | import org.antlr.intellij.plugin.ANTLRv4TokenTypes;
8 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
9 | import org.antlr.intellij.plugin.parser.ANTLRv4Parser;
10 | import org.antlr.v4.runtime.Parser;
11 | import org.antlr.v4.runtime.Token;
12 | import org.antlr.v4.runtime.tree.ParseTree;
13 |
14 | /** A specific kind of parser that knows how to parse ANTLR v4 grammar meta-language */
15 | public class ANTLRv4GrammarParser extends ANTLRParserAdaptor {
16 | public ANTLRv4GrammarParser() {
17 | super(ANTLRv4Language.INSTANCE, new ANTLRv4Parser(null));
18 | }
19 |
20 | @Override
21 | protected ParseTree parse(Parser parser, IElementType root) {
22 | int startRule;
23 | if (root instanceof IFileElementType) {
24 | startRule = ANTLRv4Parser.RULE_grammarSpec;
25 | }
26 | else if (root == ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.TOKEN_REF)
27 | || root == ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.RULE_REF)) {
28 | startRule = ANTLRv4Parser.RULE_atom;
29 | }
30 | else {
31 | startRule = Token.INVALID_TYPE;
32 | }
33 |
34 | switch (startRule) {
35 | case ANTLRv4Parser.RULE_grammarSpec:
36 | return ((ANTLRv4Parser) parser).grammarSpec();
37 |
38 | case ANTLRv4Parser.RULE_atom:
39 | return ((ANTLRv4Parser) parser).atom();
40 |
41 | default:
42 | throw new UnsupportedOperationException(String.format("cannot start parsing using root element %s", root));
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/adaptors/ANTLRv4LexerAdaptor.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.adaptors;
2 |
3 | import org.antlr.intellij.adaptor.lexer.ANTLRLexerAdaptor;
4 | import org.antlr.intellij.adaptor.lexer.PSIElementTypeFactory;
5 | import org.antlr.intellij.plugin.ANTLRv4Language;
6 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
7 | import org.antlr.intellij.plugin.parser.ANTLRv4Parser;
8 | import org.antlr.v4.runtime.Lexer;
9 |
10 | /** Adapt ANTLR needs to intellij */
11 | public class ANTLRv4LexerAdaptor extends ANTLRLexerAdaptor {
12 |
13 | // In case a lexer was created outside our ParserDefinition
14 | static {
15 | initializeElementTypeFactory();
16 | }
17 |
18 | public static void initializeElementTypeFactory() {
19 | PSIElementTypeFactory.defineLanguageIElementTypes(
20 | ANTLRv4Language.INSTANCE,
21 | ANTLRv4Lexer.tokenNames,
22 | ANTLRv4Parser.ruleNames
23 | );
24 | }
25 |
26 | private static final ANTLRv4LexerState INITIAL_STATE = new ANTLRv4LexerState(Lexer.DEFAULT_MODE, null, 0);
27 |
28 | public ANTLRv4LexerAdaptor(ANTLRv4Lexer lexer) {
29 | super(ANTLRv4Language.INSTANCE, lexer);
30 | }
31 |
32 | @Override
33 | protected ANTLRv4LexerState getInitialState() {
34 | return INITIAL_STATE;
35 | }
36 |
37 | @Override
38 | protected ANTLRv4LexerState getLexerState(Lexer lexer) {
39 | if (lexer._modeStack.isEmpty()) {
40 | return new ANTLRv4LexerState(lexer._mode, null, ((ANTLRv4Lexer)lexer).getCurrentRuleType());
41 | }
42 |
43 | return new ANTLRv4LexerState(lexer._mode, lexer._modeStack, ((ANTLRv4Lexer)lexer).getCurrentRuleType());
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/adaptors/ANTLRv4LexerState.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.adaptors;
2 |
3 | import org.antlr.intellij.adaptor.lexer.ANTLRLexerState;
4 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
5 | import org.antlr.v4.runtime.Lexer;
6 | import org.antlr.v4.runtime.misc.IntegerStack;
7 | import org.antlr.v4.runtime.misc.MurmurHash;
8 |
9 | public class ANTLRv4LexerState extends ANTLRLexerState {
10 | /** Tracks whether we are in a lexer rule, a parser rule or neither;
11 | * managed by the ANTLRv4Lexer grammar.
12 | */
13 | private final int currentRuleType;
14 |
15 | public ANTLRv4LexerState(int mode, IntegerStack modeStack, int currentRuleType) {
16 | super(mode, modeStack);
17 | this.currentRuleType = currentRuleType;
18 | }
19 |
20 | public int getCurrentRuleType() {
21 | return currentRuleType;
22 | }
23 |
24 | @Override
25 | public void apply(Lexer lexer) {
26 | super.apply(lexer);
27 | if (lexer instanceof ANTLRv4Lexer) {
28 | ((ANTLRv4Lexer)lexer).setCurrentRuleType(getCurrentRuleType());
29 | }
30 | }
31 |
32 | @Override
33 | protected int hashCodeImpl() {
34 | int hash = MurmurHash.initialize();
35 | hash = MurmurHash.update(hash, getMode());
36 | hash = MurmurHash.update(hash, getModeStack());
37 | hash = MurmurHash.update(hash, getCurrentRuleType());
38 | return MurmurHash.finish(hash, 3);
39 | }
40 |
41 | @Override
42 | public boolean equals(Object obj) {
43 | if (obj == this) {
44 | return true;
45 | }
46 |
47 | if (!(obj instanceof ANTLRv4LexerState)) {
48 | return false;
49 | }
50 |
51 | if (!super.equals(obj)) {
52 | return false;
53 | }
54 |
55 | ANTLRv4LexerState other = (ANTLRv4LexerState)obj;
56 | return this.getCurrentRuleType() == other.getCurrentRuleType();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/configdialogs/ANTLRv4ColorsPage.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.configdialogs;
2 |
3 | import com.intellij.openapi.editor.colors.TextAttributesKey;
4 | import com.intellij.openapi.fileTypes.SyntaxHighlighter;
5 | import com.intellij.openapi.options.colors.AttributesDescriptor;
6 | import com.intellij.openapi.options.colors.ColorDescriptor;
7 | import com.intellij.openapi.options.colors.ColorSettingsPage;
8 | import org.antlr.intellij.plugin.ANTLRv4SyntaxHighlighter;
9 | import org.antlr.intellij.plugin.Icons;
10 | import org.jetbrains.annotations.NotNull;
11 | import org.jetbrains.annotations.Nullable;
12 |
13 | import javax.swing.*;
14 | import java.util.Map;
15 |
16 | public class ANTLRv4ColorsPage implements ColorSettingsPage {
17 | private static final AttributesDescriptor[] ATTRIBUTES =
18 | {
19 | new AttributesDescriptor("Lexer Rule", ANTLRv4SyntaxHighlighter.TOKENNAME),
20 | new AttributesDescriptor("Parser Rule", ANTLRv4SyntaxHighlighter.RULENAME),
21 | };
22 |
23 | @Nullable
24 | @Override
25 | public Icon getIcon() {
26 | return Icons.FILE;
27 | }
28 |
29 | @NotNull
30 | @Override
31 | public SyntaxHighlighter getHighlighter() {
32 | return new ANTLRv4SyntaxHighlighter();
33 | }
34 |
35 | @NotNull
36 | @Override
37 | public String getDemoText() {
38 | return
39 | "grammar Foo;\n" +
40 | "\n" +
41 | "compilationUnit : STUFF EOF;\n" +
42 | "\n" +
43 | "STUFF : 'stuff' -> pushMode(OTHER_MODE);\n" +
44 | "WS : [ \\t]+ -> channel(HIDDEN);\n" +
45 | "NEWLINE : [\\r\\n]+ -> type(WS);\n" +
46 | "BAD_CHAR : . -> skip;\n" +
47 | "\n" +
48 | "mode OTHER_MODE;\n" +
49 | "\n" +
50 | "KEYWORD : 'keyword' -> popMode;\n";
51 | }
52 |
53 | @Nullable
54 | @Override
55 | public Map getAdditionalHighlightingTagToDescriptorMap() {
56 | return null;
57 | }
58 |
59 | @NotNull
60 | @Override
61 | public AttributesDescriptor[] getAttributeDescriptors() {
62 | return ATTRIBUTES;
63 | }
64 |
65 | @NotNull
66 | @Override
67 | public ColorDescriptor[] getColorDescriptors() {
68 | return ColorDescriptor.EMPTY_ARRAY;
69 | }
70 |
71 | @NotNull
72 | @Override
73 | public String getDisplayName() {
74 | return "ANTLR";
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/configdialogs/ANTLRv4GrammarPropertiesComponent.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.configdialogs;
2 |
3 | import com.intellij.openapi.components.PersistentStateComponent;
4 | import com.intellij.openapi.components.ServiceManager;
5 | import com.intellij.openapi.components.State;
6 | import com.intellij.openapi.project.Project;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | /**
10 | * Stores code generation preferences in .idea/misc.xml
.
11 | */
12 | @State(name = "ANTLRGenerationPreferences")
13 | public class ANTLRv4GrammarPropertiesComponent implements PersistentStateComponent {
14 |
15 | private ANTLRv4GrammarPropertiesStore mySettings = new ANTLRv4GrammarPropertiesStore();
16 |
17 | public static ANTLRv4GrammarPropertiesComponent getInstance(Project project) {
18 | return ServiceManager.getService(project, ANTLRv4GrammarPropertiesComponent.class);
19 | }
20 |
21 | @NotNull
22 | @Override
23 | public ANTLRv4GrammarPropertiesStore getState() {
24 | return mySettings;
25 | }
26 |
27 | @Override
28 | public void loadState(ANTLRv4GrammarPropertiesStore state) {
29 | mySettings = state;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/configdialogs/ANTLRv4ProjectSettings.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.configdialogs;
2 |
3 | import com.intellij.openapi.Disposable;
4 | import com.intellij.openapi.options.SearchableConfigurable;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.util.Disposer;
7 | import org.jetbrains.annotations.Nls;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.jetbrains.annotations.Nullable;
10 |
11 | import javax.swing.*;
12 |
13 | import static org.antlr.intellij.plugin.configdialogs.ANTLRv4GrammarPropertiesStore.getGrammarProperties;
14 |
15 | /**
16 | * The UI that allows viewing/modifying default grammar settings for an entire project.
17 | *
18 | * @see ConfigANTLRPerGrammar
19 | */
20 | public class ANTLRv4ProjectSettings implements SearchableConfigurable, Disposable {
21 |
22 | private ConfigANTLRPerGrammar configurationForm;
23 |
24 | private final Project project;
25 |
26 | public ANTLRv4ProjectSettings(@NotNull Project project) {
27 | this.project = project;
28 | }
29 |
30 | @NotNull
31 | @Override
32 | public String getId() {
33 | return "ANTLR4ProjectSettings";
34 | }
35 |
36 | @Nullable
37 | @Override
38 | public Runnable enableSearch(String option) {
39 | return null;
40 | }
41 |
42 | @Nls(capitalization = Nls.Capitalization.Title)
43 | @Override
44 | public String getDisplayName() {
45 | return "ANTLR4 Project Settings";
46 | }
47 |
48 | @Nullable
49 | public String getHelpTopic() {
50 | return "ANTLR4 Project Settings";
51 | }
52 |
53 | @Nullable
54 | @Override
55 | public JComponent createComponent() {
56 | configurationForm = ConfigANTLRPerGrammar.getProjectSettingsForm(project, ANTLRv4GrammarProperties.PROJECT_SETTINGS_PREFIX);
57 | return configurationForm.createCenterPanel();
58 | }
59 |
60 | @Override
61 | public boolean isModified() {
62 | ANTLRv4GrammarProperties grammarProperties = getGrammarProperties(project, ANTLRv4GrammarProperties.PROJECT_SETTINGS_PREFIX);
63 | return configurationForm.isModified(grammarProperties);
64 | }
65 |
66 | @Override
67 | public void apply() {
68 | configurationForm.saveValues(project, ANTLRv4GrammarProperties.PROJECT_SETTINGS_PREFIX);
69 | }
70 |
71 | public void reset() {
72 | configurationForm.loadValues(project, ANTLRv4GrammarProperties.PROJECT_SETTINGS_PREFIX);
73 | }
74 |
75 | @Override
76 | public void disposeUIResources() {
77 | Disposer.dispose(configurationForm.getDisposable());
78 | }
79 |
80 | @Override
81 | public void dispose() {
82 | configurationForm = null;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/configdialogs/CaseChangingStrategyConverter.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.configdialogs;
2 |
3 | import com.intellij.util.xmlb.Converter;
4 | import org.antlr.intellij.plugin.parsing.CaseChangingStrategy;
5 | import org.jetbrains.annotations.NotNull;
6 | import org.jetbrains.annotations.Nullable;
7 |
8 | /**
9 | * A converter used to serialize/deserialize a {@code CaseChangingStrategy} to/from
10 | * a String contained in {@code .idea/misc.xml} using the enum's {@code name()}.
11 | */
12 | public class CaseChangingStrategyConverter extends Converter {
13 | @Nullable
14 | @Override
15 | public CaseChangingStrategy fromString(@NotNull String value) {
16 | try {
17 | return CaseChangingStrategy.valueOf(value);
18 | } catch ( IllegalArgumentException e ) {
19 | return null;
20 | }
21 | }
22 |
23 | @Nullable
24 | @Override
25 | public String toString(@NotNull CaseChangingStrategy value) {
26 | return value.name();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/editor/ANTLRv4BraceMatcher.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.editor;
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.jetbrains.annotations.NotNull;
8 | import org.jetbrains.annotations.Nullable;
9 |
10 | import static org.antlr.intellij.plugin.ANTLRv4TokenTypes.getTokenElementType;
11 | import static org.antlr.intellij.plugin.parser.ANTLRv4Lexer.*;
12 |
13 | public class ANTLRv4BraceMatcher implements PairedBraceMatcher {
14 |
15 | @NotNull
16 | @Override
17 | public BracePair[] getPairs() {
18 | return new BracePair[] {
19 | new BracePair(getTokenElementType(LPAREN), getTokenElementType(RPAREN), false),
20 | new BracePair(getTokenElementType(OPTIONS), getTokenElementType(RBRACE), true),
21 | new BracePair(getTokenElementType(TOKENS), getTokenElementType(RBRACE), true),
22 | new BracePair(getTokenElementType(CHANNELS), getTokenElementType(RBRACE), true),
23 | new BracePair(getTokenElementType(BEGIN_ACTION), getTokenElementType(END_ACTION), false),
24 | new BracePair(getTokenElementType(BEGIN_ARGUMENT), getTokenElementType(END_ARGUMENT), false),
25 | new BracePair(getTokenElementType(LT), getTokenElementType(GT), false),
26 | };
27 | }
28 |
29 | @Override
30 | public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType lbraceType, @Nullable IElementType contextType) {
31 | return true;
32 | }
33 |
34 | @Override
35 | public int getCodeConstructStart(PsiFile file, int openingBraceOffset) {
36 | return openingBraceOffset;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/folding/ANTLRv4FoldingSettings.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.folding;
2 |
3 | /**
4 | * Created by jason on 2/2/15.
5 | */
6 | public abstract class ANTLRv4FoldingSettings {
7 | //TODO ServiceManager,UI,serialization,etc
8 | private static final ANTLRv4FoldingSettings INSTANCE= new ANTLRv4FoldingSettings() {
9 | @Override
10 | public boolean isCollapseFileHeader() {
11 | return true;
12 | }
13 |
14 | @Override
15 | public boolean isCollapseDocComments() {
16 | return false;
17 | }
18 |
19 | @Override
20 | public boolean isCollapseComments() {
21 | return false;
22 | }
23 |
24 | @Override
25 | public boolean isCollapseRuleBlocks() {
26 | return false;
27 | }
28 |
29 | @Override
30 | public boolean isCollapseActions() {
31 | return true;
32 | }
33 |
34 | @Override
35 | public boolean isCollapseTokens() {
36 | return true;
37 | }
38 | };
39 |
40 | public static ANTLRv4FoldingSettings getInstance() {
41 | return INSTANCE;
42 | }
43 |
44 | public abstract boolean isCollapseFileHeader();
45 |
46 | public abstract boolean isCollapseDocComments();
47 |
48 | public abstract boolean isCollapseComments();
49 |
50 | public abstract boolean isCollapseRuleBlocks();
51 |
52 | public abstract boolean isCollapseActions();
53 |
54 | public abstract boolean isCollapseTokens();
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/generators/LiteralChooserObject.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.generators;
2 |
3 | import com.intellij.ui.SimpleColoredComponent;
4 | import com.intellij.ui.SimpleTextAttributes;
5 | import org.jetbrains.annotations.Nullable;
6 |
7 | import javax.swing.*;
8 |
9 | public class LiteralChooserObject {
10 | private final String text;
11 | private final Icon icon;
12 |
13 | public LiteralChooserObject(final String text, @Nullable final Icon icon) {
14 | this.text = text;
15 | this.icon = icon;
16 | }
17 |
18 | public void renderTreeNode(SimpleColoredComponent component, JTree tree) {
19 | String literal = getText();
20 | SimpleTextAttributes attributes =
21 | new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, tree.getForeground());
22 | component.append(literal, attributes);
23 | component.setIcon(icon);
24 | }
25 |
26 | public String getText() {
27 | return text;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/generators/LiteralChooserRenderer.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.generators;
2 |
3 | import com.intellij.ui.CheckboxTreeBase;
4 |
5 | import javax.swing.*;
6 | import javax.swing.tree.DefaultMutableTreeNode;
7 |
8 | public class LiteralChooserRenderer extends CheckboxTreeBase.CheckboxTreeCellRendererBase {
9 | @Override
10 | public void customizeRenderer(JTree tree,
11 | Object value,
12 | boolean selected,
13 | boolean expanded,
14 | boolean leaf,
15 | int row,
16 | boolean hasFocus)
17 | {
18 | if (value instanceof DefaultMutableTreeNode) {
19 | Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
20 | if (userObject instanceof LiteralChooserObject) {
21 | LiteralChooserObject literalChooserObject = (LiteralChooserObject)userObject;
22 | literalChooserObject.renderTreeNode(getTextRenderer(), tree);
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/parsing/CaseChangingCharStream.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.parsing;
2 |
3 | import org.antlr.v4.runtime.CharStream;
4 | import org.antlr.v4.runtime.misc.Interval;
5 |
6 | /**
7 | * This class supports case-insensitive lexing by wrapping an existing
8 | * {@link CharStream} and forcing the lexer to see either upper or
9 | * lowercase characters. Grammar literals should then be either upper or
10 | * lower case such as 'BEGIN' or 'begin'. The text of the character
11 | * stream is unaffected. Example: input 'BeGiN' would match lexer rule
12 | * 'BEGIN' if constructor parameter upper=true but getText() would return
13 | * 'BeGiN'.
14 | */
15 | public class CaseChangingCharStream implements CharStream {
16 |
17 | final CharStream stream;
18 | final boolean upper;
19 |
20 | /**
21 | * Constructs a new CaseChangingCharStream wrapping the given {@link CharStream} forcing
22 | * all characters to upper case or lower case.
23 | * @param stream The stream to wrap.
24 | * @param upper If true force each symbol to upper case, otherwise force to lower.
25 | */
26 | public CaseChangingCharStream(CharStream stream, boolean upper) {
27 | this.stream = stream;
28 | this.upper = upper;
29 | }
30 |
31 | @Override
32 | public String getText(Interval interval) {
33 | return stream.getText(interval);
34 | }
35 |
36 | @Override
37 | public void consume() {
38 | stream.consume();
39 | }
40 |
41 | @Override
42 | public int LA(int i) {
43 | int c = stream.LA(i);
44 | if (c <= 0) {
45 | return c;
46 | }
47 | if (upper) {
48 | return Character.toUpperCase(c);
49 | }
50 | return Character.toLowerCase(c);
51 | }
52 |
53 | @Override
54 | public int mark() {
55 | return stream.mark();
56 | }
57 |
58 | @Override
59 | public void release(int marker) {
60 | stream.release(marker);
61 | }
62 |
63 | @Override
64 | public int index() {
65 | return stream.index();
66 | }
67 |
68 | @Override
69 | public void seek(int index) {
70 | stream.seek(index);
71 | }
72 |
73 | @Override
74 | public int size() {
75 | return stream.size();
76 | }
77 |
78 | @Override
79 | public String getSourceName() {
80 | return stream.getSourceName();
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/parsing/CaseChangingStrategy.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.parsing;
2 |
3 | import org.antlr.v4.runtime.CharStream;
4 |
5 | /**
6 | * All the case transformations that can be applied in the ANTLR Preview
7 | * window when lexing the input.
8 | *
9 | * @see CaseChangingCharStream
10 | */
11 | public enum CaseChangingStrategy {
12 | LEAVE_AS_IS {
13 | @Override
14 | public CharStream applyTo(CharStream source) {
15 | return source;
16 | }
17 |
18 | @Override
19 | public String toString() {
20 | return "Leave as-is";
21 | }
22 | },
23 | FORCE_UPPERCASE {
24 | @Override
25 | public CharStream applyTo(CharStream source) {
26 | return new CaseChangingCharStream(source, true);
27 | }
28 |
29 | @Override
30 | public String toString() {
31 | return "Transform to uppercase when lexing";
32 | }
33 | },
34 | FORCE_LOWERCASE {
35 | @Override
36 | public CharStream applyTo(CharStream source) {
37 | return new CaseChangingCharStream(source, false);
38 | }
39 |
40 | @Override
41 | public String toString() {
42 | return "Transform to lowercase when lexing";
43 | }
44 | };
45 |
46 | public abstract CharStream applyTo(CharStream source);
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/parsing/LexerWatchdog.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.parsing;
2 |
3 | import org.antlr.v4.runtime.RecognitionException;
4 | import org.antlr.v4.runtime.Token;
5 | import org.antlr.v4.runtime.TokenStream;
6 |
7 | /**
8 | * Checks that a lexer is not stuck trying to match the same thing over and over, for example if the input grammar
9 | * can match an empty string. This prevents the IDE from crashing from things like {@link OutOfMemoryError}s.
10 | */
11 | public class LexerWatchdog {
12 |
13 | /**
14 | * The number of iterations on the same index after which we kill the interpreter.
15 | */
16 | private static final int THRESHOLD = 50;
17 |
18 | private final TokenStream tokenStream;
19 | private final PreviewParser previewParser;
20 |
21 | private int currentIndex = -1;
22 | private int iterationsOnCurrentIndex = 0;
23 |
24 | public LexerWatchdog(TokenStream tokenStream, PreviewParser previewParser) {
25 | this.tokenStream = tokenStream;
26 | this.previewParser = previewParser;
27 | }
28 |
29 | public void checkLexerIsNotStuck() {
30 | if ( currentIndex==tokenStream.index() ) {
31 | iterationsOnCurrentIndex++;
32 | }
33 | else {
34 | currentIndex = tokenStream.index();
35 | iterationsOnCurrentIndex = 1;
36 | }
37 |
38 | if ( iterationsOnCurrentIndex>THRESHOLD ) {
39 | final Token token = tokenStream.get(currentIndex);
40 | final String displayName = token.getType() == Token.EOF
41 | ? token.getText()
42 | : previewParser.getVocabulary().getDisplayName(token.getType());
43 |
44 | throw new RecognitionException(
45 | "interpreter was killed after " + THRESHOLD + " iterations on token '" + displayName + "'",
46 | previewParser,
47 | tokenStream,
48 | previewParser.getContext()
49 | ) {
50 | @Override
51 | public Token getOffendingToken() {
52 | return token;
53 | }
54 | };
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/parsing/LoadGrammarsToolListener.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.parsing;
2 |
3 | import org.antlr.v4.Tool;
4 | import org.antlr.v4.tool.ANTLRMessage;
5 | import org.antlr.v4.tool.DefaultToolListener;
6 | import org.stringtemplate.v4.ST;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /** Track errors, warnings from loading grammars. Really just
12 | * swallows them for now. The external annotator shows errors.
13 | */
14 | public class LoadGrammarsToolListener extends DefaultToolListener {
15 | public List grammarErrorMessages = new ArrayList<>();
16 | public List grammarWarningMessages = new ArrayList<>();
17 | public LoadGrammarsToolListener(Tool tool) { super(tool); }
18 |
19 | @Override
20 | public void error(ANTLRMessage msg) {
21 | ST msgST = tool.errMgr.getMessageTemplate(msg);
22 | String s = msgST.render();
23 | if (tool.errMgr.formatWantsSingleLineMessage()) {
24 | s = s.replace('\n', ' ');
25 | }
26 | grammarErrorMessages.add(s);
27 | }
28 |
29 | @Override
30 | public void warning(ANTLRMessage msg) {
31 | ST msgST = tool.errMgr.getMessageTemplate(msg);
32 | String s = msgST.render();
33 | if (tool.errMgr.formatWantsSingleLineMessage()) {
34 | s = s.replace('\n', ' ');
35 | }
36 | grammarWarningMessages.add(s);
37 | }
38 |
39 | public void clear() {
40 | grammarErrorMessages.clear();
41 | grammarWarningMessages.clear();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/parsing/ParsingResult.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.parsing;
2 |
3 | import org.antlr.intellij.adaptor.parser.SyntaxErrorListener;
4 | import org.antlr.v4.runtime.Parser;
5 | import org.antlr.v4.runtime.tree.ParseTree;
6 |
7 | public class ParsingResult {
8 | public Parser parser;
9 | public ParseTree tree;
10 | public SyntaxErrorListener syntaxErrorListener;
11 |
12 | public ParsingResult(Parser parser, ParseTree tree, SyntaxErrorListener syntaxErrorListener) {
13 | this.parser = parser;
14 | this.tree = tree;
15 | this.syntaxErrorListener = syntaxErrorListener;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/parsing/PreviewInterpreterRuleContext.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.parsing;
2 |
3 | import org.antlr.v4.runtime.InterpreterRuleContext;
4 | import org.antlr.v4.runtime.ParserRuleContext;
5 | import org.antlr.v4.tool.GrammarInterpreterRuleContext;
6 |
7 | /**
8 | * This class extends {@link InterpreterRuleContext} to track
9 | * which outermost alternative was used to recognize
10 | * the subphrase matched by the entire rule.
11 | */
12 | public class PreviewInterpreterRuleContext extends GrammarInterpreterRuleContext {
13 | /** Used to mark root of subtree that hits the decision override, if any */
14 | protected boolean isDecisionOverrideRoot;
15 |
16 | /** A mark bit used during tree diff walk. If marked, then we reached
17 | * this node.
18 | */
19 | public boolean reached;
20 |
21 | /**
22 | * Constructs a new {@link InterpreterRuleContext} with the specified
23 | * parent, invoking state, and rule index.
24 | *
25 | * @param parent The parent context.
26 | * @param invokingStateNumber The invoking state number.
27 | * @param ruleIndex The rule index for the current context.
28 | */
29 | public PreviewInterpreterRuleContext(ParserRuleContext parent,
30 | int invokingStateNumber,
31 | int ruleIndex)
32 | {
33 | super(parent, invokingStateNumber, ruleIndex);
34 | }
35 |
36 | /** The predicted outermost alternative for the rule associated
37 | * with this context object. If left recursive, the true original
38 | * outermost alternative is returned.
39 | */
40 | public int getOuterAltNum() { return outerAltNum; }
41 |
42 | public boolean isDecisionOverrideRoot() {
43 | return isDecisionOverrideRoot;
44 | }
45 |
46 | @Override
47 | public boolean equals(Object obj) {
48 | if ( !(obj instanceof PreviewInterpreterRuleContext) ) return false;
49 | PreviewInterpreterRuleContext other = (PreviewInterpreterRuleContext) obj;
50 | return this==other ||
51 | (ruleIndex == other.ruleIndex && outerAltNum == other.outerAltNum);
52 | }
53 |
54 | @Override
55 | public int hashCode() {
56 | return ruleIndex << 7 + outerAltNum;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/parsing/PreviewParser.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.parsing;
2 |
3 | import com.intellij.openapi.progress.ProgressManager;
4 | import org.antlr.v4.runtime.*;
5 | import org.antlr.v4.runtime.atn.*;
6 | import org.antlr.v4.tool.Grammar;
7 | import org.antlr.v4.tool.GrammarParserInterpreter;
8 |
9 | import java.util.HashMap;
10 | import java.util.Map;
11 |
12 | public class PreviewParser extends GrammarParserInterpreter {
13 | /** Map each preview editor token to the grammar ATN state used to match it.
14 | * Saves us having to create special token subclass and token factory.
15 | */
16 | public Map inputTokenToStateMap = new HashMap<>();
17 |
18 | private final LexerWatchdog lexerWatchdog;
19 |
20 | protected int lastSuccessfulMatchState = ATNState.INVALID_STATE_NUMBER; // not sure about error nodes
21 |
22 | public PreviewParser(Grammar g, ATN atn, TokenStream input) {
23 | super(g, atn, input);
24 | lexerWatchdog = new LexerWatchdog(input, this);
25 | }
26 |
27 | public PreviewParser(Grammar g, TokenStream input) {
28 | this(g, new ATNDeserializer().deserialize(ATNSerializer.getSerialized(g.getATN()).toArray()), input);
29 | }
30 |
31 | @Override
32 | public void reset() {
33 | super.reset();
34 | if ( inputTokenToStateMap!=null ) inputTokenToStateMap.clear();
35 | lastSuccessfulMatchState = ATNState.INVALID_STATE_NUMBER;
36 | }
37 |
38 | @Override
39 | protected InterpreterRuleContext createInterpreterRuleContext(ParserRuleContext parent, int invokingStateNumber, int ruleIndex) {
40 | return new PreviewInterpreterRuleContext(parent, invokingStateNumber, ruleIndex);
41 | }
42 |
43 | @Override
44 | protected int visitDecisionState(DecisionState p) {
45 | ProgressManager.checkCanceled();
46 |
47 | int predictedAlt = super.visitDecisionState(p);
48 | if ( p.getNumberOfTransitions()>1 ) {
49 | if ( p.decision==this.overrideDecision &&
50 | this._input.index()==this.overrideDecisionInputIndex ) {
51 | ((PreviewInterpreterRuleContext)overrideDecisionRoot).isDecisionOverrideRoot = true;
52 | }
53 | }
54 | return predictedAlt;
55 | }
56 |
57 |
58 | @Override
59 | public Token match(int ttype) throws RecognitionException {
60 | lexerWatchdog.checkLexerIsNotStuck();
61 |
62 | Token t = super.match(ttype);
63 | // track which ATN state matches each token
64 | inputTokenToStateMap.put(t, getState());
65 | lastSuccessfulMatchState = getState();
66 | return t;
67 | }
68 |
69 |
70 | @Override
71 | public Token matchWildcard() throws RecognitionException {
72 | lexerWatchdog.checkLexerIsNotStuck();
73 |
74 | inputTokenToStateMap.put(_input.LT(1), getState());
75 | lastSuccessfulMatchState = getState();
76 | return super.matchWildcard();
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/parsing/RunANTLRListener.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.parsing;
2 |
3 | import com.intellij.execution.ui.ConsoleView;
4 | import com.intellij.execution.ui.ConsoleViewContentType;
5 | import org.antlr.v4.Tool;
6 | import org.antlr.v4.tool.ANTLRMessage;
7 | import org.antlr.v4.tool.ANTLRToolListener;
8 | import org.stringtemplate.v4.ST;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | /** Used to track errors during antlr run on a grammar for generation,
14 | * not for annotation of grammar.
15 | */
16 | public class RunANTLRListener implements ANTLRToolListener {
17 | public final List all = new ArrayList<>();
18 | public Tool tool;
19 | public ConsoleView console;
20 | public boolean hasOutput = false;
21 |
22 | public RunANTLRListener(Tool tool, ConsoleView console) {
23 | this.tool = tool;
24 | this.console = console;
25 | }
26 |
27 | @Override
28 | public void info(String msg) {
29 | if (tool.errMgr.formatWantsSingleLineMessage()) {
30 | msg = msg.replace('\n', ' ');
31 | }
32 | console.print(msg+"\n", ConsoleViewContentType.NORMAL_OUTPUT);
33 | hasOutput = true;
34 | }
35 |
36 | @Override
37 | public void error(ANTLRMessage msg) {
38 | track(msg, ConsoleViewContentType.ERROR_OUTPUT);
39 | }
40 |
41 | @Override
42 | public void warning(ANTLRMessage msg) {
43 | track(msg, ConsoleViewContentType.NORMAL_OUTPUT);
44 | }
45 |
46 | private void track(ANTLRMessage msg, ConsoleViewContentType errType) {
47 | ST msgST = tool.errMgr.getMessageTemplate(msg);
48 | String outputMsg = msgST.render();
49 | if (tool.errMgr.formatWantsSingleLineMessage()) {
50 | outputMsg = outputMsg.replace('\n', ' ');
51 | }
52 | console.print(outputMsg+"\n", errType);
53 | hasOutput = true;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/parsing/TokenStreamSubset.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.parsing;
2 |
3 | import org.antlr.v4.runtime.CommonToken;
4 | import org.antlr.v4.runtime.CommonTokenStream;
5 | import org.antlr.v4.runtime.Token;
6 | import org.antlr.v4.runtime.TokenSource;
7 |
8 | /** This TokenStream is just a {@link CommonTokenStream} that can be
9 | * cut off at a particular index, such as the cursor in an IDE. I
10 | * had to override more than I wanted to get this to work, but it seems okay.
11 | *
12 | * All parsers used within the plug-in should use token streams of this type.
13 | */
14 | public class TokenStreamSubset extends CommonTokenStream {
15 | public static final int STOP_TOKEN_TYPE = -3;
16 | // protected int indexOfLastToken = -1;
17 | protected Token saveToken;
18 |
19 | public TokenStreamSubset(TokenSource tokenSource) {
20 | super(tokenSource);
21 | }
22 |
23 | public void setIndexOfLastToken(int indexOfLastToken) {
24 | // System.out.println("setIndexOfLastToken("+indexOfLastToken+")");
25 | if ( indexOfLastToken<0 ) {
26 | // System.out.println("replacing "+saveToken.getTokenIndex()+" with "+saveToken);
27 | tokens.set(saveToken.getTokenIndex(), saveToken);
28 | // this.indexOfLastToken = indexOfLastToken;
29 | return;
30 | }
31 | int i = indexOfLastToken + 1; // we want to keep token at indexOfLastToken
32 | sync(i);
33 | saveToken = tokens.get(i);
34 | // System.out.println("saving "+saveToken);
35 | CommonToken stopToken = new CommonToken(saveToken);
36 | stopToken.setType(STOP_TOKEN_TYPE);
37 | // System.out.println("setting "+i+" to "+stopToken);
38 | tokens.set(i, stopToken);
39 | // this.indexOfLastToken = indexOfLastToken;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/preview/AltLabelTextProvider.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.preview;
2 |
3 | import org.antlr.intellij.plugin.parsing.PreviewInterpreterRuleContext;
4 | import org.antlr.v4.gui.TreeTextProvider;
5 | import org.antlr.v4.runtime.Parser;
6 | import org.antlr.v4.runtime.Token;
7 | import org.antlr.v4.runtime.misc.Pair;
8 | import org.antlr.v4.runtime.tree.TerminalNode;
9 | import org.antlr.v4.runtime.tree.Tree;
10 | import org.antlr.v4.runtime.tree.Trees;
11 | import org.antlr.v4.tool.Grammar;
12 | import org.antlr.v4.tool.Rule;
13 | import org.antlr.v4.tool.ast.AltAST;
14 |
15 | import java.util.Arrays;
16 | import java.util.List;
17 | import java.util.Map;
18 |
19 | public class AltLabelTextProvider implements TreeTextProvider {
20 | protected final Parser parser;
21 | protected final Grammar g;
22 |
23 | public AltLabelTextProvider(Parser parser, Grammar g) {
24 | this.parser = parser;
25 | this.g = g;
26 | }
27 |
28 | public String[] getAltLabels(Rule r) {
29 | String[] altLabels = null;
30 | Map>> altLabelsMap = r.getAltLabels();
31 | if ( altLabelsMap!=null ) {
32 | altLabels = new String[r.getOriginalNumberOfAlts() + 1];
33 | for (String altLabel : altLabelsMap.keySet()) {
34 | List> pairs = altLabelsMap.get(altLabel);
35 | for (Pair pair : pairs) {
36 | altLabels[pair.a] = altLabel;
37 | }
38 | }
39 | }
40 | return altLabels;
41 | }
42 |
43 | @Override
44 | public String getText(Tree node) {
45 | if ( node instanceof PreviewInterpreterRuleContext) {
46 | PreviewInterpreterRuleContext inode = (PreviewInterpreterRuleContext)node;
47 | Rule r = g.getRule(inode.getRuleIndex());
48 | String[] altLabels = getAltLabels(r);
49 | String name = r.name;
50 | int outerAltNum = inode.getOuterAltNum();
51 | if ( altLabels!=null ) {
52 | if ( outerAltNum>=0 && outerAltNum1 ) {
60 | return name + ":" +outerAltNum;
61 | }
62 | else {
63 | return name; // don't display an alternative number if there's only one
64 | }
65 | }
66 | else if (node instanceof TerminalNode) {
67 | return getLabelForToken( ((TerminalNode)node).getSymbol() );
68 | }
69 | return Trees.getNodeText(node, Arrays.asList(parser.getRuleNames()));
70 | }
71 |
72 | private String getLabelForToken(Token token) {
73 | String text = token.getText();
74 | if (text.equals("")) {
75 | return text;
76 | }
77 |
78 | String symbolicName = parser.getVocabulary().getSymbolicName(token.getType());
79 | if ( symbolicName==null ) { // it's a literal like ';' or 'return'
80 | return text;
81 | }
82 | if ( text.toUpperCase().equals(symbolicName) ) { // IMPORT:import
83 | return symbolicName;
84 | }
85 | return symbolicName + ":" + text;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/preview/CancelParserAction.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.preview;
2 |
3 | import com.intellij.icons.AllIcons;
4 | import com.intellij.openapi.actionSystem.ActionUpdateThread;
5 | import com.intellij.openapi.actionSystem.AnAction;
6 | import com.intellij.openapi.actionSystem.AnActionEvent;
7 | import org.antlr.intellij.plugin.ANTLRv4PluginController;
8 | import org.jetbrains.annotations.NotNull;
9 |
10 | /**
11 | * A button that allows the user to kill the interpreter if it's taking too long to
12 | * process the input in the Preview window.
13 | */
14 | public class CancelParserAction extends AnAction {
15 |
16 | private boolean enabled = false;
17 |
18 | public CancelParserAction() {
19 | super("Cancel Parsing", "Cancel the current parsing", AllIcons.Actions.Suspend);
20 | }
21 |
22 | @Override
23 | public void update(@NotNull AnActionEvent e) {
24 | super.update(e);
25 |
26 | e.getPresentation().setEnabled(enabled);
27 | }
28 |
29 | @Override
30 | public @NotNull ActionUpdateThread getActionUpdateThread() {
31 | return ActionUpdateThread.EDT;
32 | }
33 |
34 | @Override
35 | public void actionPerformed(@NotNull AnActionEvent e) {
36 | final ANTLRv4PluginController controller = ANTLRv4PluginController.getInstance(e.getProject());
37 |
38 | if (controller != null) {
39 | controller.abortCurrentParsing();
40 | }
41 | }
42 |
43 | public void setEnabled(boolean enabled) {
44 | this.enabled = enabled;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/preview/InputPanel.form:
--------------------------------------------------------------------------------
1 |
2 |
85 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/preview/ParsingResultSelectionListener.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.preview;
2 |
3 | import org.antlr.v4.runtime.tree.Tree;
4 |
5 | /**
6 | * Fired when a parsing result element (token or matched rule)
7 | * is selected in one of the viewers. Used to highlight the
8 | * corresponding area in the input editor.
9 | */
10 | public interface ParsingResultSelectionListener {
11 | void onParserRuleSelected(Tree rule);
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/preview/PreviewState.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.preview;
2 |
3 | import com.intellij.openapi.application.ApplicationManager;
4 | import com.intellij.openapi.editor.Editor;
5 | import com.intellij.openapi.editor.EditorFactory;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.openapi.vfs.VirtualFile;
8 | import org.antlr.intellij.plugin.parsing.ParsingResult;
9 | import org.antlr.v4.tool.Grammar;
10 | import org.antlr.v4.tool.LexerGrammar;
11 |
12 | /** Track everything associated with the state of the preview window.
13 | * For each grammar, we need to track an InputPanel (with <= 2 editor objects)
14 | * that we will flip to every time we come back to a specific grammar,
15 | * uniquely identified by the fully-qualified grammar name.
16 | *
17 | * Before parsing can begin, we need to know the start rule. That means that
18 | * we should not show an editor until this field is filled in.
19 | *
20 | * The plug-in controller should update all of these elements atomically so
21 | * they are self consistent. We must be careful then to send these fields
22 | * around together as a unit instead of asking the controller for the
23 | * elements piecemeal. That could get g and lg for different grammar files,
24 | * for example.
25 | */
26 | public class PreviewState {
27 | public Project project;
28 | public VirtualFile grammarFile;
29 | public Grammar g;
30 | public LexerGrammar lg;
31 | public String startRuleName;
32 | public CharSequence manualInputText = ""; // save input when switching grammars
33 | public VirtualFile inputFile; // save input file when switching grammars
34 |
35 | public ParsingResult parsingResult;
36 |
37 | /** The current input editor (inputEditor or fileEditor) for this grammar
38 | * in InputPanel. This can be null when a PreviewState and InputPanel
39 | * are created out of sync. Depends on order IDE opens files vs
40 | * creates preview pane.
41 | */
42 | private Editor inputEditor;
43 |
44 | public PreviewState(Project project, VirtualFile grammarFile) {
45 | this.project = project;
46 | this.grammarFile = grammarFile;
47 | }
48 |
49 | public synchronized Editor getInputEditor() {
50 | return inputEditor;
51 | }
52 |
53 | public synchronized void setInputEditor(Editor inputEditor) {
54 | releaseEditor();
55 | this.inputEditor = inputEditor;
56 | }
57 |
58 | public Grammar getMainGrammar() {
59 | return g!=null ? g : lg;
60 | }
61 |
62 | public synchronized void releaseEditor() {
63 |
64 | // Editor can't be release during unit tests, because it is used by multiple tests
65 | if (ApplicationManager.getApplication().isUnitTestMode()) return;
66 |
67 | // It would appear that the project closed event occurs before these
68 | // close grammars sometimes. Very strange. check for null editor.
69 | if (inputEditor != null) {
70 | final EditorFactory factory = EditorFactory.getInstance();
71 | factory.releaseEditor(inputEditor);
72 | inputEditor = null;
73 | }
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/preview/TrackpadZoomingTreeView.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.preview;
2 |
3 | import com.intellij.ui.components.Magnificator;
4 | import org.antlr.v4.runtime.tree.Tree;
5 |
6 | import javax.swing.*;
7 | import java.awt.*;
8 |
9 | /**
10 | * Created by jason on 2/7/15.
11 | */
12 | public class TrackpadZoomingTreeView extends UberTreeViewer implements Magnificator {
13 | public TrackpadZoomingTreeView(java.util.List ruleNames, Tree tree, boolean highlightUnreachedNodes) {
14 | super(ruleNames, tree, highlightUnreachedNodes);
15 | //TODO: memory leak?
16 | putClientProperty(Magnificator.CLIENT_PROPERTY_KEY, this);
17 | }
18 |
19 | public final ScaleModel scaleModel = new ScaleModel(1000);
20 |
21 | @Override
22 | public Point magnify(double magnification, Point at) {
23 | double s = getScale();
24 | scaleModel.setDoubleValue(magnification * s);
25 | return at;
26 | }
27 |
28 | static final double SCALE_MIN = 0.1;
29 | static final double SCALE_MAX = 2.5;
30 | static final double SCALE_RANGE = SCALE_MAX - SCALE_MIN;
31 |
32 | class ScaleModel extends DefaultBoundedRangeModel {
33 | ScaleModel(int ticks) {
34 | super(ticks / 2, 0, 1, ticks);
35 | }
36 |
37 | int range() {
38 | return getMaximum() - getMinimum();
39 | }
40 |
41 | //TODO: these methods could use caching if performance becomes an issue;
42 | double i2dTranslate(double val) {
43 | return val + (SCALE_MIN - (double) getMinimum());
44 | }
45 |
46 | double i2dScale(double val) {
47 | return val * (SCALE_RANGE / ((double) range()));
48 | }
49 |
50 | double d2iTranslate(double val) {
51 | return val + (((double) getMinimum()) - SCALE_MIN);
52 | }
53 |
54 | double d2iScale(double val) {
55 | return val * ((double) range()) / SCALE_RANGE;
56 | }
57 |
58 |
59 | int computeIntValue(double doubleValue) {
60 | return Math.round((float) d2iTranslate(d2iScale(doubleValue)));
61 | }
62 |
63 | double computeDoubleValue() {
64 | return i2dScale(i2dTranslate((double) getValue()));
65 | }
66 |
67 | @Override
68 | public void setValue(int i) {
69 | super.setValue(i);
70 | TrackpadZoomingTreeView.this.doSetScale(computeDoubleValue());
71 |
72 | }
73 |
74 | public void setDoubleValue(double value) {
75 | setValue(computeIntValue(value));
76 | }
77 |
78 | public double getDoubleValue() {
79 | return TrackpadZoomingTreeView.this.getScale();
80 | }
81 |
82 | }
83 |
84 | static double clamp(double val) {
85 | if (val <= SCALE_MIN) return SCALE_MIN;
86 | if (val >= SCALE_MAX) return SCALE_MAX;
87 | return val;
88 | }
89 |
90 | void doSetScale(double scale) {
91 | super.setScale(clamp(scale));
92 | }
93 |
94 | @Override
95 | public void setScale(double scale) {
96 | //route everything through the scale model so that the slider will stay in sync;
97 | scaleModel.setDoubleValue(scale);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/preview/UberTreeViewer.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.preview;
2 |
3 | import com.intellij.ui.DarculaColors;
4 | import com.intellij.ui.Gray;
5 | import com.intellij.ui.JBColor;
6 | import org.antlr.intellij.plugin.parsing.PreviewInterpreterRuleContext;
7 | import org.antlr.v4.gui.TreeViewer;
8 | import org.antlr.v4.runtime.ParserRuleContext;
9 | import org.antlr.v4.runtime.tree.ErrorNode;
10 | import org.antlr.v4.runtime.tree.Tree;
11 |
12 | import java.awt.*;
13 | import java.awt.geom.Rectangle2D;
14 | import java.util.List;
15 |
16 | public class UberTreeViewer extends TreeViewer {
17 | private final boolean highlightUnreachedNodes;
18 |
19 | public UberTreeViewer(List ruleNames, Tree tree, boolean highlightUnreachedNodes) {
20 | super(ruleNames, tree);
21 | this.highlightUnreachedNodes = highlightUnreachedNodes;
22 | }
23 |
24 | @Override
25 | protected void paintBox(Graphics g, Tree tree) {
26 | customPaintBox(g, tree);
27 |
28 | Rectangle2D.Double box = getBoundsOfNode(tree);
29 | if ( tree instanceof PreviewInterpreterRuleContext ) {
30 | PreviewInterpreterRuleContext ctx = (PreviewInterpreterRuleContext)tree;
31 | if ( highlightUnreachedNodes && !ctx.reached ) {
32 | g.setColor(JBColor.orange);
33 | g.drawRoundRect((int) box.x, (int) box.y, (int) box.width - 1,
34 | (int) box.height - 1, arcSize, arcSize);
35 | }
36 | }
37 | }
38 |
39 | // Customized version of super.paintBox() that supports Darcula colors
40 | private void customPaintBox(Graphics g, Tree tree) {
41 | Rectangle2D.Double box = getBoundsOfNode(tree);
42 | // draw the box in the background
43 | boolean ruleFailedAndMatchedNothing = false;
44 | if ( tree instanceof ParserRuleContext ) {
45 | ParserRuleContext ctx = (ParserRuleContext) tree;
46 | ruleFailedAndMatchedNothing = ctx.exception != null &&
47 | ctx.stop != null && ctx.stop.getTokenIndex() < ctx.start.getTokenIndex();
48 | }
49 | if ( isHighlighted(tree) || boxColor!=null ||
50 | tree instanceof ErrorNode ||
51 | ruleFailedAndMatchedNothing)
52 | {
53 | if ( isHighlighted(tree) ) g.setColor(highlightedBoxColor);
54 | else if ( tree instanceof ErrorNode || ruleFailedAndMatchedNothing ) g.setColor(DarculaColors.RED);
55 | else g.setColor(boxColor);
56 | g.fillRoundRect((int) box.x, (int) box.y, (int) box.width,
57 | (int) box.height, arcSize, arcSize);
58 | }
59 | if ( borderColor!=null ) {
60 | g.setColor(borderColor);
61 | g.drawRoundRect((int) box.x, (int) box.y, (int) box.width,
62 | (int) box.height, arcSize, arcSize);
63 | }
64 |
65 | // draw the text on top of the box (possibly multiple lines)
66 | if ( tree instanceof ErrorNode || ruleFailedAndMatchedNothing ) {
67 | g.setColor(Gray._64);
68 | }
69 | else {
70 | g.setColor(textColor);
71 | }
72 | String s = getText(tree);
73 | String[] lines = s.split("\n");
74 | FontMetrics m = getFontMetrics(font);
75 | int x = (int) box.x + arcSize / 2 + nodeWidthPadding;
76 | int y = (int) box.y + m.getAscent() + m.getLeading() + 1 + nodeHeightPadding;
77 | for (int i = 0; i < lines.length; i++) {
78 | text(g, lines[i], x, y);
79 | y += m.getHeight();
80 | }
81 | }
82 |
83 | @Override
84 | public void setTree(Tree root) {
85 | setTextColor(JBColor.BLACK);
86 | super.setTree(root);
87 | }
88 |
89 | public boolean hasTree() {
90 | return treeLayout!=null;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/preview/WrappedFlowLayout.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2016 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.antlr.intellij.plugin.preview;
17 |
18 | import javax.swing.*;
19 | import java.awt.*;
20 |
21 | public class WrappedFlowLayout extends FlowLayout {
22 |
23 | public WrappedFlowLayout(int hGap, int vGap) {
24 | super(FlowLayout.LEADING, hGap, vGap);
25 | }
26 |
27 | @Override
28 | public Dimension preferredLayoutSize(Container target) {
29 | Dimension baseSize = super.preferredLayoutSize(target);
30 | if (getAlignOnBaseline()) {
31 | return baseSize;
32 | }
33 |
34 | return getWrappedSize(target);
35 | }
36 |
37 | public Dimension getWrappedSize(Container target) {
38 | Container parent = SwingUtilities.getUnwrappedParent(target);
39 | int maxWidth = parent.getWidth() - (parent.getInsets().left + parent.getInsets().right);
40 |
41 | return getDimension(target, maxWidth);
42 | }
43 |
44 | public Dimension getDimension(Container target, int maxWidth) {
45 | Insets insets = target.getInsets();
46 | int height = insets.top + insets.bottom;
47 | int width = insets.left + insets.right;
48 |
49 | int rowHeight = 0;
50 | int rowWidth = insets.left + insets.right;
51 |
52 | boolean isVisible = false;
53 | boolean start = true;
54 |
55 | synchronized (target.getTreeLock()) {
56 | for (int i = 0; i < target.getComponentCount(); i++) {
57 | Component component = target.getComponent(i);
58 | if (component.isVisible()) {
59 | isVisible = true;
60 | Dimension size = component.getPreferredSize();
61 |
62 | if (rowWidth + getHgap() + size.width > maxWidth && !start) {
63 | height += getVgap() + rowHeight;
64 | width = Math.max(width, rowWidth);
65 |
66 | rowWidth = insets.left + insets.right;
67 | rowHeight = 0;
68 | }
69 |
70 | rowWidth += getHgap() + size.width;
71 | rowHeight = Math.max(rowHeight, size.height);
72 |
73 | start = false;
74 | }
75 | }
76 | height += getVgap() + rowHeight;
77 | width = Math.max(width, rowWidth);
78 |
79 | if (!isVisible) {
80 | return super.preferredLayoutSize(target);
81 | }
82 | else {
83 | return new Dimension(width, height);
84 | }
85 | }
86 | }
87 |
88 | @Override
89 | public Dimension minimumLayoutSize(Container target) {
90 | if (getAlignOnBaseline()) return super.minimumLayoutSize(target);
91 |
92 | return getWrappedSize(target);
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/profiler/ProfilerTableDataModel.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.profiler;
2 |
3 | import javax.swing.table.AbstractTableModel;
4 |
5 | public abstract class ProfilerTableDataModel extends AbstractTableModel {
6 |
7 | public abstract String[] getColumnNames();
8 | public abstract String[] getColumnToolTips();
9 |
10 | @Override
11 | public String getColumnName(int column) {
12 | return getColumnNames()[column];
13 | }
14 |
15 | @Override
16 | public Class> getColumnClass(int columnIndex) {
17 | return Integer.class;
18 | }
19 |
20 | @Override
21 | public int getColumnCount() {
22 | return getColumnNames().length;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/profiler/SimpleProfilerTableDataModel.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.profiler;
2 |
3 | import org.antlr.v4.runtime.Parser;
4 | import org.antlr.v4.runtime.atn.DecisionInfo;
5 | import org.antlr.v4.runtime.atn.ParseInfo;
6 |
7 | import java.math.BigDecimal;
8 | import java.math.RoundingMode;
9 | import java.util.LinkedHashMap;
10 |
11 | public class SimpleProfilerTableDataModel extends ProfilerTableDataModel {
12 | public ParseInfo parseInfo;
13 | public LinkedHashMap nameToColumnMap = new LinkedHashMap<>();
14 | public static final String[] columnNames = {
15 | "Rule","Invocations", "Time (ms)", "Total k", "Max k", "Ambiguities", "DFA cache miss"
16 | };
17 |
18 | public static final String[] columnToolTips = {
19 | "name of rule and decision no",
20 | "# decision invocations",
21 | "Rough estimate of time (ms) spent in prediction",
22 | "Total lookahead symbols examined",
23 | "Max lookahead symbols examined in any decision event",
24 | "# of ambiguous input phrases",
25 | "# of non-DFA transitions during prediction (cache miss)"
26 | };
27 |
28 | private final String[] ruleNamesByDecision ;
29 | public SimpleProfilerTableDataModel(ParseInfo parseInfo,Parser parser) {
30 | this.parseInfo = parseInfo;
31 | /*copying rule names to not hold ref to parser object*/
32 | ruleNamesByDecision = new String[parser.getATN().decisionToState.size()];
33 | for(int i = 0; i < ruleNamesByDecision .length; i++) {
34 | ruleNamesByDecision [i] = parser.getRuleNames()[parser.getATN().getDecisionState(i).ruleIndex];
35 | }
36 | for (int i = 0; i < columnNames.length; i++) {
37 | nameToColumnMap.put(columnNames[i], i);
38 | }
39 | }
40 |
41 | @Override
42 | public String[] getColumnNames() {
43 | return columnNames;
44 | }
45 |
46 | @Override
47 | public String[] getColumnToolTips() {
48 | return columnToolTips;
49 | }
50 |
51 | @Override
52 | public int getRowCount() {
53 | return parseInfo.getDecisionInfo().length;
54 | }
55 |
56 | @Override
57 | public Object getValueAt(int row, int col) {
58 | int decision = row;
59 | DecisionInfo decisionInfo = parseInfo.getDecisionInfo()[decision];
60 | switch (col) { // laborious but more efficient than reflection
61 | case 0:
62 | return String.format("%s (%d)",ruleNamesByDecision [decision],decision);
63 | case 1:
64 | return decisionInfo.invocations;
65 | case 2:
66 | return BigDecimal.valueOf(decisionInfo.timeInPrediction / (1000.0 * 1000.0)).setScale(3, RoundingMode.HALF_DOWN);
67 | case 3:
68 | return decisionInfo.LL_TotalLook+decisionInfo.SLL_TotalLook;
69 | case 4:
70 | return Math.max(decisionInfo.LL_MaxLook, decisionInfo.SLL_MaxLook);
71 | case 5:
72 | return decisionInfo.ambiguities.size();
73 | case 6:
74 | return decisionInfo.SLL_ATNTransitions+
75 | decisionInfo.LL_ATNTransitions;
76 | }
77 | return "n/a";
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/ANTLRv4IndexPatternBuilder.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.lexer.Lexer;
4 | import com.intellij.psi.PsiFile;
5 | import com.intellij.psi.impl.search.IndexPatternBuilder;
6 | import com.intellij.psi.tree.IElementType;
7 | import com.intellij.psi.tree.TokenSet;
8 | import org.antlr.intellij.plugin.ANTLRv4FileRoot;
9 | import org.antlr.intellij.plugin.adaptors.ANTLRv4LexerAdaptor;
10 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
11 | import org.jetbrains.annotations.NotNull;
12 | import org.jetbrains.annotations.Nullable;
13 |
14 | import static org.antlr.intellij.plugin.ANTLRv4TokenTypes.getTokenElementType;
15 |
16 | public class ANTLRv4IndexPatternBuilder implements IndexPatternBuilder {
17 |
18 | @Nullable
19 | @Override
20 | public Lexer getIndexingLexer(@NotNull PsiFile file) {
21 | if ( file instanceof ANTLRv4FileRoot ) {
22 | ANTLRv4Lexer lexer = new ANTLRv4Lexer(null);
23 | return new ANTLRv4LexerAdaptor(lexer);
24 | }
25 | return null;
26 | }
27 |
28 | @Nullable
29 | @Override
30 | public TokenSet getCommentTokenSet(@NotNull PsiFile file) {
31 | if ( file instanceof ANTLRv4FileRoot ) {
32 | return TokenSet.create(getTokenElementType(ANTLRv4Lexer.LINE_COMMENT));
33 | }
34 | return null;
35 | }
36 |
37 | @Override
38 | public int getCommentStartDelta(IElementType tokenType) {
39 | return tokenType==getTokenElementType(ANTLRv4Lexer.LINE_COMMENT) ? 2 : 0;
40 | }
41 |
42 | @Override
43 | public int getCommentEndDelta(IElementType tokenType) {
44 | return 0;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/AtAction.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.extapi.psi.ASTWrapperPsiElement;
4 | import com.intellij.lang.ASTNode;
5 | import com.intellij.psi.PsiElement;
6 | import org.antlr.intellij.adaptor.parser.PsiElementFactory;
7 | import org.antlr.intellij.plugin.ANTLRv4TokenTypes;
8 | import org.antlr.intellij.plugin.parser.ANTLRv4Parser;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | public class AtAction extends ASTWrapperPsiElement {
12 | public AtAction(@NotNull ASTNode node) {
13 | super(node);
14 | }
15 |
16 | @NotNull
17 | public String getIdText() {
18 | PsiElement id = findChildByType(ANTLRv4TokenTypes.getRuleElementType(ANTLRv4Parser.RULE_identifier));
19 |
20 | return id==null ? "" : id.getText();
21 | }
22 |
23 | @NotNull
24 | public String getActionBlockText() {
25 | PsiElement actionBlock = findChildByType(ANTLRv4TokenTypes.getRuleElementType(ANTLRv4Parser.RULE_actionBlock));
26 |
27 | if (actionBlock != null) {
28 | PsiElement openingBrace = actionBlock.getFirstChild();
29 | PsiElement closingBrace = actionBlock.getLastChild();
30 |
31 | return actionBlock.getText().substring(openingBrace.getStartOffsetInParent() + 1, closingBrace.getStartOffsetInParent());
32 | }
33 |
34 | return "";
35 | }
36 |
37 | public static class Factory implements PsiElementFactory {
38 | public static Factory INSTANCE = new Factory();
39 |
40 | @Override
41 | public PsiElement createElement(ASTNode node) {
42 | return new AtAction(node);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/ChannelSpecNode.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.psi.tree.IElementType;
5 | import com.intellij.psi.util.PsiTreeUtil;
6 | import org.antlr.intellij.plugin.ANTLRv4TokenTypes;
7 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
8 | import org.jetbrains.annotations.NotNull;
9 |
10 | /**
11 | * A channel defined in the {@code channels} section.
12 | */
13 | public class ChannelSpecNode extends RuleSpecNode {
14 |
15 | public ChannelSpecNode(@NotNull ASTNode node) {
16 | super(node);
17 | }
18 |
19 | @Override
20 | public GrammarElementRefNode getNameIdentifier() {
21 | return PsiTreeUtil.getChildOfType(this, LexerRuleRefNode.class);
22 | }
23 |
24 | @Override
25 | public IElementType getRuleRefType() {
26 | return ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.TOKEN_REF);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/GrammarElementRef.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.openapi.project.Project;
4 | import com.intellij.openapi.util.TextRange;
5 | import com.intellij.psi.PsiElement;
6 | import com.intellij.psi.PsiFile;
7 | import com.intellij.psi.PsiReferenceBase;
8 | import com.intellij.psi.util.PsiTreeUtil;
9 | import com.intellij.util.IncorrectOperationException;
10 | import org.antlr.intellij.plugin.ANTLRv4TokenTypes;
11 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
12 | import org.antlr.intellij.plugin.resolve.ImportResolver;
13 | import org.antlr.intellij.plugin.resolve.TokenVocabResolver;
14 | import org.jetbrains.annotations.NotNull;
15 | import org.jetbrains.annotations.Nullable;
16 |
17 | import java.util.Collection;
18 |
19 | /**
20 | * A reference to a grammar element (parser rule, lexer rule or lexical mode).
21 | */
22 | public class GrammarElementRef extends PsiReferenceBase {
23 |
24 | private final String ruleName;
25 |
26 | public GrammarElementRef(GrammarElementRefNode idNode, String ruleName) {
27 | super(idNode, new TextRange(0, ruleName.length()));
28 | this.ruleName = ruleName;
29 | }
30 |
31 | /**
32 | * Using for completion. Returns list of rules and tokens; the prefix
33 | * of current element is used as filter by IDEA later.
34 | */
35 | @NotNull
36 | @Override
37 | public Object[] getVariants() {
38 | RulesNode rules = PsiTreeUtil.getContextOfType(myElement, RulesNode.class);
39 | // find all rule defs (token, parser)
40 | Collection extends RuleSpecNode> ruleSpecNodes =
41 | PsiTreeUtil.findChildrenOfAnyType(rules, ParserRuleSpecNode.class, LexerRuleSpecNode.class);
42 |
43 | return ruleSpecNodes.toArray();
44 | }
45 |
46 | /**
47 | * Called upon jump to def for this rule ref
48 | */
49 | @Nullable
50 | @Override
51 | public PsiElement resolve() {
52 | PsiFile tokenVocabFile = TokenVocabResolver.resolveTokenVocabFile(getElement());
53 |
54 | if ( tokenVocabFile!=null ) {
55 | return tokenVocabFile;
56 | }
57 |
58 | PsiFile importedFile = ImportResolver.resolveImportedFile(getElement());
59 | if ( importedFile!=null ) {
60 | return importedFile;
61 | }
62 |
63 | GrammarSpecNode grammar = PsiTreeUtil.getContextOfType(getElement(), GrammarSpecNode.class);
64 | PsiElement specNode = MyPsiUtils.findSpecNode(grammar, ruleName);
65 |
66 | if ( specNode!=null ) {
67 | return specNode;
68 | }
69 |
70 | // Look for a rule defined in an imported grammar
71 | specNode = ImportResolver.resolveInImportedFiles(getElement().getContainingFile(), ruleName);
72 |
73 | if ( specNode!=null ) {
74 | return specNode;
75 | }
76 |
77 | // Look for a lexer rule in the tokenVocab file if it exists
78 | if ( getElement() instanceof LexerRuleRefNode ) {
79 | return TokenVocabResolver.resolveInTokenVocab(getElement(), ruleName);
80 | }
81 |
82 | return null;
83 | }
84 |
85 | @Override
86 | public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
87 | Project project = getElement().getProject();
88 | myElement.replace(MyPsiUtils.createLeafFromText(project,
89 | myElement.getContext(),
90 | newElementName,
91 | ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.TOKEN_REF)));
92 | return myElement;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/GrammarElementRefNode.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.psi.impl.source.tree.LeafPsiElement;
4 | import com.intellij.psi.tree.IElementType;
5 |
6 | /**
7 | * Refs to tokens, rules
8 | */
9 | public abstract class GrammarElementRefNode extends LeafPsiElement {
10 | public GrammarElementRefNode(IElementType type, CharSequence text) {
11 | super(type, text);
12 | }
13 |
14 | @Override
15 | public String getName() {
16 | return getText();
17 | }
18 |
19 | @Override
20 | public String toString() {
21 | return getClass().getSimpleName() + "(" + getElementType() + ")";
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/GrammarSpecNode.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.extapi.psi.ASTWrapperPsiElement;
4 | import com.intellij.lang.ASTNode;
5 | import com.intellij.psi.PsiElement;
6 | import org.antlr.intellij.adaptor.parser.PsiElementFactory;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | public class GrammarSpecNode extends ASTWrapperPsiElement {
10 | public GrammarSpecNode(@NotNull ASTNode node) {
11 | super(node);
12 | }
13 |
14 | public static class Factory implements PsiElementFactory {
15 | public static Factory INSTANCE = new Factory();
16 |
17 | @Override
18 | public PsiElement createElement(ASTNode node) {
19 | return new GrammarSpecNode(node);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/LexerRuleRefNode.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.psi.PsiElement;
4 | import com.intellij.psi.PsiReference;
5 | import com.intellij.psi.tree.IElementType;
6 |
7 | public class LexerRuleRefNode extends GrammarElementRefNode {
8 | public LexerRuleRefNode(IElementType type, CharSequence text) {
9 | super(type, text);
10 | }
11 |
12 | @Override
13 | public PsiReference getReference() {
14 | if (isDeclaration()) {
15 | return null;
16 | }
17 | return new GrammarElementRef(this, getText());
18 | }
19 |
20 | private boolean isDeclaration() {
21 | PsiElement parent = getParent();
22 | return parent instanceof LexerRuleSpecNode
23 | || parent instanceof TokenSpecNode
24 | || parent instanceof ChannelSpecNode;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/LexerRuleSpecNode.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.openapi.diagnostic.Logger;
5 | import com.intellij.psi.PsiElement;
6 | import com.intellij.psi.tree.IElementType;
7 | import com.intellij.psi.util.PsiTreeUtil;
8 | import org.antlr.intellij.adaptor.parser.PsiElementFactory;
9 | import org.antlr.intellij.plugin.ANTLRv4TokenTypes;
10 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public class LexerRuleSpecNode extends RuleSpecNode {
14 | public static final Logger LOG = Logger.getInstance("org.antlr.intellij.plugin.psi.LexerRuleSpecNode");
15 | public LexerRuleSpecNode(@NotNull ASTNode node) {
16 | super(node);
17 | }
18 |
19 | @Override
20 | public IElementType getRuleRefType() {
21 | return ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.TOKEN_REF);
22 | }
23 |
24 | @Override
25 | public GrammarElementRefNode getNameIdentifier() {
26 | GrammarElementRefNode tr = PsiTreeUtil.getChildOfType(this, LexerRuleRefNode.class);
27 | if ( tr==null ) {
28 | LOG.error("can't find LexerRuleRefNode child of "+this.getText(), (Throwable)null);
29 | }
30 | return tr;
31 | }
32 |
33 | public boolean isFragment() {
34 | return getNode().findChildByType(ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.FRAGMENT)) != null;
35 | }
36 |
37 | public static class Factory implements PsiElementFactory {
38 | public static Factory INSTANCE = new Factory();
39 |
40 | @Override
41 | public PsiElement createElement(ASTNode node) {
42 | return new LexerRuleSpecNode(node);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/ModeSpecNode.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.psi.PsiElement;
5 | import com.intellij.psi.tree.IElementType;
6 | import org.antlr.intellij.adaptor.parser.PsiElementFactory;
7 | import org.antlr.intellij.plugin.ANTLRv4TokenTypes;
8 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
9 | import org.antlr.intellij.plugin.parser.ANTLRv4Parser;
10 | import org.jetbrains.annotations.NotNull;
11 |
12 | import static org.antlr.intellij.plugin.psi.MyPsiUtils.findFirstChildOfType;
13 |
14 | /**
15 | * A node representing a lexical {@code mode} definition, and all its child rules.
16 | *
17 | * @implNote this is technically not a 'rule', but it has the same characteristics as a named rule so we
18 | * can extend {@code RuleSpecNode}
19 | */
20 | public class ModeSpecNode extends RuleSpecNode {
21 |
22 | public ModeSpecNode(@NotNull ASTNode node) {
23 | super(node);
24 | }
25 |
26 | @Override
27 | public IElementType getRuleRefType() {
28 | return ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.TOKEN_REF);
29 | }
30 |
31 | @Override
32 | public GrammarElementRefNode getNameIdentifier() {
33 | PsiElement idNode = findFirstChildOfType(this, ANTLRv4TokenTypes.getRuleElementType(ANTLRv4Parser.RULE_identifier));
34 |
35 | if (idNode != null) {
36 | PsiElement firstChild = idNode.getFirstChild();
37 |
38 | if (firstChild instanceof GrammarElementRefNode) {
39 | return (GrammarElementRefNode) firstChild;
40 | }
41 | }
42 |
43 | return null;
44 | }
45 |
46 | public static class Factory implements PsiElementFactory {
47 | public static Factory INSTANCE = new Factory();
48 |
49 | @Override
50 | public PsiElement createElement(ASTNode node) {
51 | return new ModeSpecNode(node);
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/ParserRuleRefNode.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.psi.PsiReference;
4 | import com.intellij.psi.tree.IElementType;
5 |
6 | public class ParserRuleRefNode extends GrammarElementRefNode {
7 | public ParserRuleRefNode(IElementType type, CharSequence text) {
8 | super(type, text);
9 | }
10 |
11 | @Override
12 | public PsiReference getReference() {
13 | if (isDeclaration()) {
14 | return null;
15 | }
16 | return new GrammarElementRef(this, getText());
17 | }
18 |
19 | private boolean isDeclaration() {
20 | return getParent() instanceof ParserRuleSpecNode;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/ParserRuleSpecNode.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.openapi.diagnostic.Logger;
5 | import com.intellij.psi.PsiElement;
6 | import com.intellij.psi.tree.IElementType;
7 | import com.intellij.psi.util.PsiTreeUtil;
8 | import org.antlr.intellij.adaptor.parser.PsiElementFactory;
9 | import org.antlr.intellij.plugin.ANTLRv4TokenTypes;
10 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public class ParserRuleSpecNode extends RuleSpecNode {
14 | public static final Logger LOG = Logger.getInstance("org.antlr.intellij.plugin.psi.ParserRuleSpecNode");
15 | public ParserRuleSpecNode(@NotNull ASTNode node) {
16 | super(node);
17 | }
18 |
19 | @Override
20 | public IElementType getRuleRefType() {
21 | return ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.RULE_REF);
22 | }
23 |
24 | @Override
25 | public GrammarElementRefNode getNameIdentifier() {
26 | GrammarElementRefNode rr = PsiTreeUtil.getChildOfType(this, ParserRuleRefNode.class);
27 | if ( rr==null ) {
28 | LOG.error("can't find ParserRuleRefNode child of "+this.getText(), (Throwable)null);
29 | }
30 | return rr;
31 | }
32 |
33 | public static class Factory implements PsiElementFactory {
34 | public static Factory INSTANCE = new Factory();
35 |
36 | @Override
37 | public PsiElement createElement(ASTNode node) {
38 | return new ParserRuleSpecNode(node);
39 | }
40 | }
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/RuleSpecNode.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.extapi.psi.ASTWrapperPsiElement;
4 | import com.intellij.lang.ASTNode;
5 | import com.intellij.psi.PsiElement;
6 | import com.intellij.psi.PsiNameIdentifierOwner;
7 | import com.intellij.psi.tree.IElementType;
8 | import com.intellij.util.IncorrectOperationException;
9 | import org.jetbrains.annotations.NonNls;
10 | import org.jetbrains.annotations.NotNull;
11 | import org.jetbrains.annotations.Nullable;
12 |
13 | /** Root of lexer, parser rule defs */
14 | public abstract class RuleSpecNode extends ASTWrapperPsiElement implements PsiNameIdentifierOwner {
15 | protected String name = null; // an override to input text ID
16 |
17 | public RuleSpecNode(@NotNull final ASTNode node) {
18 | super(node);
19 | }
20 |
21 | @Override
22 | public String getName() {
23 | if ( name!=null ) return name;
24 | GrammarElementRefNode id = getNameIdentifier();
25 | if ( id!=null ) {
26 | return id.getText();
27 | }
28 | return "unknown-name";
29 | }
30 |
31 | @Nullable
32 | public abstract GrammarElementRefNode getNameIdentifier();
33 |
34 | @Override
35 | public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
36 | /*
37 | From doc: "Creating a fully correct AST node from scratch is
38 | quite difficult. Thus, surprisingly, the easiest way to
39 | get the replacement node is to create a dummy file in the
40 | custom language so that it would contain the necessary
41 | node in its parse tree, build the parse tree and
42 | extract the necessary node from it.
43 | */
44 | GrammarElementRefNode id = getNameIdentifier();
45 | if ( id != null ) {
46 | id.replace(MyPsiUtils.createLeafFromText(getProject(),
47 | getContext(),
48 | name, getRuleRefType()));
49 | }
50 | this.name = name;
51 | return this;
52 | }
53 |
54 | public abstract IElementType getRuleRefType();
55 |
56 | @Override
57 | public void subtreeChanged() {
58 | super.subtreeChanged();
59 | name = null;
60 | }
61 |
62 | @Override
63 | public int getTextOffset() {
64 | GrammarElementRefNode id = getNameIdentifier();
65 | if ( id!=null ) return id.getTextOffset();
66 | return super.getTextOffset();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/RulesNode.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.extapi.psi.ASTWrapperPsiElement;
4 | import com.intellij.lang.ASTNode;
5 | import com.intellij.psi.PsiElement;
6 | import org.antlr.intellij.adaptor.parser.PsiElementFactory;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | public class RulesNode extends ASTWrapperPsiElement {
10 | public RulesNode(@NotNull ASTNode node) {
11 | super(node);
12 | }
13 |
14 | public static class Factory implements PsiElementFactory {
15 | public static Factory INSTANCE = new Factory();
16 |
17 | @Override
18 | public PsiElement createElement(ASTNode node) {
19 | return new RulesNode(node);
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/StringLiteralElement.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.psi.PsiElement;
4 | import com.intellij.psi.PsiReference;
5 | import com.intellij.psi.impl.source.tree.LeafPsiElement;
6 | import com.intellij.psi.tree.IElementType;
7 |
8 | import static org.antlr.intellij.plugin.ANTLRv4TokenTypes.RULE_ELEMENT_TYPES;
9 | import static org.antlr.intellij.plugin.parser.ANTLRv4Parser.RULE_optionValue;
10 |
11 | public class StringLiteralElement extends LeafPsiElement {
12 | public StringLiteralElement(IElementType type, CharSequence text) {
13 | super(type, text);
14 | }
15 |
16 | @Override
17 | public PsiReference getReference() {
18 | PsiElement parent = getParent();
19 |
20 | if ( parent!=null && parent.getNode().getElementType()==RULE_ELEMENT_TYPES.get(RULE_optionValue) ) {
21 | return new StringLiteralRef(this);
22 | }
23 |
24 | return super.getReference();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/StringLiteralRef.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.openapi.util.TextRange;
4 | import com.intellij.psi.PsiElement;
5 | import com.intellij.psi.PsiReferenceBase;
6 | import com.intellij.util.ArrayUtilRt;
7 | import org.antlr.intellij.plugin.resolve.TokenVocabResolver;
8 | import org.jetbrains.annotations.Nullable;
9 |
10 | public class StringLiteralRef extends PsiReferenceBase {
11 |
12 | public StringLiteralRef(StringLiteralElement node) {
13 | super(node, TextRange.from(1, node.getTextLength() - 2));
14 | }
15 |
16 | @Override // For compatibility with 2017.x
17 | public Object[] getVariants() {
18 | return ArrayUtilRt.EMPTY_OBJECT_ARRAY;
19 | }
20 |
21 | @Override
22 | public @Nullable PsiElement resolve() {
23 | return TokenVocabResolver.resolveTokenVocabFile(myElement);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/psi/TokenSpecNode.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.psi;
2 |
3 | import com.intellij.extapi.psi.ASTWrapperPsiElement;
4 | import com.intellij.lang.ASTNode;
5 | import com.intellij.psi.PsiElement;
6 | import com.intellij.psi.tree.IElementType;
7 | import com.intellij.psi.util.PsiTreeUtil;
8 | import org.antlr.intellij.adaptor.parser.PsiElementFactory;
9 | import org.antlr.intellij.plugin.ANTLRv4TokenTypes;
10 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
11 | import org.antlr.intellij.plugin.parser.ANTLRv4Parser;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | /**
15 | * A token defined in the {@code tokens} section.
16 | */
17 | public class TokenSpecNode extends RuleSpecNode {
18 |
19 | public TokenSpecNode(@NotNull ASTNode node) {
20 | super(node);
21 | }
22 |
23 | @Override
24 | public GrammarElementRefNode getNameIdentifier() {
25 | return PsiTreeUtil.getChildOfType(this, LexerRuleRefNode.class);
26 | }
27 |
28 | @Override
29 | public IElementType getRuleRefType() {
30 | return ANTLRv4TokenTypes.TOKEN_ELEMENT_TYPES.get(ANTLRv4Lexer.TOKEN_REF);
31 | }
32 |
33 | public static class Factory implements PsiElementFactory {
34 | public static Factory INSTANCE = new Factory();
35 |
36 | @Override
37 | public PsiElement createElement(ASTNode node) {
38 | ASTNode idList = node.getTreeParent();
39 | ASTNode parent = null;
40 |
41 | if (idList != null) {
42 | parent = idList.getTreeParent();
43 | }
44 | if (parent != null) {
45 | if (parent.getElementType() == ANTLRv4TokenTypes.RULE_ELEMENT_TYPES.get(ANTLRv4Parser.RULE_tokensSpec)) {
46 | return new TokenSpecNode(node);
47 | }
48 | else if (parent.getElementType() == ANTLRv4TokenTypes.RULE_ELEMENT_TYPES.get(ANTLRv4Parser.RULE_channelsSpec)) {
49 | return new ChannelSpecNode(node);
50 | }
51 | }
52 |
53 | return new ASTWrapperPsiElement(node);
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/refactor/ANTLRv4RefactoringSupport.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.refactor;
2 |
3 | import com.intellij.lang.refactoring.RefactoringSupportProvider;
4 | import com.intellij.psi.PsiElement;
5 | import org.antlr.intellij.plugin.ANTLRv4Language;
6 | import org.antlr.intellij.plugin.psi.RuleSpecNode;
7 | import org.jetbrains.annotations.NotNull;
8 | import org.jetbrains.annotations.Nullable;
9 |
10 | public class ANTLRv4RefactoringSupport extends RefactoringSupportProvider{
11 |
12 | public boolean isAvailable(@NotNull PsiElement context){
13 | return context.getLanguage().isKindOf(ANTLRv4Language.INSTANCE);
14 | }
15 |
16 | // variable in-place rename only applies to elements limited to one file
17 | public boolean isMemberInplaceRenameAvailable(@NotNull PsiElement element, @Nullable PsiElement context){
18 | return element instanceof RuleSpecNode;
19 | }
20 | }
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/resolve/ImportResolver.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.resolve;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.psi.PsiElement;
5 | import com.intellij.psi.PsiFile;
6 | import com.intellij.psi.PsiRecursiveElementVisitor;
7 | import com.intellij.psi.util.PsiTreeUtil;
8 | import org.antlr.intellij.plugin.parser.ANTLRv4Parser;
9 | import org.antlr.intellij.plugin.psi.GrammarElementRefNode;
10 | import org.antlr.intellij.plugin.psi.GrammarSpecNode;
11 | import org.antlr.intellij.plugin.psi.MyPsiUtils;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | import static org.antlr.intellij.plugin.ANTLRv4TokenTypes.RULE_ELEMENT_TYPES;
18 | import static org.antlr.intellij.plugin.resolve.TokenVocabResolver.findRelativeFile;
19 |
20 | public class ImportResolver {
21 |
22 | public static PsiFile resolveImportedFile(GrammarElementRefNode reference) {
23 | PsiElement importStatement = PsiTreeUtil.findFirstParent(reference, ImportResolver::isImportStatement);
24 |
25 | if ( importStatement!=null ) {
26 | return findRelativeFile(reference.getText(), reference.getContainingFile());
27 | }
28 |
29 | return null;
30 | }
31 |
32 | private static boolean isImportStatement(PsiElement el) {
33 | ASTNode node = el.getNode();
34 | return node != null && node.getElementType() == RULE_ELEMENT_TYPES.get(ANTLRv4Parser.RULE_delegateGrammar);
35 | }
36 |
37 | public static PsiElement resolveInImportedFiles(@NotNull PsiFile grammarFile, @NotNull String ruleName) {
38 | return resolveInImportedFiles(grammarFile, ruleName, new ArrayList<>());
39 | }
40 |
41 | private static PsiElement resolveInImportedFiles(PsiFile grammarFile, String ruleName, List visitedFiles) {
42 | DelegateGrammarsVisitor visitor = new DelegateGrammarsVisitor();
43 | grammarFile.accept(visitor);
44 |
45 | for ( PsiFile importedGrammar : visitor.importedGrammars ) {
46 | if ( visitedFiles.contains(importedGrammar) ) {
47 | continue;
48 | }
49 | visitedFiles.add(importedGrammar);
50 |
51 | GrammarSpecNode grammar = PsiTreeUtil.getChildOfType(importedGrammar, GrammarSpecNode.class);
52 | PsiElement specNode = MyPsiUtils.findSpecNode(grammar, ruleName);
53 |
54 | if ( specNode!=null ) {
55 | return specNode;
56 | }
57 |
58 | // maybe the imported grammar also imports other grammars itself?
59 | specNode = resolveInImportedFiles(importedGrammar, ruleName, visitedFiles);
60 | if ( specNode!=null ) {
61 | return specNode;
62 | }
63 | }
64 |
65 | return null;
66 | }
67 |
68 | private static class DelegateGrammarsVisitor extends PsiRecursiveElementVisitor {
69 |
70 | List importedGrammars = new ArrayList<>();
71 |
72 | @Override
73 | public void visitElement(PsiElement element) {
74 | if ( isImportStatement(element) ) {
75 | PsiFile importedGrammar = findRelativeFile(element.getText(), element.getContainingFile());
76 |
77 | if (importedGrammar != null) {
78 | importedGrammars.add(importedGrammar);
79 | }
80 | }
81 | super.visitElement(element);
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/resolve/TokenVocabResolver.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.resolve;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.psi.PsiDirectory;
5 | import com.intellij.psi.PsiElement;
6 | import com.intellij.psi.PsiFile;
7 | import com.intellij.psi.util.PsiTreeUtil;
8 | import org.antlr.intellij.plugin.ANTLRv4FileRoot;
9 | import org.antlr.intellij.plugin.parser.ANTLRv4Parser;
10 | import org.antlr.intellij.plugin.psi.*;
11 | import org.apache.commons.lang.StringUtils;
12 | import org.jetbrains.annotations.Nullable;
13 |
14 | import static org.antlr.intellij.plugin.ANTLRv4TokenTypes.RULE_ELEMENT_TYPES;
15 |
16 | public class TokenVocabResolver {
17 |
18 | /**
19 | * If this reference is the value of a {@code tokenVocab} option, returns the corresponding
20 | * grammar file.
21 | */
22 | @Nullable
23 | public static PsiFile resolveTokenVocabFile(PsiElement reference) {
24 | PsiElement optionValue = PsiTreeUtil.findFirstParent(reference, TokenVocabResolver::isOptionValue);
25 |
26 | if (optionValue != null) {
27 | PsiElement option = optionValue.getParent();
28 |
29 | if (option != null) {
30 | PsiElement optionName = PsiTreeUtil.getDeepestFirst(option);
31 |
32 | if (optionName.getText().equals("tokenVocab")) {
33 | String text = StringUtils.strip(reference.getText(), "'");
34 | return findRelativeFile(text, reference.getContainingFile());
35 | }
36 | }
37 | }
38 |
39 | return null;
40 | }
41 |
42 | /**
43 | * Tries to find a declaration named {@code ruleName} in the {@code tokenVocab} file if it exists.
44 | */
45 | @Nullable
46 | public static PsiElement resolveInTokenVocab(GrammarElementRefNode reference, String ruleName) {
47 | String tokenVocab = MyPsiUtils.findTokenVocabIfAny((ANTLRv4FileRoot) reference.getContainingFile());
48 |
49 | if (tokenVocab != null) {
50 | PsiFile tokenVocabFile = findRelativeFile(tokenVocab, reference.getContainingFile());
51 |
52 | if (tokenVocabFile != null) {
53 | GrammarSpecNode lexerGrammar = PsiTreeUtil.findChildOfType(tokenVocabFile, GrammarSpecNode.class);
54 | PsiElement node = MyPsiUtils.findSpecNode(lexerGrammar, ruleName);
55 |
56 | if (node instanceof LexerRuleSpecNode) {
57 | // fragments are not visible to the parser
58 | if (!((LexerRuleSpecNode) node).isFragment()) {
59 | return node;
60 | }
61 | }
62 | if (node instanceof TokenSpecNode) {
63 | return node;
64 | }
65 | }
66 | }
67 |
68 | return null;
69 | }
70 |
71 | private static boolean isOptionValue(PsiElement el) {
72 | ASTNode node = el.getNode();
73 | return node != null && node.getElementType() == RULE_ELEMENT_TYPES.get(ANTLRv4Parser.RULE_optionValue);
74 | }
75 |
76 | /**
77 | * Looks for an ANTLR grammar file named {@code }.g4 next to the given {@code sibling} file.
78 | */
79 | static PsiFile findRelativeFile(String baseName, PsiFile sibling) {
80 | PsiDirectory parentDirectory = sibling.getParent();
81 |
82 | if (parentDirectory != null) {
83 | PsiFile candidate = parentDirectory.findFile(baseName + ".g4");
84 |
85 | if (candidate instanceof ANTLRv4FileRoot) {
86 | return candidate;
87 | }
88 | }
89 |
90 | return null;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/structview/ANTLRv4ItemPresentation.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.structview;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.navigation.ItemPresentation;
5 | import com.intellij.psi.PsiElement;
6 | import com.intellij.psi.util.PsiTreeUtil;
7 | import org.antlr.intellij.plugin.ANTLRv4FileRoot;
8 | import org.antlr.intellij.plugin.ANTLRv4TokenTypes;
9 | import org.antlr.intellij.plugin.parser.ANTLRv4Parser;
10 | import org.antlr.intellij.plugin.psi.GrammarElementRefNode;
11 | import org.antlr.intellij.plugin.psi.GrammarSpecNode;
12 | import org.antlr.intellij.plugin.psi.ModeSpecNode;
13 | import org.antlr.intellij.plugin.psi.MyPsiUtils;
14 | import org.jetbrains.annotations.Nullable;
15 |
16 | import javax.swing.*;
17 |
18 | public class ANTLRv4ItemPresentation implements ItemPresentation {
19 | protected final PsiElement element;
20 |
21 | protected ANTLRv4ItemPresentation(PsiElement element) {
22 | this.element = element;
23 | }
24 |
25 | @Nullable
26 | public String getLocationString() {
27 | return null;
28 | }
29 |
30 | @Override
31 | public String getPresentableText() {
32 | if (element instanceof ANTLRv4FileRoot) {
33 | GrammarSpecNode gnode = PsiTreeUtil.findChildOfType(element, GrammarSpecNode.class);
34 | PsiElement id = MyPsiUtils.findChildOfType(gnode, ANTLRv4TokenTypes.RULE_ELEMENT_TYPES.get(ANTLRv4Parser.RULE_identifier));
35 | if ( id!=null ) {
36 | return id.getText();
37 | }
38 | return "";
39 | }
40 | if ( element instanceof ModeSpecNode ) {
41 | ModeSpecNode mode = (ModeSpecNode) element;
42 | GrammarElementRefNode modeId = mode.getNameIdentifier();
43 | if ( modeId!=null ) {
44 | return modeId.getName();
45 | }
46 | return "";
47 | }
48 | ASTNode node = element.getNode();
49 | return node.getText();
50 | }
51 |
52 | @Nullable
53 | public Icon getIcon(boolean open) {
54 | return element.getIcon(0);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/structview/ANTLRv4StructureViewElement.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.structview;
2 |
3 | import com.intellij.ide.structureView.StructureViewTreeElement;
4 | import com.intellij.ide.util.treeView.smartTree.TreeElement;
5 | import com.intellij.navigation.ItemPresentation;
6 | import com.intellij.navigation.NavigationItem;
7 | import com.intellij.psi.PsiElement;
8 | import com.intellij.psi.PsiRecursiveElementVisitor;
9 | import com.intellij.psi.util.PsiTreeUtil;
10 | import org.antlr.intellij.plugin.ANTLRv4FileRoot;
11 | import org.antlr.intellij.plugin.psi.*;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 | import java.util.Objects;
17 |
18 | public class ANTLRv4StructureViewElement implements StructureViewTreeElement {
19 | private final PsiElement element;
20 |
21 | public ANTLRv4StructureViewElement(PsiElement element) {
22 | this.element = element;
23 | }
24 |
25 | @Override
26 | public Object getValue() {
27 | return element;
28 | }
29 |
30 | @Override
31 | public void navigate(boolean requestFocus) {
32 | if (element instanceof NavigationItem) {
33 | ((NavigationItem) element).navigate(requestFocus);
34 | }
35 | }
36 |
37 | @Override
38 | public boolean canNavigate() {
39 | return element instanceof NavigationItem &&
40 | ((NavigationItem)element).canNavigate();
41 | }
42 |
43 | @Override
44 | public boolean canNavigateToSource() {
45 | return element instanceof NavigationItem &&
46 | ((NavigationItem)element).canNavigateToSource();
47 | }
48 |
49 | @NotNull
50 | @Override
51 | public ItemPresentation getPresentation() {
52 | return new ANTLRv4ItemPresentation(element);
53 | }
54 |
55 | @NotNull
56 | @Override
57 | public TreeElement[] getChildren() {
58 | List treeElements = new ArrayList<>();
59 |
60 | if (element instanceof ANTLRv4FileRoot) {
61 | new PsiRecursiveElementVisitor() {
62 | @Override
63 | public void visitElement(PsiElement element) {
64 | if ( element instanceof ModeSpecNode ) {
65 | treeElements.add(new ANTLRv4StructureViewElement(element));
66 | return;
67 | }
68 |
69 | if ( element instanceof LexerRuleSpecNode || element instanceof ParserRuleSpecNode ) {
70 | PsiElement rule = PsiTreeUtil.findChildOfAnyType(element, LexerRuleRefNode.class, ParserRuleRefNode.class);
71 | if (rule != null) {
72 | treeElements.add(new ANTLRv4StructureViewElement(rule));
73 | }
74 | }
75 |
76 | super.visitElement(element);
77 | }
78 | }.visitElement(element);
79 | }
80 | else if ( element instanceof ModeSpecNode ) {
81 | LexerRuleSpecNode[] lexerRules = PsiTreeUtil.getChildrenOfType(element, LexerRuleSpecNode.class);
82 |
83 | if ( lexerRules != null ) {
84 | for ( LexerRuleSpecNode lexerRule : lexerRules ) {
85 | treeElements.add(new ANTLRv4StructureViewElement(PsiTreeUtil.findChildOfType(lexerRule, LexerRuleRefNode.class)));
86 | }
87 | }
88 | }
89 |
90 | return treeElements.toArray(new TreeElement[0]);
91 | }
92 |
93 | // probably not critical
94 | @Override
95 | public boolean equals(Object o) {
96 | if (this == o) return true;
97 | if (o == null || getClass() != o.getClass()) return false;
98 |
99 | ANTLRv4StructureViewElement that = (ANTLRv4StructureViewElement)o;
100 |
101 | return Objects.equals(element, that.element);
102 | }
103 |
104 | @Override
105 | public int hashCode() {
106 | return element != null ? element.hashCode() : 0;
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/structview/ANTLRv4StructureViewFactory.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.structview;
2 |
3 | import com.intellij.ide.structureView.StructureViewBuilder;
4 | import com.intellij.ide.structureView.StructureViewModel;
5 | import com.intellij.ide.structureView.StructureViewModelBase;
6 | import com.intellij.ide.structureView.StructureViewTreeElement;
7 | import com.intellij.ide.structureView.TreeBasedStructureViewBuilder;
8 | import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
9 | import com.intellij.lang.PsiStructureViewFactory;
10 | import com.intellij.openapi.editor.Editor;
11 | import com.intellij.openapi.vfs.VirtualFile;
12 | import com.intellij.psi.PsiElement;
13 | import com.intellij.psi.PsiFile;
14 | import org.antlr.intellij.plugin.ANTLRv4FileRoot;
15 | import org.jetbrains.annotations.NotNull;
16 | import org.jetbrains.annotations.Nullable;
17 |
18 | import java.util.Collection;
19 | import java.util.Collections;
20 |
21 | public class ANTLRv4StructureViewFactory implements PsiStructureViewFactory {
22 | /** fake a blank Treeview with a warning */
23 | public static class DummyViewTreeElement extends PsiTreeElementBase {
24 | public DummyViewTreeElement(PsiElement psiElement) {
25 | super(psiElement);
26 | }
27 |
28 | @NotNull
29 | @Override
30 | public Collection getChildrenBase() {
31 | return Collections.emptyList();
32 | }
33 |
34 | @Nullable
35 | @Override
36 | public String getPresentableText() {
37 | return "Sorry .g not supported (use .g4)";
38 | }
39 | }
40 |
41 | @Nullable
42 | @Override
43 | public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) {
44 | return new TreeBasedStructureViewBuilder() {
45 | @NotNull
46 | @Override
47 | public StructureViewModel createStructureViewModel(@Nullable Editor editor) {
48 | VirtualFile grammarFile = psiFile.getVirtualFile();
49 | if ( grammarFile==null || !grammarFile.getName().endsWith(".g4") ) {
50 | return new StructureViewModelBase(psiFile, new DummyViewTreeElement(psiFile));
51 | }
52 | return new ANTLRv4StructureViewModel((ANTLRv4FileRoot)psiFile);
53 | }
54 | };
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/structview/ANTLRv4StructureViewModel.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.structview;
2 |
3 | import com.intellij.icons.AllIcons;
4 | import com.intellij.ide.structureView.StructureViewModel;
5 | import com.intellij.ide.structureView.StructureViewModelBase;
6 | import com.intellij.ide.structureView.StructureViewTreeElement;
7 | import com.intellij.ide.util.treeView.smartTree.ActionPresentation;
8 | import com.intellij.ide.util.treeView.smartTree.ActionPresentationData;
9 | import com.intellij.ide.util.treeView.smartTree.Sorter;
10 | import com.intellij.ide.util.treeView.smartTree.SorterUtil;
11 | import com.intellij.psi.PsiFile;
12 | import org.antlr.intellij.plugin.ANTLRv4FileRoot;
13 | import org.antlr.intellij.plugin.psi.LexerRuleSpecNode;
14 | import org.antlr.intellij.plugin.psi.ParserRuleSpecNode;
15 | import org.jetbrains.annotations.NotNull;
16 |
17 | import java.util.Comparator;
18 |
19 | public class ANTLRv4StructureViewModel
20 | extends StructureViewModelBase
21 | // extends TextEditorBasedStructureViewModel
22 | implements StructureViewModel.ElementInfoProvider
23 | {
24 | private static final Sorter PARSER_LEXER_RULE_SORTER = new Sorter() {
25 | public Comparator> getComparator() {
26 | return (o1, o2) -> {
27 | String s1 = SorterUtil.getStringPresentation(o1);
28 | String s2 = SorterUtil.getStringPresentation(o2);
29 | // flip case of char 0 so it puts parser rules first
30 | if ( Character.isLowerCase(s1.charAt(0)) ) {
31 | s1 = Character.toUpperCase(s1.charAt(0))+s1.substring(1);
32 | }
33 | else {
34 | s1 = Character.toLowerCase(s1.charAt(0))+s1.substring(1);
35 | }
36 | if ( Character.isLowerCase(s2.charAt(0)) ) {
37 | s2 = Character.toUpperCase(s2.charAt(0))+s2.substring(1);
38 | }
39 | else {
40 | s2 = Character.toLowerCase(s2.charAt(0))+s2.substring(1);
41 | }
42 | return s1.compareTo(s2);
43 | };
44 | }
45 |
46 | public boolean isVisible() {
47 | return true;
48 | }
49 |
50 | @NotNull
51 | public ActionPresentation getPresentation() {
52 | // how it's described in sort by dropdown in nav window.
53 | String name = "Sort by rule type";
54 | return new ActionPresentationData(name, name, AllIcons.ObjectBrowser.SortByType);
55 | }
56 |
57 | @NotNull
58 | public String getName() {
59 | return "PARSER_LEXER_RULE_SORTER";
60 | }
61 | };
62 |
63 | ANTLRv4FileRoot rootElement;
64 |
65 | public ANTLRv4StructureViewModel(ANTLRv4FileRoot rootElement) {
66 | super(rootElement, new ANTLRv4StructureViewElement(rootElement));
67 | this.rootElement = rootElement;
68 | }
69 |
70 |
71 | @NotNull
72 | public Sorter[] getSorters() {
73 | return new Sorter[] {PARSER_LEXER_RULE_SORTER, Sorter.ALPHA_SORTER};
74 | }
75 |
76 | @Override
77 | protected PsiFile getPsiFile() {
78 | return rootElement;
79 | }
80 |
81 | @Override
82 | public boolean isAlwaysShowsPlus(StructureViewTreeElement element) {
83 | Object value = element.getValue();
84 | return value instanceof ANTLRv4FileRoot;
85 | }
86 |
87 | @Override
88 | public boolean isAlwaysLeaf(StructureViewTreeElement element) {
89 | Object value = element.getValue();
90 | return value instanceof ParserRuleSpecNode || value instanceof LexerRuleSpecNode;
91 | }
92 |
93 | /**
94 | Intellij: The implementation of StructureViewTreeElement.getChildren()
95 | needs to be matched by TextEditorBasedStructureViewModel.getSuitableClasses().
96 | The latter method returns an array of PsiElement-derived classes which can
97 | be shown as structure view elements, and is used to select the Structure
98 | View item matching the cursor position when the structure view is first
99 | opened or when the "Autoscroll from source" option is used.
100 | */
101 | @NotNull
102 | protected Class>[] getSuitableClasses() {
103 | return new Class[] {ANTLRv4FileRoot.class,
104 | LexerRuleSpecNode.class,
105 | ParserRuleSpecNode.class};
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/templates/ANTLRGenericContext.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.templates;
2 |
3 | import com.intellij.codeInsight.template.EverywhereContextType;
4 | import com.intellij.psi.PsiElement;
5 | import com.intellij.psi.PsiFile;
6 | import org.jetbrains.annotations.NotNull;
7 |
8 | public class ANTLRGenericContext extends ANTLRLiveTemplateContext {
9 | public ANTLRGenericContext() {
10 | super("ANTLR", "ANTLR", EverywhereContextType.class);
11 | }
12 |
13 | @Override
14 | protected boolean isInContext(@NotNull PsiFile file, @NotNull PsiElement element, int offset) {
15 | return false;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/templates/ANTLRLiveTemplateContext.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.templates;
2 |
3 | import com.intellij.codeInsight.template.TemplateContextType;
4 | import com.intellij.psi.PsiElement;
5 | import com.intellij.psi.PsiFile;
6 | import com.intellij.psi.util.PsiUtilBase;
7 | import org.antlr.intellij.plugin.ANTLRv4Language;
8 | import org.jetbrains.annotations.NonNls;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | public abstract class ANTLRLiveTemplateContext extends TemplateContextType {
13 | public ANTLRLiveTemplateContext(@NotNull @NonNls String id,
14 | @NotNull String presentableName,
15 | @Nullable Class extends TemplateContextType> baseContextType)
16 | {
17 | super(id, presentableName, baseContextType);
18 | }
19 |
20 | protected abstract boolean isInContext(@NotNull PsiFile file, @NotNull PsiElement element, int offset);
21 |
22 | @Override
23 | public boolean isInContext(@NotNull PsiFile file, int offset) {
24 | // offset is where cursor or insertion point is I guess
25 | if ( !PsiUtilBase.getLanguageAtOffset(file, offset).isKindOf(ANTLRv4Language.INSTANCE) ) {
26 | return false;
27 | }
28 | if ( offset==file.getTextLength() ) { // allow at EOF
29 | offset--;
30 | }
31 | PsiElement element = file.findElementAt(offset);
32 |
33 | if ( element==null ) {
34 | return false;
35 | }
36 |
37 | return isInContext(file, element, offset);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/templates/ANTLRLiveTemplatesProvider.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.templates;
2 |
3 | import com.intellij.codeInsight.template.impl.DefaultLiveTemplatesProvider;
4 | import org.jetbrains.annotations.Nullable;
5 |
6 | public class ANTLRLiveTemplatesProvider implements DefaultLiveTemplatesProvider {
7 | // make sure module shows liveTemplates as source dir or whatever dir holds "lexer"
8 | public static final String[] TEMPLATES = {"liveTemplates/lexer/user"};
9 |
10 | @Override
11 | public String[] getDefaultLiveTemplateFiles() {
12 | return TEMPLATES;
13 | }
14 |
15 | @Nullable
16 | @Override
17 | public String[] getHiddenLiveTemplateFiles() {
18 | return new String[0];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/templates/OutsideRuleContext.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.templates;
2 |
3 | import com.intellij.psi.PsiElement;
4 | import com.intellij.psi.PsiFile;
5 | import org.antlr.intellij.plugin.parser.ANTLRv4Parser;
6 | import org.antlr.intellij.plugin.parsing.ParsingUtils;
7 | import org.antlr.v4.runtime.CommonTokenStream;
8 | import org.antlr.v4.runtime.Token;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | public class OutsideRuleContext extends ANTLRLiveTemplateContext {
12 | public OutsideRuleContext() {
13 | super("ANTLR_OUTSIDE", "Outside rule", ANTLRGenericContext.class);
14 | }
15 |
16 | @Override
17 | public boolean isInContext(@NotNull PsiFile file, PsiElement element, int offset) {
18 | CommonTokenStream tokens = ParsingUtils.tokenizeANTLRGrammar(file.getText());
19 | Token tokenUnderCursor = ParsingUtils.getTokenUnderCursor(tokens, offset);
20 | if ( tokenUnderCursor==null ) {
21 | return false; // sometimes happens at the eof
22 | }
23 | int tokenIndex = tokenUnderCursor.getTokenIndex();
24 | Token nextRealToken = ParsingUtils.nextRealToken(tokens, tokenIndex);
25 | Token previousRealToken = ParsingUtils.previousRealToken(tokens, tokenIndex);
26 |
27 | if ( nextRealToken==null || previousRealToken==null ) {
28 | return false;
29 | }
30 |
31 | int previousRealTokenType = previousRealToken.getType();
32 | int nextRealTokenType = nextRealToken.getType();
33 |
34 | if ( previousRealTokenType== ANTLRv4Parser.BEGIN_ACTION ) {
35 | // make sure we're not in a rule; has to be @lexer::header {...} stuff
36 | Token prevPrevRealToken = ParsingUtils.previousRealToken(tokens, previousRealToken.getTokenIndex());
37 | if ( prevPrevRealToken==null ) {
38 | return false;
39 | }
40 | Token prevPrevPrevRealToken = ParsingUtils.previousRealToken(tokens, prevPrevRealToken.getTokenIndex());
41 | if ( prevPrevPrevRealToken==null ) {
42 | return false;
43 | }
44 | if ( prevPrevPrevRealToken.getType()!=ANTLRv4Parser.AT &&
45 | prevPrevPrevRealToken.getType()!=ANTLRv4Parser.COLONCOLON )
46 | {
47 | return false;
48 | }
49 | }
50 |
51 | boolean okBefore =
52 | previousRealTokenType == ANTLRv4Parser.RBRACE ||
53 | previousRealTokenType == ANTLRv4Parser.SEMI ||
54 | previousRealTokenType == ANTLRv4Parser.BEGIN_ACTION;
55 | boolean okAfter =
56 | nextRealTokenType == ANTLRv4Parser.TOKEN_REF ||
57 | nextRealTokenType == ANTLRv4Parser.RULE_REF ||
58 | nextRealTokenType == Token.EOF;
59 |
60 | return okBefore && okAfter;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/validation/CreateRuleFix.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.validation;
2 |
3 | import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
4 | import com.intellij.codeInsight.template.Template;
5 | import com.intellij.codeInsight.template.TemplateManager;
6 | import com.intellij.codeInsight.template.impl.TextExpression;
7 | import com.intellij.openapi.editor.Editor;
8 | import com.intellij.openapi.project.Project;
9 | import com.intellij.openapi.util.TextRange;
10 | import com.intellij.psi.PsiDocumentManager;
11 | import com.intellij.psi.PsiElement;
12 | import com.intellij.psi.PsiFile;
13 | import com.intellij.psi.util.PsiTreeUtil;
14 | import com.intellij.util.IncorrectOperationException;
15 | import org.antlr.intellij.plugin.psi.MyPsiUtils;
16 | import org.antlr.intellij.plugin.psi.RuleSpecNode;
17 | import org.jetbrains.annotations.Nls;
18 | import org.jetbrains.annotations.NotNull;
19 |
20 | import static org.antlr.intellij.plugin.ANTLRv4TokenTypes.getTokenElementType;
21 | import static org.antlr.intellij.plugin.parser.ANTLRv4Lexer.SEMI;
22 |
23 | /**
24 | * A quick fix to create missing rules.
25 | */
26 | public class CreateRuleFix extends BaseIntentionAction {
27 |
28 | private final TextRange textRange;
29 | private final String ruleName;
30 |
31 | public CreateRuleFix(TextRange textRange, PsiFile file) {
32 | this.textRange = textRange;
33 | ruleName = textRange.substring(file.getText());
34 | }
35 |
36 | @Nls(capitalization = Nls.Capitalization.Sentence)
37 | @NotNull
38 | @Override
39 | public String getFamilyName() {
40 | return "ANTLR4";
41 | }
42 |
43 | @Nls(capitalization = Nls.Capitalization.Sentence)
44 | @NotNull
45 | @Override
46 | public String getText() {
47 | return "Create rule '" + ruleName + "'";
48 | }
49 |
50 | @Override
51 | public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
52 | return true;
53 | }
54 |
55 | @Override
56 | public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
57 | String ruleName = editor.getDocument().getText(textRange);
58 |
59 | prepareEditor(project, editor, file);
60 |
61 | Template template = TemplateManager.getInstance(project).createTemplate("", "");
62 | template.addTextSegment(ruleName + ": ");
63 | template.addVariable("CONTENT", new TextExpression("' '"), true);
64 | template.addTextSegment(";");
65 |
66 | TemplateManager.getInstance(project).startTemplate(editor, template);
67 | }
68 |
69 | private void prepareEditor(@NotNull Project project, Editor editor, PsiFile file) {
70 | int insertionPoint = findInsertionPoint(editor, file);
71 | editor.getDocument().insertString(insertionPoint, "\n\n");
72 |
73 | PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
74 |
75 | editor.getCaretModel().moveToOffset(insertionPoint + 2);
76 | }
77 |
78 | private int findInsertionPoint(Editor editor, PsiFile file) {
79 | PsiElement atRange = file.findElementAt(textRange.getEndOffset());
80 | if ( atRange!=null ) {
81 | RuleSpecNode parentRule = PsiTreeUtil.getParentOfType(atRange, RuleSpecNode.class);
82 |
83 | if ( parentRule!=null ) {
84 | PsiElement semi = MyPsiUtils.findFirstChildOfType(parentRule, getTokenElementType(SEMI));
85 |
86 | if ( semi!=null ) {
87 | return semi.getTextOffset() + 1;
88 | }
89 | return parentRule.getTextRange().getEndOffset();
90 | }
91 | }
92 |
93 | return editor.getDocument().getLineEndOffset(editor.getDocument().getLineCount() - 1);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/validation/GrammarInfoMessage.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.validation;
2 |
3 | import org.antlr.runtime.Token;
4 | import org.antlr.v4.tool.GrammarSemanticsMessage;
5 |
6 | public class GrammarInfoMessage extends GrammarSemanticsMessage {
7 | public GrammarInfoMessage(String fileName, Token offendingToken, Object... args) {
8 | super(null, fileName, offendingToken, args);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/validation/GrammarIssue.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.validation;
2 |
3 | import org.antlr.runtime.Token;
4 | import org.antlr.v4.tool.ANTLRMessage;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | public class GrammarIssue {
10 | private String annotation;
11 | private final List offendingTokens = new ArrayList<>();
12 | private final ANTLRMessage msg;
13 |
14 | public GrammarIssue(ANTLRMessage msg) { this.msg = msg; }
15 |
16 | public String getAnnotation() {
17 | return annotation;
18 | }
19 |
20 | public void setAnnotation(String annotation) {
21 | this.annotation = annotation;
22 | }
23 |
24 | public List getOffendingTokens() {
25 | return offendingTokens;
26 | }
27 |
28 | public ANTLRMessage getMsg() {
29 | return msg;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/intellij/plugin/validation/GrammarIssuesCollectorToolListener.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.validation;
2 |
3 | import org.antlr.v4.tool.ANTLRMessage;
4 | import org.antlr.v4.tool.ANTLRToolListener;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | /** Track all issues found in a grammar for use by the external
10 | * annotator that puts up messages in grammar editor window.
11 | * The annotator looks for semantic errors not syntax errors,
12 | * which are indicated with error nodes in the PSI.
13 | */
14 | class GrammarIssuesCollectorToolListener implements ANTLRToolListener {
15 | private final List issues = new ArrayList<>();
16 |
17 | @Override
18 | public void info(String msg) {
19 | }
20 |
21 | @Override
22 | public void error(ANTLRMessage msg) {
23 | issues.add(new GrammarIssue(msg));
24 | }
25 |
26 | @Override
27 | public void warning(ANTLRMessage msg) {
28 | issues.add(new GrammarIssue(msg));
29 | }
30 |
31 | public List getIssues() {
32 | return issues;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/pluginIcon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/colorSchemes/ANTLRv4Darcula.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/resources/colorSchemes/ANTLRv4Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/antlr-icon.idraw:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/src/main/resources/icons/org/antlr/intellij/plugin/antlr-icon.idraw
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/antlr-tiny-icon.idraw:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/src/main/resources/icons/org/antlr/intellij/plugin/antlr-tiny-icon.idraw
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/antlr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/src/main/resources/icons/org/antlr/intellij/plugin/antlr.png
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/antlr.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/antlr@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/src/main/resources/icons/org/antlr/intellij/plugin/antlr@2x.png
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/lexer-rule.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/src/main/resources/icons/org/antlr/intellij/plugin/lexer-rule.png
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/lexer-rule.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/lexer-rule@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/src/main/resources/icons/org/antlr/intellij/plugin/lexer-rule@2x.png
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/mode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/src/main/resources/icons/org/antlr/intellij/plugin/mode.png
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/mode.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/mode@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/src/main/resources/icons/org/antlr/intellij/plugin/mode@2x.png
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/parser-rule.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/src/main/resources/icons/org/antlr/intellij/plugin/parser-rule.png
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/parser-rule.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/parser-rule@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/intellij-plugin-v4/46bc9a5d2bdd88d0d2144e5cd26f15ba8bf409d2/src/main/resources/icons/org/antlr/intellij/plugin/parser-rule@2x.png
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/toolWindowAntlr.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/icons/org/antlr/intellij/plugin/toolWindowAntlr_dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/liveTemplates/lexer/user.xml:
--------------------------------------------------------------------------------
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 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/src/main/resources/templates/org/antlr/intellij/plugin/gen/Java.stg:
--------------------------------------------------------------------------------
1 | tokenTypeFile(package, grammarName, tokenTypeClassName, tokenNames, keywords, ruleNames, commentTokens, whitespaceTokens) ::= <<
2 | package ;
3 |
4 | import com.intellij.psi.TokenType;
5 | import com.intellij.psi.tree.IElementType;
6 | import com.intellij.psi.tree.TokenSet;
7 | import org.antlr.v4.runtime.Token;
8 |
9 | import org.antlr.intellij.plugin.ANTLRv4TokenType;
10 |
11 | import static .Lexer.*;
12 |
13 | public class TokenTypes {
14 | public static IElementType BAD_CHARACTER = TokenType.BAD_CHARACTER;
15 | public static BAD_TOKEN = new ("BAD_TOKEN");
16 | public static EOF = new (Token.EOF, "EOF");
17 |
18 | = new (ANTLRv4Lexer., "");}; separator="\n">
19 |
20 | = new ("");}; separator="\n">
21 |
22 | public static TokenSet COMMENTS = TokenSet.create();
23 | public static TokenSet WHITESPACES = TokenSet.create(BAD_TOKEN, );
24 | public static TokenSet KEYWORDS = TokenSet.create();
25 |
26 | public static [] typeToIDEATokenType = new [+1];
27 | public static [] ruleToIDEATokenType = new [+1];
28 |
29 | static {
30 | Lexer.] = ;}; separator="\n">
31 | ] = ;}; separator="\n">
32 | }
33 | }
34 | >>
35 |
--------------------------------------------------------------------------------
/src/test/java/org/antlr/intellij/plugin/ANTLRv4ExternalAnnotatorTest.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.google.common.collect.Iterables;
4 | import com.intellij.lang.annotation.Annotation;
5 | import com.intellij.lang.annotation.HighlightSeverity;
6 | import com.intellij.psi.PsiFile;
7 | import org.antlr.intellij.plugin.validation.CreateRuleFix;
8 | import org.antlr.intellij.plugin.validation.AddTokenDefinitionFix;
9 | import org.antlr.intellij.plugin.validation.GrammarIssue;
10 | import org.antlr.v4.tool.ANTLRMessage;
11 | import org.antlr.v4.tool.ErrorType;
12 | import org.junit.Assert;
13 | import org.junit.Test;
14 | import org.mockito.Mockito;
15 |
16 | public class ANTLRv4ExternalAnnotatorTest {
17 |
18 | @Test
19 | public void shouldRegisterTokenDefinitionQuickFix() {
20 | // given:
21 | Annotation annotation = new Annotation(0,0, HighlightSeverity.WARNING, "msg", "tooltip");
22 |
23 | // when:
24 | ANTLRv4ExternalAnnotator.registerFixForAnnotation(annotation, new GrammarIssue(new ANTLRMessage(ErrorType.IMPLICIT_TOKEN_DEFINITION)), null);
25 |
26 | // then:
27 | Annotation.QuickFixInfo quickFix = Iterables.getOnlyElement(annotation.getQuickFixes());
28 | Assert.assertTrue(quickFix.quickFix instanceof AddTokenDefinitionFix);
29 | }
30 |
31 | @Test
32 | public void shouldRegisterCreateRuleQuickFix() {
33 | // given:
34 | Annotation annotation = new Annotation(0,0, HighlightSeverity.WARNING, "msg", "tooltip");
35 | PsiFile file = Mockito.mock(PsiFile.class);
36 | Mockito.when(file.getText()).thenReturn("sample text");
37 |
38 | // when:
39 | ANTLRv4ExternalAnnotator.registerFixForAnnotation(annotation, new GrammarIssue(new ANTLRMessage(ErrorType.UNDEFINED_RULE_REF)), file);
40 |
41 | // then:
42 | Annotation.QuickFixInfo quickFix = Iterables.getOnlyElement(annotation.getQuickFixes());
43 | Assert.assertTrue(quickFix.quickFix instanceof CreateRuleFix);
44 | }
45 | }
--------------------------------------------------------------------------------
/src/test/java/org/antlr/intellij/plugin/TestUtils.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin;
2 |
3 | import com.intellij.openapi.diagnostic.Attachment;
4 | import com.intellij.openapi.diagnostic.ExceptionWithAttachments;
5 | import com.intellij.util.ThrowableRunnable;
6 | import com.intellij.util.lang.CompoundRuntimeException;
7 |
8 | import java.io.PrintWriter;
9 | import java.io.StringWriter;
10 |
11 | public class TestUtils {
12 | public static void tearDownIgnoringObjectNotDisposedException(ThrowableRunnable delegate) throws Exception {
13 | try {
14 | delegate.run();
15 | } catch (RuntimeException e) {
16 | // We don't want to release the editor in the Tool Output tool window, so we ignore
17 | // ObjectNotDisposedExceptions related to this particular editor
18 | if (exceptionShouldBeIgnored(e)) {
19 | return;
20 | }
21 |
22 | throw e;
23 | }
24 | }
25 |
26 | private static boolean exceptionShouldBeIgnored(RuntimeException e) {
27 | if (e instanceof CompoundRuntimeException) {
28 | for (Throwable exception : ((CompoundRuntimeException) e).getExceptions()) {
29 | if (exception instanceof RuntimeException && exceptionShouldBeIgnored((RuntimeException) exception)) {
30 | return true;
31 | }
32 | }
33 | }
34 |
35 | if (e.getClass().getName().equals("com.intellij.openapi.util.TraceableDisposable$ObjectNotDisposedException")) {
36 | StringWriter stringWriter = new StringWriter();
37 | e.printStackTrace(new PrintWriter(stringWriter));
38 | String stack = stringWriter.toString();
39 |
40 | if (stackMatchesOurEditorCreation(stack)) {
41 | return true;
42 | }
43 | }
44 |
45 | if (e.getClass().getName().equals("com.intellij.openapi.util.TraceableDisposable$DisposalException")) {
46 | for (Attachment attachment : ((ExceptionWithAttachments) e).getAttachments()) {
47 | if (stackMatchesOurEditorCreation(attachment.getDisplayText())) {
48 | return true;
49 | }
50 | }
51 | }
52 |
53 | return false;
54 | }
55 |
56 | private static boolean stackMatchesOurEditorCreation(String stack) {
57 | return stack.contains("ANTLRv4PluginController.createToolWindows")
58 | || stack.contains("Issue559Test")
59 | || stack.contains("Issue540Test")
60 | || stack.contains("org.antlr.intellij.plugin.preview.InputPanel.createPreviewEditor");
61 | }
62 | }
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/test/java/org/antlr/intellij/plugin/actions/AnnotationIntentActionsFactoryTest.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.actions;
2 |
3 | import com.intellij.codeInsight.intention.IntentionAction;
4 | import com.intellij.openapi.util.TextRange;
5 | import org.antlr.intellij.plugin.psi.LexerRuleRefNode;
6 | import org.antlr.v4.tool.ErrorType;
7 | import org.junit.Test;
8 |
9 | import java.util.Optional;
10 |
11 | import static org.junit.Assert.assertFalse;
12 | import static org.mockito.Mockito.mock;
13 | import static org.mockito.Mockito.when;
14 |
15 | public class AnnotationIntentActionsFactoryTest {
16 | @Test
17 | public void shouldReturnEmptyOptionalForUnsupportedErrorType() {
18 | // when:
19 | LexerRuleRefNode lexerRuleRefNode = mock(LexerRuleRefNode.class);
20 | when(lexerRuleRefNode.isValid()).thenReturn(true);
21 | Optional quickFix = AnnotationIntentActionsFactory.getFix(new TextRange(0, 1), ErrorType.INTERNAL_ERROR, null);
22 |
23 | // then:
24 | assertFalse(quickFix.isPresent());
25 | }
26 | }
--------------------------------------------------------------------------------
/src/test/java/org/antlr/intellij/plugin/configdialogs/ANTLRv4GrammarPropertiesStoreTest.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.configdialogs;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | public class ANTLRv4GrammarPropertiesStoreTest {
7 |
8 | private static final String MY_GRAMMAR_PATH = "/home/grammars/test/MyGrammar.java";
9 |
10 | @Test
11 | public void shouldReturnPropertiesForExactFile() {
12 | // given:
13 | ANTLRv4GrammarPropertiesStore propertiesStore = new ANTLRv4GrammarPropertiesStore();
14 | propertiesStore.add(createGrammarProperties("/home/grammars/test/NotMyGrammar.java"));
15 | ANTLRv4GrammarProperties myGrammarProperties = createGrammarProperties(MY_GRAMMAR_PATH);
16 | propertiesStore.add(myGrammarProperties);
17 |
18 | // when:
19 | ANTLRv4GrammarProperties grammarProperties = propertiesStore.getGrammarProperties(MY_GRAMMAR_PATH);
20 |
21 | // then:
22 | Assert.assertSame(grammarProperties, myGrammarProperties);
23 | }
24 |
25 | @Test
26 | public void shouldReturnDefaultPropertiesIfNoneDefined() {
27 | // given:
28 | ANTLRv4GrammarPropertiesStore propertiesStore = new ANTLRv4GrammarPropertiesStore();
29 |
30 | // when:
31 | ANTLRv4GrammarProperties grammarProperties = propertiesStore.getGrammarProperties(MY_GRAMMAR_PATH);
32 |
33 | // then:
34 | Assert.assertSame(grammarProperties, ANTLRv4GrammarPropertiesStore.DEFAULT_GRAMMAR_PROPERTIES);
35 | }
36 |
37 | @Test
38 | public void shouldMatchPropertiesByWildcard() {
39 | // given:
40 | ANTLRv4GrammarPropertiesStore propertiesStore = new ANTLRv4GrammarPropertiesStore();
41 | propertiesStore.add(createGrammarProperties("*/main/*.java"));
42 | ANTLRv4GrammarProperties testGrammarProperties = createGrammarProperties("/home/*/test/*.java");
43 | propertiesStore.add(testGrammarProperties);
44 |
45 | // when:
46 | ANTLRv4GrammarProperties grammarProperties = propertiesStore.getGrammarProperties(MY_GRAMMAR_PATH);
47 |
48 | // then:
49 | Assert.assertSame(grammarProperties, testGrammarProperties);
50 | }
51 |
52 | @Test
53 | public void shouldPreferExactMatchOverWildcard() {
54 | // given:
55 | ANTLRv4GrammarPropertiesStore propertiesStore = new ANTLRv4GrammarPropertiesStore();
56 | propertiesStore.add(createGrammarProperties("/home/grammars/test/NotMyGrammar.java"));
57 | propertiesStore.add(createGrammarProperties("/home/*/test/*.java"));
58 | ANTLRv4GrammarProperties myGrammarProperties = createGrammarProperties(MY_GRAMMAR_PATH);
59 | propertiesStore.add(myGrammarProperties);
60 |
61 | // when:
62 | ANTLRv4GrammarProperties grammarProperties = propertiesStore.getGrammarProperties(MY_GRAMMAR_PATH);
63 |
64 | // then:
65 | Assert.assertSame(grammarProperties, myGrammarProperties);
66 | }
67 |
68 | private ANTLRv4GrammarProperties createGrammarProperties(String fileName) {
69 | ANTLRv4GrammarProperties antlRv4GrammarProperties = new ANTLRv4GrammarProperties();
70 | antlRv4GrammarProperties.fileName = fileName;
71 | return antlRv4GrammarProperties;
72 | }
73 | }
--------------------------------------------------------------------------------
/src/test/java/org/antlr/intellij/plugin/configdialogs/ANTLRv4GrammarPropertiesTest.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.configdialogs;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 |
7 | public class ANTLRv4GrammarPropertiesTest {
8 |
9 | private static final String QUAL_FILE_NAME = "file";
10 | private static final String FILE_VALUE = "fileValue";
11 | private static final String PROJECT_VALUE = "projectValue";
12 | private static final String DEFAULT_VALUE = "";
13 |
14 | private ANTLRv4GrammarPropertiesStore propertiesStore;
15 |
16 | @Before
17 | public void setUp() {
18 | propertiesStore = new ANTLRv4GrammarPropertiesStore();
19 | }
20 |
21 | @Test
22 | public void shouldGetPropertyFromFileSettingsWhenDefined() {
23 | // given:
24 | ANTLRv4GrammarProperties fileProps = new ANTLRv4GrammarProperties();
25 | fileProps.fileName = QUAL_FILE_NAME;
26 | fileProps.language = FILE_VALUE;
27 | propertiesStore.add(fileProps);
28 |
29 | ANTLRv4GrammarProperties projectProps = new ANTLRv4GrammarProperties();
30 | projectProps.fileName = "*";
31 | projectProps.language = PROJECT_VALUE;
32 | propertiesStore.add(projectProps);
33 |
34 | // when:
35 | String propertyValueForFile = propertiesStore.getGrammarProperties(QUAL_FILE_NAME).getLanguage();
36 |
37 | // then:
38 | Assert.assertEquals(FILE_VALUE, propertyValueForFile);
39 | }
40 |
41 | @Test
42 | public void shouldGetPropertyProjectSettingsValueWhenNotSetForFile() {
43 | // given:
44 | ANTLRv4GrammarProperties projectProps = new ANTLRv4GrammarProperties();
45 | projectProps.fileName = "*";
46 | projectProps.language = PROJECT_VALUE;
47 | propertiesStore.add(projectProps);
48 |
49 | // when:
50 | String propertyValueForFile = propertiesStore.getGrammarProperties(QUAL_FILE_NAME).getLanguage();
51 |
52 | // then:
53 | Assert.assertEquals(PROJECT_VALUE, propertyValueForFile);
54 | }
55 |
56 | @Test
57 | public void shouldGetPropertyDefaultValueWhenNotSetForFileNorProject() {
58 | // when:
59 | String propertyValueForFile = propertiesStore.getGrammarProperties(QUAL_FILE_NAME).getLanguage();
60 |
61 | // then:
62 | Assert.assertEquals(DEFAULT_VALUE, propertyValueForFile);
63 | }
64 |
65 | }
--------------------------------------------------------------------------------
/src/test/java/org/antlr/intellij/plugin/configdialogs/ConfigANTLRPerGrammarTest.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.configdialogs;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 | import org.mockito.Mockito;
7 |
8 | import static org.mockito.Mockito.doReturn;
9 | import static org.mockito.Mockito.when;
10 |
11 | public class ConfigANTLRPerGrammarTest {
12 |
13 | private static final String DEFAULT_OUTPUT_DIR = "DefaultOutputDir";
14 | private static final String DEFAULT_ENCODING = "DefaultEncoding";
15 | private static final String DEFAULT_LIBRARY = "DefaultLibrary";
16 | private static final String DEFAULT_PACKAGE = "DefaultPackage";
17 | private static final String DEFAULT_LANGUAGE = "DefaultLanguage";
18 |
19 | private ANTLRv4GrammarProperties originalProperties;
20 | private ConfigANTLRPerGrammar form;
21 |
22 | @Before
23 | public void setUp() {
24 | originalProperties = buildOriginalProperties();
25 | this.form = mockForm();
26 | }
27 |
28 | private ConfigANTLRPerGrammar mockForm() {
29 | ConfigANTLRPerGrammar form = Mockito.mock(ConfigANTLRPerGrammar.class, Mockito.CALLS_REAL_METHODS);
30 | doReturn(DEFAULT_OUTPUT_DIR).when(form).getOutputDirText();
31 | doReturn(DEFAULT_ENCODING).when(form).getFileEncodingText();
32 | doReturn(DEFAULT_LIBRARY).when(form).getLibDirText();
33 | doReturn(DEFAULT_PACKAGE).when(form).getPackageFieldText();
34 | doReturn(DEFAULT_LANGUAGE).when(form).getLanguageText();
35 | return form;
36 | }
37 |
38 | private ANTLRv4GrammarProperties buildOriginalProperties() {
39 | ANTLRv4GrammarProperties properties = new ANTLRv4GrammarProperties();
40 |
41 | properties.outputDir = DEFAULT_OUTPUT_DIR;
42 | properties.encoding = DEFAULT_ENCODING;
43 | properties.libDir = DEFAULT_LIBRARY;
44 | properties.pkg = DEFAULT_PACKAGE;
45 | properties.language = DEFAULT_LANGUAGE;
46 |
47 | return properties;
48 | }
49 |
50 | @Test
51 | public void shouldDetectModifiedOutputDirectory() {
52 | // given:
53 | when(form.getOutputDirText()).thenReturn("ModifiedOutputDir");
54 |
55 | // then:
56 | Assert.assertTrue(form.isModified(originalProperties));
57 | }
58 |
59 | @Test
60 | public void shouldDetectModifiedLibDirectory() {
61 | // given:
62 | when(form.getLibDirText()).thenReturn("ModifiedLibDir");
63 |
64 | // then:
65 | Assert.assertTrue(form.isModified(originalProperties));
66 | }
67 |
68 | @Test
69 | public void shouldDetectModifiedEncoding() {
70 | // given:
71 | when(form.getFileEncodingText()).thenReturn("ModifiedEncoding");
72 |
73 | // then:
74 | Assert.assertTrue(form.isModified(originalProperties));
75 | }
76 |
77 | @Test
78 | public void shouldDetectModifiedPackage() {
79 | // given:
80 | when(form.getFileEncodingText()).thenReturn("ModifiedPackage");
81 |
82 | // then:
83 | Assert.assertTrue(form.isModified(originalProperties));
84 | }
85 |
86 | @Test
87 | public void shouldDetectModifiedLanguage() {
88 | // given:
89 | when(form.getLanguageText()).thenReturn("ModifiedLanguage");
90 |
91 | // then:
92 | Assert.assertTrue(form.isModified(originalProperties));
93 | }
94 | }
--------------------------------------------------------------------------------
/src/test/java/org/antlr/intellij/plugin/editor/Issue559Test.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.editor;
2 |
3 | import com.intellij.openapi.editor.EditorFactory;
4 | import com.intellij.openapi.fileEditor.FileEditorManager;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.vfs.VirtualFile;
7 | import com.intellij.openapi.wm.ToolWindow;
8 | import com.intellij.testFramework.fixtures.BasePlatformTestCase;
9 | import org.antlr.intellij.plugin.ANTLRv4PluginController;
10 | import org.antlr.intellij.plugin.TestUtils;
11 | import org.antlr.intellij.plugin.preview.PreviewPanel;
12 | import org.junit.Test;
13 | import org.junit.Assert;
14 |
15 | public class Issue559Test extends BasePlatformTestCase {
16 |
17 | @Test
18 | public void test_shouldNotClosePanel() {
19 |
20 | Project project = getProject();
21 | VirtualFile[] vFiles = new VirtualFile[]{openFile("T1.g4"), openFile("T2.g4")};
22 |
23 | // Setup
24 | ANTLRv4PluginController controller = ANTLRv4PluginController.getInstance(project);
25 | PreviewPanel panel = controller.getPreviewPanel();
26 | ToolWindow previewWindow = controller.previewWindow = new MockToolWindow();
27 | FileEditorManager source = FileEditorManager.getInstance(project);
28 |
29 | // Close file 1
30 | controller.myFileEditorManagerAdapter.fileClosed(source, vFiles[0]);
31 | Assert.assertTrue(previewWindow.isVisible());
32 | Assert.assertTrue(panel.isEnabled());
33 |
34 | // Close file 2
35 | controller.myFileEditorManagerAdapter.fileClosed(source, vFiles[1]);
36 | Assert.assertFalse(previewWindow.isVisible());
37 | Assert.assertFalse(panel.isEnabled());
38 |
39 | }
40 |
41 | private VirtualFile openFile(String file) {
42 | VirtualFile vf = myFixture.configureByFile(file).getVirtualFile();
43 | myFixture.openFileInEditor(vf);
44 | return vf;
45 | }
46 |
47 | @Override
48 | protected String getTestDataPath() {
49 | return "src/test/resources/editor";
50 | }
51 |
52 | @Override
53 | protected void tearDown() throws Exception {
54 | TestUtils.tearDownIgnoringObjectNotDisposedException(() -> {
55 | EditorFactory.getInstance().releaseEditor(myFixture.getEditor());
56 | super.tearDown();
57 | });
58 | }
59 |
60 | }
--------------------------------------------------------------------------------
/src/test/java/org/antlr/intellij/plugin/folding/ANTLRv4FoldingBuilderTest.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.folding;
2 |
3 | import com.intellij.codeInsight.folding.CodeFoldingManager;
4 | import com.intellij.openapi.editor.Editor;
5 | import com.intellij.openapi.editor.FoldRegion;
6 | import com.intellij.testFramework.EditorTestUtil;
7 | import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
8 | import org.antlr.intellij.plugin.TestUtils;
9 |
10 | import java.lang.reflect.Method;
11 |
12 | public class ANTLRv4FoldingBuilderTest extends LightPlatformCodeInsightFixtureTestCase {
13 |
14 | public void test_folding_should_not_throw_on_incomplete_prequel() {
15 | // Given
16 | myFixture.configureByText("foo.g4", "grammar foo;\n @\n");
17 |
18 | // When
19 | buildInitialFoldings();
20 |
21 | // Then
22 | FoldRegion[] allFoldRegions = myFixture.getEditor().getFoldingModel().getAllFoldRegions();
23 | assertEquals(0, allFoldRegions.length);
24 | }
25 |
26 | public void test_should_not_fold_single_line() {
27 | // Given
28 | myFixture.configureByText("foo.g4", "grammar foo;\n @members { int i; }\n");
29 |
30 | // When
31 | buildInitialFoldings();
32 |
33 | // Then
34 | FoldRegion[] allFoldRegions = myFixture.getEditor().getFoldingModel().getAllFoldRegions();
35 | assertEquals(0, allFoldRegions.length);
36 | }
37 |
38 | @Override
39 | protected void tearDown() throws Exception {
40 | TestUtils.tearDownIgnoringObjectNotDisposedException(() -> super.tearDown());
41 | }
42 |
43 | private void buildInitialFoldings() {
44 | try {
45 | Method method = EditorTestUtil.class.getMethod("buildInitialFoldingsInBackground", Editor.class);
46 | method.invoke(null, myFixture.getEditor());
47 | } catch (ReflectiveOperationException e) {
48 | CodeFoldingManager.getInstance(getProject()).buildInitialFoldings(myFixture.getEditor());
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/src/test/java/org/antlr/intellij/plugin/parsing/Issue374Test.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.parsing;
2 |
3 | import junit.framework.TestCase;
4 | import org.antlr.intellij.adaptor.parser.SyntaxErrorListener;
5 | import org.antlr.intellij.plugin.parser.ANTLRv4Lexer;
6 | import org.antlr.intellij.plugin.parser.ANTLRv4Parser;
7 | import org.antlr.v4.runtime.CharStream;
8 | import org.antlr.v4.runtime.CharStreams;
9 | import org.antlr.v4.runtime.CommonTokenStream;
10 |
11 | public class Issue374Test extends TestCase {
12 |
13 | public void test_lexer_rule_should_be_parsed_after_header() {
14 | // Given
15 | String grammar = "grammar Sample;\n" +
16 | "@header {}\n" +
17 | "WS: [ \\t\\r\\n]+ -> skip ;";
18 |
19 | ANTLRv4Parser parser = createParser(grammar);
20 |
21 | SyntaxErrorListener listener = new SyntaxErrorListener();
22 | parser.addErrorListener(listener);
23 |
24 | // When
25 | parser.grammarSpec();
26 |
27 | // Then
28 | assertTrue(listener.getSyntaxErrors().isEmpty());
29 | }
30 |
31 | public void test_lexer_rule_should_be_parsed_after_options() {
32 | // Given
33 | String grammar = "grammar Sample;\n" +
34 | "options {" +
35 | " foo = {};" +
36 | "}\n" +
37 | "WS: [ \\t\\r\\n]+ -> skip ;";
38 |
39 | ANTLRv4Parser parser = createParser(grammar);
40 |
41 | SyntaxErrorListener listener = new SyntaxErrorListener();
42 | parser.addErrorListener(listener);
43 |
44 | // When
45 | parser.grammarSpec();
46 |
47 | // Then
48 | assertTrue(listener.getSyntaxErrors().isEmpty());
49 | }
50 |
51 | public void test_lexer_rule_should_be_parsed_after_tokens() {
52 | // Given
53 | String grammar = "grammar Sample;\n" +
54 | "tokens {" +
55 | " foo, bar" +
56 | "}\n" +
57 | "WS: [ \\t\\r\\n]+ -> skip ;";
58 |
59 | ANTLRv4Parser parser = createParser(grammar);
60 |
61 | SyntaxErrorListener listener = new SyntaxErrorListener();
62 | parser.addErrorListener(listener);
63 |
64 | // When
65 | parser.grammarSpec();
66 |
67 | // Then
68 | assertTrue(listener.getSyntaxErrors().isEmpty());
69 | }
70 |
71 | public void test_lexer_rule_should_be_parsed_after_channels() {
72 | // Given
73 | String grammar = "grammar Sample;\n" +
74 | "channels {" +
75 | " foo, bar" +
76 | "}\n" +
77 | "WS: [ \\t\\r\\n]+ -> skip ;";
78 |
79 | ANTLRv4Parser parser = createParser(grammar);
80 |
81 | SyntaxErrorListener listener = new SyntaxErrorListener();
82 | parser.addErrorListener(listener);
83 |
84 | // When
85 | parser.grammarSpec();
86 |
87 | // Then
88 | assertTrue(listener.getSyntaxErrors().isEmpty());
89 | }
90 |
91 | public void test_parser_rule_allows_options() {
92 | // Given
93 | String grammar = "parser grammar Sample;\n" +
94 | "options { key = value; }\n" +
95 | "entry\n" +
96 | "options { key = value; }\n" +
97 | ": 'text' EOF ;";
98 |
99 | ANTLRv4Parser parser = createParser(grammar);
100 |
101 | SyntaxErrorListener listener = new SyntaxErrorListener();
102 | ANTLRv4Lexer lexer = (ANTLRv4Lexer) parser.getInputStream().getTokenSource();
103 | lexer.addErrorListener(listener);
104 | parser.addErrorListener(listener);
105 |
106 | // When
107 | parser.grammarSpec();
108 |
109 | // Then
110 | assertTrue(listener.getSyntaxErrors().isEmpty());
111 | }
112 |
113 | private ANTLRv4Parser createParser(String grammar) {
114 | CharStream charStream = CharStreams.fromString(grammar);
115 | ANTLRv4Lexer lexer = new ANTLRv4Lexer(charStream);
116 | CommonTokenStream tokenStream = new CommonTokenStream(lexer);
117 |
118 | return new ANTLRv4Parser(tokenStream);
119 | }
120 | }
--------------------------------------------------------------------------------
/src/test/java/org/antlr/intellij/plugin/parsing/RunANTLROnGrammarFileTest.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.parsing;
2 |
3 | import com.intellij.openapi.vfs.VirtualFile;
4 | import com.intellij.testFramework.LightPlatformCodeInsightTestCase;
5 | import com.intellij.testFramework.VfsTestUtil;
6 | import org.antlr.intellij.plugin.TestUtils;
7 |
8 | import java.util.List;
9 |
10 | public class RunANTLROnGrammarFileTest extends LightPlatformCodeInsightTestCase {
11 |
12 | public void testPackageOptionShouldNotBeAddedIfDeclaredInHeader() {
13 | VirtualFile file = VfsTestUtil.createFile(getSourceRoot(), "mypkg/myGrammarWithHeader.g4",
14 | "grammar myGrammarWithHeader;\n@header { package com.foo.bar; }\nFOO: 'foo';");
15 | List options = RunANTLROnGrammarFile.getANTLRArgsAsList(getProject(), file);
16 |
17 | assertFalse(options.contains("-package"));
18 | }
19 |
20 | public void testPackageOptionShouldBeAddedIfNotDeclaredInHeader() {
21 | VirtualFile file = VfsTestUtil.createFile(getSourceRoot(), "mypkg/myGrammarWithoutHeader.g4",
22 | "grammar myGrammarWithoutHeader; FOO: 'foo';");
23 | List options = RunANTLROnGrammarFile.getANTLRArgsAsList(getProject(), file);
24 |
25 | assertTrue(options.contains("-package"));
26 | assertTrue(options.contains("mypkg"));
27 | }
28 |
29 | @Override
30 | protected void tearDown() throws Exception {
31 | TestUtils.tearDownIgnoringObjectNotDisposedException(() -> super.tearDown());
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/src/test/java/org/antlr/intellij/plugin/validation/AddTokenDefinitionFixTest.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.validation;
2 |
3 | import com.intellij.openapi.util.TextRange;
4 | import com.intellij.psi.PsiElement;
5 | import org.junit.Assert;
6 | import org.junit.Test;
7 | import org.mockito.Mockito;
8 |
9 | public class AddTokenDefinitionFixTest {
10 |
11 | private static final int TOKEN_EXPR_START_OFFSET = 10;
12 | private static final int ELEMENT_LENGTH = 20;
13 |
14 | @Test
15 | public void shouldCreateTokenDefinitionText() {
16 | Assert.assertEquals("M Y T O K E N", AddTokenDefinitionFix.buildTokenDefinitionExpressionText("MYTOKEN"));
17 | }
18 |
19 | @Test
20 | public void shouldCreateTokenDefinitionTextWhenHavingLowercase() {
21 | Assert.assertEquals("M Y T O K E N", AddTokenDefinitionFix.buildTokenDefinitionExpressionText("MYToken"));
22 | }
23 |
24 | @Test
25 | public void shouldCreateTokenDefinitionTextWhenHavingNonLetterLiterals() {
26 | Assert.assertEquals("M Y '_' T O K E N", AddTokenDefinitionFix.buildTokenDefinitionExpressionText("MY_TOKEN"));
27 | }
28 |
29 | @Test
30 | public void shouldGetRangeForReplacement() {
31 | // given:
32 | PsiElement element = Mockito.mock(PsiElement.class);
33 | Mockito.when(element.getTextLength()).thenReturn(ELEMENT_LENGTH);
34 |
35 | // when:
36 | TextRange range = AddTokenDefinitionFix.getRange(element, TOKEN_EXPR_START_OFFSET);
37 |
38 | // then:
39 | Assert.assertEquals(TOKEN_EXPR_START_OFFSET, range.getStartOffset());
40 | Assert.assertEquals(ELEMENT_LENGTH - 1, range.getEndOffset());
41 | }
42 | }
--------------------------------------------------------------------------------
/src/test/java/org/antlr/intellij/plugin/validation/CreateRuleFixTest.java:
--------------------------------------------------------------------------------
1 | package org.antlr.intellij.plugin.validation;
2 |
3 | import com.intellij.openapi.application.ApplicationManager;
4 | import com.intellij.openapi.util.TextRange;
5 | import com.intellij.testFramework.LightPlatformCodeInsightTestCase;
6 | import org.antlr.intellij.plugin.TestUtils;
7 |
8 | public class CreateRuleFixTest extends LightPlatformCodeInsightTestCase {
9 |
10 | public CreateRuleFixTest() {
11 | myTestDataPath = "src/test/resources/quickfixes/CreateRuleFix/";
12 | }
13 |
14 | public void testQuickFixDescriptionShouldShowRuleName() {
15 | // Given
16 | configureByFile("missingRule.g4");
17 | CreateRuleFix createRuleFix = new CreateRuleFix(TextRange.create(30, 37), getFile());
18 |
19 | // When
20 | String description = createRuleFix.getText();
21 |
22 | // Then
23 | assertEquals("Create rule 'newRule'", description);
24 | }
25 |
26 | public void testQuickFixShouldCreateRuleAfterCurrentRule() {
27 | // Given
28 | configureByFile("missingRule.g4");
29 | CreateRuleFix createRuleFix = new CreateRuleFix(TextRange.create(30, 37), getFile());
30 |
31 | // When
32 | ApplicationManager.getApplication().runWriteAction(
33 | () -> createRuleFix.invoke(getProject(), getEditor(), getFile())
34 | );
35 |
36 | // Then
37 | assertEquals(
38 | "grammar missingRule;\n\n" +
39 | "myRule: newRule;\n\n" +
40 | "newRule: ' ';",
41 | getFile().getText()
42 | );
43 | }
44 |
45 | @Override
46 | protected void tearDown() throws Exception {
47 | TestUtils.tearDownIgnoringObjectNotDisposedException(() -> super.tearDown());
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/test/resources/editor/T1.g4:
--------------------------------------------------------------------------------
1 | grammar T1;
2 | startRule : TEST EOF;
3 | TEST : 'TEST';
4 | WS : [ \t\f;]+ -> skip;
--------------------------------------------------------------------------------
/src/test/resources/editor/T2.g4:
--------------------------------------------------------------------------------
1 | grammar T2;
2 | startRule : TEST2 EOF;
3 | TEST2 : 'TEST2';
4 | WS : [ \t\f;]+ -> skip;
--------------------------------------------------------------------------------
/src/test/resources/quickfixes/CreateRuleFix/missingRule.g4:
--------------------------------------------------------------------------------
1 | grammar missingRule;
2 |
3 | myRule: newRule;
--------------------------------------------------------------------------------
/src/test/resources/references/FooLexer.g4:
--------------------------------------------------------------------------------
1 | lexer grammar FooLexer;
2 |
3 | tokens { STRING }
4 | channels { MYHIDDEN }
5 |
6 | TOKEN1: 'TOKEN1';
7 |
8 | fragment Fragment1
9 | : Fragment2
10 | | TOKEN1
11 | ;
12 |
13 | fragment Fragment2
14 | : 'FOO'
15 | | 'BAR'
16 | ;
17 |
18 | SINGLE : '\'' .*? '\'' -> type(STRING), channel(MYHIDDEN);
19 |
20 |
--------------------------------------------------------------------------------
/src/test/resources/references/FooParser.g4:
--------------------------------------------------------------------------------
1 | parser grammar FooParser;
2 |
3 | options {
4 | tokenVocab=FooLexer;
5 | }
6 |
7 | myrule: TOKEN1 Fragment1 MYHIDDEN STRING;
--------------------------------------------------------------------------------
/src/test/resources/references/FooParser2.g4:
--------------------------------------------------------------------------------
1 | parser grammar FooParser2;
2 |
3 | options {
4 | tokenVocab='FooLexer';
5 | }
6 |
7 | myrule: TOKEN1 Fragment1 MYHIDDEN STRING;
--------------------------------------------------------------------------------
/src/test/resources/references/Modes.g4:
--------------------------------------------------------------------------------
1 | lexer grammar Modes;
2 |
3 | tokens { T1 }
4 | channels { C1 }
5 |
6 | TOKEN1: 'token1' -> pushMode(MY_MODE);
7 |
8 | mode MY_MODE;
9 |
10 | TOKEN2: 'token2' -> type(TOKEN1);
11 |
12 | mode MY_OTHER_MODE;
13 |
14 | TOKEN3: 'token3' -> type(TOKEN2), type(T1), channel(C1), pushMode(MY_MODE);
--------------------------------------------------------------------------------
/src/test/resources/references/SimpleGrammar.g4:
--------------------------------------------------------------------------------
1 | grammar SimpleGrammar;
2 |
3 | TOKEN1: '$' DIGIT+ '$';
4 |
5 | DIGIT: [0-9]+;
6 |
7 | rule1: TOKEN1;
8 |
9 | rule2: DIGIT rule1 DIGIT;
10 |
--------------------------------------------------------------------------------
/src/test/resources/references/SimpleGrammar2.g4:
--------------------------------------------------------------------------------
1 | grammar SimpleGrammar;
2 |
3 | TOKEN1: '$' DIGIT+ '$';
4 |
5 | DIGIT: [0-9]+;
6 |
7 | rule1: TOKEN1;
8 |
9 | rule2: DIGIT rule1 DIGIT;
10 |
--------------------------------------------------------------------------------
/src/test/resources/references/imported.g4:
--------------------------------------------------------------------------------
1 | lexer grammar imported;
2 |
3 | import imported2, imported3;
4 |
5 | fragment Foo: 'foo';
--------------------------------------------------------------------------------
/src/test/resources/references/imported2.g4:
--------------------------------------------------------------------------------
1 | lexer grammar imported2;
2 |
3 | fragment Bar: 'bar';
4 |
--------------------------------------------------------------------------------
/src/test/resources/references/imported3.g4:
--------------------------------------------------------------------------------
1 | lexer grammar imported3;
2 |
3 | fragment Bar: 'bar';
4 |
5 | fragment Baz: 'baz';
6 |
--------------------------------------------------------------------------------
/src/test/resources/references/importing.g4:
--------------------------------------------------------------------------------
1 | lexer grammar importing;
2 |
3 | import imported;
4 |
5 | MY_FOO: Foo;
6 | MY_BAR: Bar;
7 | MY_BAZ: Baz;
8 |
--------------------------------------------------------------------------------