├── images
├── editor.png
├── java-highlight.png
└── template-data-language.png
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── src
├── main
│ ├── resources
│ │ ├── icons
│ │ │ ├── dict.png
│ │ │ ├── st.png
│ │ │ ├── st@2x.png
│ │ │ ├── string.png
│ │ │ ├── bigstring.png
│ │ │ ├── dict@2x.png
│ │ │ ├── string@2x.png
│ │ │ ├── bigstring-nonl.png
│ │ │ ├── bigstring@2x.png
│ │ │ ├── bigstring-nonl@2x.png
│ │ │ ├── string.svg
│ │ │ ├── dict.svg
│ │ │ ├── bigstring.svg
│ │ │ └── bigstring-nonl.svg
│ │ ├── META-INF
│ │ │ ├── st-intellilang.xml
│ │ │ ├── pluginIcon.svg
│ │ │ └── plugin.xml
│ │ ├── colorSchemes
│ │ │ ├── STGroupDarcula.xml
│ │ │ └── STGroupDefault.xml
│ │ └── st-java-injections.xml
│ ├── java
│ │ └── org
│ │ │ └── antlr
│ │ │ └── jetbrains
│ │ │ └── st4plugin
│ │ │ ├── STLanguage.java
│ │ │ ├── STGroupLanguage.java
│ │ │ ├── structview
│ │ │ ├── STGroupStructureViewFactory.java
│ │ │ ├── STGroupStructureViewBuilder.java
│ │ │ ├── STGroupRootItemPresentation.java
│ │ │ ├── STGroupItemPresentation.java
│ │ │ ├── STGroupTemplateDefTreeElement.java
│ │ │ ├── STGroupStructureViewModel.java
│ │ │ ├── STGroupRootTreeElement.java
│ │ │ ├── STGroupStructureViewTreeElement.java
│ │ │ └── STGroupTemplateDefItemPresentation.java
│ │ │ ├── Icons.java
│ │ │ ├── highlight
│ │ │ ├── STSyntaxHighlighterFactory.java
│ │ │ ├── STGroupSyntaxHighlighterFactory.java
│ │ │ ├── STGroupBraceMatcher.java
│ │ │ ├── STBraceMatcher.java
│ │ │ ├── STGroupSemanticHighlightAnnotator.java
│ │ │ ├── STEditorHighlighterProvider.java
│ │ │ ├── STSyntaxHighlighter.java
│ │ │ ├── STGroupSyntaxHighlighter.java
│ │ │ ├── STColorSettingsPage.java
│ │ │ └── STSemanticHighlightAnnotator.java
│ │ │ ├── psi
│ │ │ ├── TemplateContentElement.java
│ │ │ ├── STFile.java
│ │ │ ├── STGroupFile.java
│ │ │ ├── STTokenTypes.java
│ │ │ ├── STGroupTokenTypes.java
│ │ │ ├── TemplateContentLiteralTextEscaper.java
│ │ │ ├── STLanguageInjector.java
│ │ │ ├── STGroupParserDefinition.java
│ │ │ └── STParserDefinition.java
│ │ │ ├── STFileType.java
│ │ │ ├── STGroupFileType.java
│ │ │ ├── folding
│ │ │ ├── STFoldingBuilder.java
│ │ │ └── STGroupFoldingBuilder.java
│ │ │ └── parsing
│ │ │ └── LexerAdaptor.java
│ └── antlr
│ │ ├── STGParser.g4
│ │ ├── STGLexer.g4
│ │ ├── STLexer.g4
│ │ ├── STParser.g4
│ │ ├── LexBasic.g4
│ │ └── LexUnicode.g4
└── test
│ └── java
│ └── org
│ └── antlr
│ └── jetbrains
│ └── st4plugin
│ ├── psi
│ └── TemplateContentLiteralTextEscaperTest.java
│ └── structview
│ └── STGroupTemplateDefItemPresentationTest.java
├── .gitignore
├── gradle.properties
├── .editorconfig
├── LICENSE
├── .github
└── workflows
│ └── gradle.yml
├── README.md
├── contributors.txt
├── gradlew.bat
└── gradlew
/images/editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/images/editor.png
--------------------------------------------------------------------------------
/images/java-highlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/images/java-highlight.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/images/template-data-language.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/images/template-data-language.png
--------------------------------------------------------------------------------
/src/main/resources/icons/dict.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/src/main/resources/icons/dict.png
--------------------------------------------------------------------------------
/src/main/resources/icons/st.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/src/main/resources/icons/st.png
--------------------------------------------------------------------------------
/src/main/resources/icons/st@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/src/main/resources/icons/st@2x.png
--------------------------------------------------------------------------------
/src/main/resources/icons/string.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/src/main/resources/icons/string.png
--------------------------------------------------------------------------------
/src/main/resources/icons/bigstring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/src/main/resources/icons/bigstring.png
--------------------------------------------------------------------------------
/src/main/resources/icons/dict@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/src/main/resources/icons/dict@2x.png
--------------------------------------------------------------------------------
/src/main/resources/icons/string@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/src/main/resources/icons/string@2x.png
--------------------------------------------------------------------------------
/src/main/resources/icons/bigstring-nonl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/src/main/resources/icons/bigstring-nonl.png
--------------------------------------------------------------------------------
/src/main/resources/icons/bigstring@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/src/main/resources/icons/bigstring@2x.png
--------------------------------------------------------------------------------
/src/main/resources/icons/bigstring-nonl@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antlr/jetbrains-plugin-st4/HEAD/src/main/resources/icons/bigstring-nonl@2x.png
--------------------------------------------------------------------------------
/src/main/resources/META-INF/st-intellilang.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Mobile Tools for Java (J2ME)
4 | .mtj.tmp/
5 |
6 | # Package Files #
7 |
8 | *.war
9 | *.ear
10 |
11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
12 | hs_err_pid*
13 |
14 | /build
15 | /bin
16 | /.gradle
17 | /.idea/
18 | *.iml
19 | *.ipr
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | pluginVersion=0.10
2 |
3 | # e.g. IC-2016.3.3, IU-2018.2.5 etc
4 | # For a list of possible values, refer to the section 'com.jetbrains.intellij.idea' at https://www.jetbrains.com/intellij-repository/releases
5 | ideaVersion=2022.2.5
6 |
7 | # The version of ANTLR v4 that will be used to generate the parser
8 | antlr4Version=4.13.1
9 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/STLanguage.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin;
2 |
3 | import com.intellij.lang.Language;
4 |
5 | public class STLanguage extends Language {
6 |
7 | public static final STLanguage INSTANCE = new STLanguage();
8 |
9 | private STLanguage() {
10 | super("ST");
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/resources/colorSchemes/STGroupDarcula.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/resources/colorSchemes/STGroupDefault.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/STGroupLanguage.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin;
2 |
3 | import com.intellij.lang.Language;
4 |
5 | public class STGroupLanguage extends Language {
6 | public static final STGroupLanguage INSTANCE = new STGroupLanguage();
7 |
8 | private STGroupLanguage() {
9 | super("STGroup");
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/resources/icons/string.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 4
7 | indent_style = space
8 | insert_final_newline = true
9 | max_line_length = 240
10 | tab_width = 4
11 | trim_trailing_whitespace = true
12 | ij_continuation_indent_size = 8
13 | ij_formatter_off_tag = @formatter:off
14 | ij_formatter_on_tag = @formatter:on
15 | ij_formatter_tags_enabled = true
16 | ij_smart_tabs = false
17 | ij_wrap_on_typing = false
18 |
19 | ij_java_class_count_to_use_import_on_demand = 999
20 |
--------------------------------------------------------------------------------
/src/main/resources/icons/dict.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/icons/bigstring.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/structview/STGroupStructureViewFactory.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.structview;
2 |
3 | import com.intellij.ide.structureView.StructureViewBuilder;
4 | import com.intellij.lang.PsiStructureViewFactory;
5 | import com.intellij.psi.PsiFile;
6 | import org.jetbrains.annotations.NotNull;
7 | import org.jetbrains.annotations.Nullable;
8 |
9 | public class STGroupStructureViewFactory implements PsiStructureViewFactory {
10 | @Nullable
11 | @Override
12 | public StructureViewBuilder getStructureViewBuilder(@NotNull PsiFile psiFile) {
13 | return new STGroupStructureViewBuilder(psiFile);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/Icons.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin;
2 |
3 | import com.intellij.openapi.util.IconLoader;
4 |
5 | import javax.swing.*;
6 |
7 | public final class Icons {
8 | public static final Icon STG_FILE = IconLoader.getIcon("/icons/st.png", Icons.class);
9 | public static final Icon BIGSTRING = IconLoader.getIcon("/icons/bigstring.png", Icons.class);
10 | public static final Icon BIGSTRING_NONL = IconLoader.getIcon("/icons/bigstring-nonl.png", Icons.class);
11 | public static final Icon STRING = IconLoader.getIcon("/icons/string.png", Icons.class);
12 | public static final Icon DICT = IconLoader.getIcon("/icons/dict.png", Icons.class);
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/highlight/STSyntaxHighlighterFactory.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.highlight;
2 |
3 | import com.intellij.openapi.fileTypes.SyntaxHighlighter;
4 | import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.vfs.VirtualFile;
7 | import org.jetbrains.annotations.NotNull;
8 | import org.jetbrains.annotations.Nullable;
9 |
10 | public class STSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
11 | @NotNull
12 | @Override
13 | public SyntaxHighlighter getSyntaxHighlighter(@Nullable Project project, @Nullable VirtualFile virtualFile) {
14 | return new STSyntaxHighlighter();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/highlight/STGroupSyntaxHighlighterFactory.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.highlight;
2 |
3 | import com.intellij.openapi.fileTypes.SyntaxHighlighter;
4 | import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.vfs.VirtualFile;
7 | import org.jetbrains.annotations.NotNull;
8 | import org.jetbrains.annotations.Nullable;
9 |
10 | public class STGroupSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
11 |
12 | @NotNull
13 | @Override
14 | public SyntaxHighlighter getSyntaxHighlighter(@Nullable Project project, @Nullable VirtualFile virtualFile) {
15 | return new STGroupSyntaxHighlighter();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/structview/STGroupStructureViewBuilder.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.structview;
2 |
3 | import com.intellij.ide.structureView.StructureViewModel;
4 | import com.intellij.ide.structureView.TreeBasedStructureViewBuilder;
5 | import com.intellij.openapi.editor.Editor;
6 | import com.intellij.psi.PsiFile;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | public class STGroupStructureViewBuilder extends TreeBasedStructureViewBuilder {
10 |
11 | private final PsiFile psiFile;
12 |
13 | public STGroupStructureViewBuilder(PsiFile psiFile) {
14 | this.psiFile = psiFile;
15 | }
16 |
17 | @NotNull
18 | @Override
19 | public StructureViewModel createStructureViewModel(final Editor editor) {
20 | return new STGroupStructureViewModel(psiFile);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/pluginIcon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/structview/STGroupRootItemPresentation.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.structview;
2 |
3 | import com.intellij.navigation.ItemPresentation;
4 | import com.intellij.psi.PsiFile;
5 | import org.antlr.jetbrains.st4plugin.Icons;
6 | import org.jetbrains.annotations.Nullable;
7 |
8 | import javax.swing.*;
9 |
10 | public class STGroupRootItemPresentation implements ItemPresentation {
11 | private final PsiFile file;
12 |
13 | public STGroupRootItemPresentation(PsiFile file) {
14 | this.file = file;
15 | }
16 |
17 | @Nullable
18 | @Override
19 | public String getPresentableText() {
20 | return file.getName();
21 | }
22 |
23 | @Nullable
24 | @Override
25 | public String getLocationString() {
26 | return null;
27 | }
28 |
29 | @Nullable
30 | @Override
31 | public Icon getIcon(boolean unused) {
32 | return Icons.STG_FILE;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/resources/icons/bigstring-nonl.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/structview/STGroupItemPresentation.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.structview;
2 |
3 | import com.intellij.navigation.ItemPresentation;
4 | import org.antlr.jetbrains.st4plugin.Icons;
5 | import org.antlr.v4.runtime.tree.ParseTree;
6 | import org.jetbrains.annotations.Nullable;
7 |
8 | import javax.swing.*;
9 |
10 | public abstract class STGroupItemPresentation implements ItemPresentation {
11 | protected ParseTree node;
12 |
13 | public STGroupItemPresentation(ParseTree node) {
14 | this.node = node;
15 | }
16 |
17 | @Nullable
18 | @Override
19 | public Icon getIcon(boolean unused) {
20 | if (node.getParent() == null) return null;
21 | return Icons.STG_FILE;
22 | }
23 |
24 | @Nullable
25 | @Override
26 | public String getPresentableText() {
27 | return "n/a";
28 | }
29 |
30 | @Nullable
31 | @Override
32 | public String getLocationString() {
33 | return null;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/structview/STGroupTemplateDefTreeElement.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.structview;
2 |
3 | import com.intellij.extapi.psi.ASTWrapperPsiElement;
4 | import com.intellij.navigation.ItemPresentation;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | public class STGroupTemplateDefTreeElement extends STGroupStructureViewTreeElement {
8 | public STGroupTemplateDefTreeElement(ASTWrapperPsiElement psiElement) {
9 | super(psiElement);
10 | }
11 |
12 | @NotNull
13 | @Override
14 | public ItemPresentation getPresentation() {
15 | return new STGroupTemplateDefItemPresentation((ASTWrapperPsiElement) psiElement);
16 | }
17 |
18 | @Override
19 | public boolean canNavigate() {
20 | return true;
21 | }
22 |
23 | @Override
24 | public boolean canNavigateToSource() {
25 | return true;
26 | }
27 |
28 | @Override
29 | public void navigate(boolean requestFocus) {
30 | psiElement.navigate(requestFocus);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/psi/TemplateContentElement.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.psi;
2 |
3 | import com.intellij.extapi.psi.ASTWrapperPsiElement;
4 | import com.intellij.lang.ASTNode;
5 | import com.intellij.psi.LiteralTextEscaper;
6 | import com.intellij.psi.PsiLanguageInjectionHost;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | public class TemplateContentElement extends ASTWrapperPsiElement implements PsiLanguageInjectionHost {
10 |
11 | public TemplateContentElement(@NotNull ASTNode node) {
12 | super(node);
13 | }
14 |
15 | @Override
16 | public boolean isValidHost() {
17 | return true;
18 | }
19 |
20 | @Override
21 | public PsiLanguageInjectionHost updateText(@NotNull String text) {
22 | throw new UnsupportedOperationException();
23 | }
24 |
25 | @NotNull
26 | @Override
27 | public LiteralTextEscaper extends PsiLanguageInjectionHost> createLiteralTextEscaper() {
28 | return new TemplateContentLiteralTextEscaper(this);
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/psi/STFile.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.psi;
2 |
3 | import com.intellij.extapi.psi.PsiFileBase;
4 | import com.intellij.openapi.fileTypes.FileType;
5 | import com.intellij.psi.FileViewProvider;
6 | import org.antlr.jetbrains.st4plugin.Icons;
7 | import org.antlr.jetbrains.st4plugin.STFileType;
8 | import org.antlr.jetbrains.st4plugin.STLanguage;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | import javax.swing.*;
13 |
14 | public class STFile extends PsiFileBase {
15 |
16 | protected STFile(@NotNull FileViewProvider viewProvider) {
17 | super(viewProvider, STLanguage.INSTANCE);
18 | }
19 |
20 | @NotNull
21 | @Override
22 | public FileType getFileType() {
23 | return STFileType.INSTANCE;
24 | }
25 |
26 | @Override
27 | public String toString() {
28 | return "String Template file";
29 | }
30 |
31 | @Nullable
32 | @Override
33 | public Icon getIcon(int flags) {
34 | return Icons.STG_FILE;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/psi/STGroupFile.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.psi;
2 |
3 | import com.intellij.extapi.psi.PsiFileBase;
4 | import com.intellij.openapi.fileTypes.FileType;
5 | import com.intellij.psi.FileViewProvider;
6 | import org.antlr.jetbrains.st4plugin.Icons;
7 | import org.antlr.jetbrains.st4plugin.STGroupFileType;
8 | import org.antlr.jetbrains.st4plugin.STGroupLanguage;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | import javax.swing.*;
13 |
14 | public class STGroupFile extends PsiFileBase {
15 |
16 | protected STGroupFile(@NotNull FileViewProvider viewProvider) {
17 | super(viewProvider, STGroupLanguage.INSTANCE);
18 | }
19 |
20 | @NotNull
21 | @Override
22 | public FileType getFileType() {
23 | return STGroupFileType.INSTANCE;
24 | }
25 |
26 | @Override
27 | public String toString() {
28 | return "String Template group file";
29 | }
30 |
31 | @Nullable
32 | @Override
33 | public Icon getIcon(int flags) {
34 | return Icons.STG_FILE;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/STFileType.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin;
2 |
3 | import com.intellij.openapi.fileTypes.LanguageFileType;
4 | import com.intellij.openapi.fileTypes.TemplateLanguageFileType;
5 | import org.jetbrains.annotations.NotNull;
6 | import org.jetbrains.annotations.Nullable;
7 |
8 | import javax.swing.*;
9 |
10 | public class STFileType extends LanguageFileType implements TemplateLanguageFileType {
11 | public static final STFileType INSTANCE = new STFileType();
12 |
13 | protected STFileType() {
14 | super(STLanguage.INSTANCE);
15 | }
16 |
17 | @NotNull
18 | @Override
19 | public String getName() {
20 | return "StringTemplate v4 template file";
21 | }
22 |
23 | @NotNull
24 | @Override
25 | public String getDescription() {
26 | return "StringTemplate v4 template file";
27 | }
28 |
29 | @NotNull
30 | @Override
31 | public String getDefaultExtension() {
32 | return "st";
33 | }
34 |
35 | @Nullable
36 | @Override
37 | public Icon getIcon() {
38 | return Icons.STG_FILE;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/STGroupFileType.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin;
2 |
3 | import com.intellij.openapi.fileTypes.LanguageFileType;
4 | import com.intellij.openapi.fileTypes.TemplateLanguageFileType;
5 | import org.jetbrains.annotations.NotNull;
6 | import org.jetbrains.annotations.Nullable;
7 |
8 | import javax.swing.*;
9 |
10 | public class STGroupFileType extends LanguageFileType implements TemplateLanguageFileType {
11 | public static final STGroupFileType INSTANCE = new STGroupFileType();
12 |
13 | protected STGroupFileType() {
14 | super(STGroupLanguage.INSTANCE);
15 | }
16 |
17 | @NotNull
18 | @Override
19 | public String getName() {
20 | return "StringTemplate v4 template group file";
21 | }
22 |
23 | @NotNull
24 | @Override
25 | public String getDescription() {
26 | return "StringTemplate v4 template group file";
27 | }
28 |
29 | @NotNull
30 | @Override
31 | public String getDefaultExtension() {
32 | return "stg";
33 | }
34 |
35 | @Nullable
36 | @Override
37 | public Icon getIcon() {
38 | return Icons.STG_FILE;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/structview/STGroupStructureViewModel.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.structview;
2 |
3 | import com.intellij.ide.structureView.StructureViewModel;
4 | import com.intellij.ide.structureView.StructureViewModelBase;
5 | import com.intellij.ide.structureView.StructureViewTreeElement;
6 | import com.intellij.ide.util.treeView.smartTree.Sorter;
7 | import com.intellij.psi.PsiFile;
8 | import org.jetbrains.annotations.NotNull;
9 |
10 | public class STGroupStructureViewModel extends StructureViewModelBase implements
11 | StructureViewModel.ElementInfoProvider {
12 |
13 | public STGroupStructureViewModel(PsiFile psiFile) {
14 | super(psiFile, new STGroupRootTreeElement(psiFile));
15 | }
16 |
17 | @NotNull
18 | @Override
19 | public Sorter[] getSorters() {
20 | return new Sorter[]{Sorter.ALPHA_SORTER};
21 | }
22 |
23 | @Override
24 | public boolean isAlwaysShowsPlus(StructureViewTreeElement element) {
25 | return false;
26 | }
27 |
28 | @Override
29 | public boolean isAlwaysLeaf(StructureViewTreeElement element) {
30 | return element instanceof STGroupTemplateDefTreeElement;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/highlight/STGroupBraceMatcher.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.highlight;
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.antlr.jetbrains.st4plugin.parsing.STGLexer;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.jetbrains.annotations.Nullable;
10 |
11 | import static org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes.getTokenElementType;
12 |
13 | public class STGroupBraceMatcher implements PairedBraceMatcher {
14 |
15 | private static final BracePair[] PAIRS = {
16 | new BracePair(getTokenElementType(STGLexer.LBRACK), getTokenElementType(STGLexer.RBRACK), true),
17 | new BracePair(getTokenElementType(STGLexer.LPAREN), getTokenElementType(STGLexer.RPAREN), true)
18 | };
19 |
20 | @NotNull
21 | @Override
22 | public BracePair[] getPairs() {
23 | return PAIRS;
24 | }
25 |
26 | @Override
27 | public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType lbraceType, @Nullable IElementType contextType) {
28 | return true;
29 | }
30 |
31 | @Override
32 | public int getCodeConstructStart(PsiFile file, int openingBraceOffset) {
33 | return openingBraceOffset;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015, Terence Parr
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, 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,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
--------------------------------------------------------------------------------
/.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 | matrix:
15 | env:
16 | # see https://www.jetbrains.com/idea/download/previous.html
17 | # and https://www.jetbrains.com/intellij-repository/snapshots/
18 | - IDEA_VERSION: IC-2022.2.5
19 | - IDEA_VERSION: IC-2022.3.1
20 | - IDEA_VERSION: IC-2023.2.2
21 | - IDEA_VERSION: IU-LATEST-EAP-SNAPSHOT
22 |
23 | steps:
24 | - uses: actions/checkout@v2
25 | - name: Set up JDK 17
26 | uses: actions/setup-java@v1
27 | with:
28 | java-version: 17
29 | - name: Build with Gradle
30 | run: |
31 | ./gradlew -PideaVersion=${IDEA_VERSION} buildPlugin
32 | echo "DIST_FILE=$(find build/distributions/ -name 'jetbrains-plugin-st4-*.zip' -exec basename {} .zip \;)" >> $GITHUB_ENV
33 | env: ${{ matrix.env }}
34 | - name: Archive distribution artifact
35 | uses: actions/upload-artifact@v2
36 | with:
37 | name: ${{env.DIST_FILE}}
38 | path: build/distributions/jetbrains-plugin-st4-*.zip
39 | if: matrix.env.IDEA_VERSION == 'IC-2022.2.5'
40 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # IntelliJ Plugin for StringTemplate v4
2 | [](https://github.com/antlr/jetbrains-plugin-st4/actions) [](https://plugins.jetbrains.com/plugin/8041-stringtemplate-v4-plugin) 
3 |
4 | A plugin that adds support for StringTemplate v4 to [IntelliJ](https://www.jetbrains.com/idea/)-based IDEs (version 15.x and later).
5 |
6 | It understands `.stg` and `.st` files. For example,
7 |
8 |
9 |
10 | See the [plugin page](https://plugins.jetbrains.com/plugin/8041?pr=) for more information.
11 |
12 | # Highlighting the target language
13 |
14 | You can configure `Template Data Languages` to make the editor highlight the content around StringTemplate tags.
15 | For example, if your template is used to generate Java code, you can go to `File | Settings | Languages & Frameworks | Template Data Languages`
16 | and configure which language to highlight:
17 |
18 |
19 |
20 | The editor will now highlight Java parts around ST tags:
21 |
22 |
23 |
24 | # Building and contributing
25 |
26 | To build the plugin:
27 | `gradlew buildPlugin`
28 |
29 | To run the plugin:
30 | `gradlew runIde`
31 |
32 | When submitting a pull request, make sure your name is in the `contributors.txt` file.
33 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/highlight/STBraceMatcher.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.highlight;
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.antlr.jetbrains.st4plugin.parsing.STLexer;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.jetbrains.annotations.Nullable;
10 |
11 | import static org.antlr.jetbrains.st4plugin.psi.STTokenTypes.getTokenElementType;
12 |
13 | public class STBraceMatcher implements PairedBraceMatcher {
14 |
15 | private static final BracePair[] PAIRS = {
16 | new BracePair(getTokenElementType(STLexer.LBRACK), getTokenElementType(STLexer.RBRACK), true),
17 | new BracePair(getTokenElementType(STLexer.LDELIM), getTokenElementType(STLexer.RDELIM), true),
18 | new BracePair(getTokenElementType(STLexer.LBRACE), getTokenElementType(STLexer.RBRACE), true),
19 | new BracePair(getTokenElementType(STLexer.LPAREN), getTokenElementType(STLexer.RPAREN), true)
20 | };
21 |
22 | @NotNull
23 | @Override
24 | public BracePair[] getPairs() {
25 | return PAIRS;
26 | }
27 |
28 | @Override
29 | public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType lbraceType, @Nullable IElementType contextType) {
30 | return true;
31 | }
32 |
33 | @Override
34 | public int getCodeConstructStart(PsiFile file, int openingBraceOffset) {
35 | return openingBraceOffset;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/highlight/STGroupSemanticHighlightAnnotator.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.highlight;
2 |
3 | import com.intellij.lang.annotation.AnnotationHolder;
4 | import com.intellij.lang.annotation.Annotator;
5 | import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
6 | import com.intellij.openapi.editor.colors.TextAttributesKey;
7 | import com.intellij.psi.PsiElement;
8 | import org.antlr.jetbrains.st4plugin.parsing.STGLexer;
9 | import org.antlr.jetbrains.st4plugin.parsing.STGParser;
10 | import org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | import static com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey;
14 | import static org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes.getRuleElementType;
15 |
16 | /**
17 | * Highlights a group's formal args differently from its name.
18 | */
19 | public class STGroupSemanticHighlightAnnotator implements Annotator {
20 |
21 | public static final TextAttributesKey TEMPLATE_PARAM = createTextAttributesKey("STGroup_TEMPLATE_PARAM", DefaultLanguageHighlighterColors.INSTANCE_FIELD);
22 |
23 | @Override
24 | public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
25 | if (element.getNode().getElementType() == STGroupTokenTypes.getTokenElementType(STGLexer.ID)) {
26 | if (element.getParent().getNode().getElementType() == getRuleElementType(STGParser.RULE_formalArg)) {
27 | holder.createInfoAnnotation(element, null)
28 | .setTextAttributes(TEMPLATE_PARAM);
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/psi/STTokenTypes.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.psi;
2 |
3 | import com.intellij.util.LazyInitializer;
4 | import org.antlr.intellij.adaptor.lexer.PSIElementTypeFactory;
5 | import org.antlr.intellij.adaptor.lexer.RuleIElementType;
6 | import org.antlr.intellij.adaptor.lexer.TokenIElementType;
7 | import org.antlr.jetbrains.st4plugin.STLanguage;
8 | import org.antlr.jetbrains.st4plugin.parsing.STLexer;
9 | import org.antlr.jetbrains.st4plugin.parsing.STParser;
10 | import org.intellij.lang.annotations.MagicConstant;
11 |
12 | import java.util.List;
13 |
14 | public final class STTokenTypes {
15 |
16 | private static final LazyInitializer.LazyValue> TOKEN_ELEMENT_TYPES = LazyInitializer.create(() -> {
17 | initIElementTypes();
18 | return PSIElementTypeFactory.getTokenIElementTypes(STLanguage.INSTANCE);
19 | });
20 | private static final LazyInitializer.LazyValue> RULE_ELEMENT_TYPES = LazyInitializer.create(() -> {
21 | initIElementTypes();
22 | return PSIElementTypeFactory.getRuleIElementTypes(STLanguage.INSTANCE);
23 | });
24 |
25 | public static void initIElementTypes() {
26 | PSIElementTypeFactory.defineLanguageIElementTypes(
27 | STLanguage.INSTANCE,
28 | STLexer.tokenNames,
29 | STParser.ruleNames
30 | );
31 | }
32 |
33 | public static RuleIElementType getRuleElementType(@MagicConstant(valuesFromClass = STParser.class) int ruleIndex) {
34 | return RULE_ELEMENT_TYPES.get().get(ruleIndex);
35 | }
36 |
37 | public static TokenIElementType getTokenElementType(@MagicConstant(valuesFromClass = STLexer.class) int ruleIndex) {
38 | return TOKEN_ELEMENT_TYPES.get().get(ruleIndex);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/psi/STGroupTokenTypes.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.psi;
2 |
3 | import com.intellij.util.LazyInitializer;
4 | import org.antlr.intellij.adaptor.lexer.PSIElementTypeFactory;
5 | import org.antlr.intellij.adaptor.lexer.RuleIElementType;
6 | import org.antlr.intellij.adaptor.lexer.TokenIElementType;
7 | import org.antlr.jetbrains.st4plugin.STGroupLanguage;
8 | import org.antlr.jetbrains.st4plugin.parsing.STGLexer;
9 | import org.antlr.jetbrains.st4plugin.parsing.STGParser;
10 | import org.intellij.lang.annotations.MagicConstant;
11 |
12 | import java.util.List;
13 |
14 | public final class STGroupTokenTypes {
15 |
16 | private static final LazyInitializer.LazyValue> TOKEN_ELEMENT_TYPES = LazyInitializer.create(() -> {
17 | initIElementTypes();
18 | return PSIElementTypeFactory.getTokenIElementTypes(STGroupLanguage.INSTANCE);
19 | });
20 | private static final LazyInitializer.LazyValue> RULE_ELEMENT_TYPES = LazyInitializer.create(() -> {
21 | initIElementTypes();
22 | return PSIElementTypeFactory.getRuleIElementTypes(STGroupLanguage.INSTANCE);
23 | });
24 |
25 | public static void initIElementTypes() {
26 | PSIElementTypeFactory.defineLanguageIElementTypes(
27 | STGroupLanguage.INSTANCE,
28 | STGLexer.tokenNames,
29 | STGParser.ruleNames
30 | );
31 | }
32 |
33 | public static RuleIElementType getRuleElementType(@MagicConstant(valuesFromClass = STGParser.class) int ruleIndex) {
34 | return RULE_ELEMENT_TYPES.get().get(ruleIndex);
35 | }
36 |
37 | public static TokenIElementType getTokenElementType(@MagicConstant(valuesFromClass = STGLexer.class) int ruleIndex) {
38 | return TOKEN_ELEMENT_TYPES.get().get(ruleIndex);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/structview/STGroupRootTreeElement.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.structview;
2 |
3 | import com.intellij.extapi.psi.ASTWrapperPsiElement;
4 | import com.intellij.ide.util.treeView.smartTree.TreeElement;
5 | import com.intellij.navigation.ItemPresentation;
6 | import com.intellij.psi.PsiElement;
7 | import com.intellij.psi.PsiFile;
8 | import org.antlr.jetbrains.st4plugin.parsing.STGParser;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | import java.util.Arrays;
12 |
13 | import static org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes.getRuleElementType;
14 |
15 | public class STGroupRootTreeElement extends STGroupStructureViewTreeElement {
16 |
17 | public STGroupRootTreeElement(PsiFile psiFile) {
18 | super(psiFile);
19 | }
20 |
21 | @NotNull
22 | @Override
23 | public ItemPresentation getPresentation() {
24 | return new STGroupRootItemPresentation((PsiFile) psiElement);
25 | }
26 |
27 | @NotNull
28 | @Override
29 | public TreeElement[] getChildren() {
30 | return Arrays.stream(this.psiElement.getChildren())
31 | .filter(e -> e.getNode().getElementType() == getRuleElementType(STGParser.RULE_group))
32 | .findFirst()
33 | .map(group -> Arrays.stream(group.getChildren())
34 | .filter(this::shouldShowInStructureView)
35 | .map(e -> new STGroupTemplateDefTreeElement((ASTWrapperPsiElement) e))
36 | .toArray(TreeElement[]::new))
37 | .orElse(TreeElement.EMPTY_ARRAY);
38 | }
39 |
40 | private boolean shouldShowInStructureView(@NotNull PsiElement child) {
41 | return child.getNode().getElementType() == getRuleElementType(STGParser.RULE_template)
42 | || child.getNode().getElementType() == getRuleElementType(STGParser.RULE_dict);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/structview/STGroupStructureViewTreeElement.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.structview;
2 |
3 | import com.intellij.ide.structureView.StructureViewTreeElement;
4 | import com.intellij.ide.util.treeView.smartTree.SortableTreeElement;
5 | import com.intellij.ide.util.treeView.smartTree.TreeElement;
6 | import com.intellij.navigation.ItemPresentation;
7 | import com.intellij.psi.NavigatablePsiElement;
8 | import org.antlr.jetbrains.st4plugin.Icons;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | import javax.swing.*;
13 |
14 | public abstract class STGroupStructureViewTreeElement
15 | implements StructureViewTreeElement, ItemPresentation, SortableTreeElement {
16 |
17 | protected NavigatablePsiElement psiElement;
18 |
19 | public STGroupStructureViewTreeElement(NavigatablePsiElement psiElement) {
20 | this.psiElement = psiElement;
21 | }
22 |
23 | @Nullable
24 | @Override
25 | public Icon getIcon(boolean unused) {
26 | return Icons.STG_FILE;
27 | }
28 |
29 | @Nullable
30 | @Override
31 | public String getPresentableText() {
32 | return "TODO";
33 | }
34 |
35 | @Override
36 | public void navigate(boolean requestFocus) {
37 | psiElement.navigate(requestFocus);
38 | }
39 |
40 | @Override
41 | public boolean canNavigate() {
42 | return true;
43 | }
44 |
45 | @Override
46 | public boolean canNavigateToSource() {
47 | return false;
48 | }
49 |
50 | @Nullable
51 | @Override
52 | public String getLocationString() {
53 | return null;
54 | }
55 |
56 | @Override
57 | public NavigatablePsiElement getValue() {
58 | return psiElement;
59 | }
60 |
61 | @NotNull
62 | @Override
63 | public String getAlphaSortKey() {
64 | return getPresentation().getPresentableText();
65 | }
66 |
67 | @NotNull
68 | @Override
69 | public TreeElement[] getChildren() {
70 | return EMPTY_ARRAY;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/highlight/STEditorHighlighterProvider.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.highlight;
2 |
3 | import com.intellij.lang.Language;
4 | import com.intellij.openapi.editor.colors.EditorColorsScheme;
5 | import com.intellij.openapi.editor.ex.util.LayerDescriptor;
6 | import com.intellij.openapi.editor.ex.util.LayeredLexerEditorHighlighter;
7 | import com.intellij.openapi.editor.highlighter.EditorHighlighter;
8 | import com.intellij.openapi.fileTypes.EditorHighlighterProvider;
9 | import com.intellij.openapi.fileTypes.FileType;
10 | import com.intellij.openapi.fileTypes.SyntaxHighlighter;
11 | import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
12 | import com.intellij.openapi.project.Project;
13 | import com.intellij.openapi.vfs.VirtualFile;
14 | import com.intellij.psi.templateLanguages.TemplateDataLanguageMappings;
15 | import org.antlr.jetbrains.st4plugin.STGroupFileType;
16 | import org.antlr.jetbrains.st4plugin.parsing.STLexer;
17 | import org.jetbrains.annotations.NotNull;
18 | import org.jetbrains.annotations.Nullable;
19 |
20 | import static org.antlr.jetbrains.st4plugin.psi.STTokenTypes.getTokenElementType;
21 |
22 | public class STEditorHighlighterProvider implements EditorHighlighterProvider {
23 |
24 | @Override
25 | public EditorHighlighter getEditorHighlighter(@Nullable Project project, @NotNull FileType fileType, @Nullable VirtualFile virtualFile, @NotNull EditorColorsScheme colors) {
26 | return new STEditorHighlighter(virtualFile, project, fileType, colors);
27 | }
28 | }
29 |
30 | /**
31 | * Highlights the "outer language", i.e. the target language.
32 | * The target language can be configured in the Template Data Languages settings.
33 | */
34 | class STEditorHighlighter extends LayeredLexerEditorHighlighter {
35 |
36 | public STEditorHighlighter(@Nullable VirtualFile virtualFile,
37 | @Nullable Project project,
38 | @NotNull FileType fileType,
39 | @NotNull EditorColorsScheme scheme) {
40 | super(fileType == STGroupFileType.INSTANCE ? new STGroupSyntaxHighlighter() : new STSyntaxHighlighter(), scheme);
41 |
42 | if (project != null && virtualFile != null) {
43 | Language language = TemplateDataLanguageMappings.getInstance(project).getMapping(virtualFile);
44 |
45 | if (language != null) {
46 | SyntaxHighlighter outerHighlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(language.getAssociatedFileType(), project, virtualFile);
47 |
48 | if (outerHighlighter != null) {
49 | registerLayer(getTokenElementType(STLexer.TEXT), new LayerDescriptor(outerHighlighter, ""));
50 | }
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/highlight/STSyntaxHighlighter.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.highlight;
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.adaptor.lexer.ANTLRLexerAdaptor;
10 | import org.antlr.jetbrains.st4plugin.STLanguage;
11 | import org.antlr.jetbrains.st4plugin.parsing.STLexer;
12 | import org.antlr.jetbrains.st4plugin.psi.STTokenTypes;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | import java.util.List;
16 | import java.util.stream.Collectors;
17 | import java.util.stream.Stream;
18 |
19 | import static com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey;
20 | import static org.antlr.jetbrains.st4plugin.psi.STTokenTypes.getTokenElementType;
21 |
22 | public class STSyntaxHighlighter extends SyntaxHighlighterBase {
23 |
24 | public static final TextAttributesKey STGroup_TEMPLATE_TEXT =
25 | createTextAttributesKey("STGroup_TEMPLATE_TEXT", DefaultLanguageHighlighterColors.TEMPLATE_LANGUAGE_COLOR);
26 |
27 | private static final List KEYWORDS = Stream.of(
28 | STLexer.IF, STLexer.ELSE, STLexer.END, STLexer.TRUE,
29 | STLexer.FALSE, STLexer.ELSEIF, STLexer.ENDIF, STLexer.SUPER
30 | ).map(STTokenTypes::getTokenElementType).collect(Collectors.toList());
31 |
32 | @NotNull
33 | @Override
34 | public Lexer getHighlightingLexer() {
35 | return new ANTLRLexerAdaptor(STLanguage.INSTANCE, new STLexer(null));
36 | }
37 |
38 | @NotNull
39 | @Override
40 | public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
41 | TextAttributesKey key;
42 |
43 | if (KEYWORDS.contains(tokenType)) {
44 | key = STGroupSyntaxHighlighter.KEYWORD;
45 | } else if (getTokenElementType(STLexer.STRING).equals(tokenType)
46 | || getTokenElementType(STLexer.TEXT).equals(tokenType)) {
47 | key = STGroup_TEMPLATE_TEXT;
48 | } else if (getTokenElementType(STLexer.TMPL_COMMENT).equals(tokenType)) {
49 | key = STGroupSyntaxHighlighter.BLOCK_COMMENT;
50 | } else if (getTokenElementType(STLexer.SUB_ERR_CHAR).equals(tokenType)) {
51 | key = HighlighterColors.BAD_CHARACTER;
52 | } else if (getTokenElementType(STLexer.ESCAPE).equals(tokenType)) {
53 | key = DefaultLanguageHighlighterColors.VALID_STRING_ESCAPE;
54 | } else {
55 | return STGroupSyntaxHighlighter.NO_ATTRIBUTES;
56 | }
57 |
58 | return new TextAttributesKey[]{key};
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/psi/TemplateContentLiteralTextEscaper.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.psi;
2 |
3 | import com.intellij.openapi.util.TextRange;
4 | import com.intellij.psi.LiteralTextEscaper;
5 | import com.intellij.psi.PsiLanguageInjectionHost;
6 | import org.antlr.jetbrains.st4plugin.parsing.STGLexer;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | import static org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes.getTokenElementType;
10 |
11 | /**
12 | * Removes escaped quotes from subtemplates when parsing them as {@link org.antlr.jetbrains.st4plugin.STLanguage}
13 | * files.
14 | */
15 | class TemplateContentLiteralTextEscaper extends LiteralTextEscaper {
16 |
17 | private int[] offsetsFromDecodedToHost = new int[0];
18 |
19 | public TemplateContentLiteralTextEscaper(TemplateContentElement templateContentElement) {
20 | super(templateContentElement);
21 | }
22 |
23 | @Override
24 | public boolean decode(@NotNull TextRange rangeInsideHost, @NotNull StringBuilder outChars) {
25 | String subTemplate = rangeInsideHost.substring(myHost.getText());
26 |
27 | if (myHost.getNode().getFirstChildNode().getElementType() == getTokenElementType(STGLexer.STRING)
28 | && subTemplate.indexOf('\\') >= 0) {
29 |
30 | offsetsFromDecodedToHost = new int[subTemplate.length() + 1];
31 |
32 | for (int indexInHost = 0, indexInDecoded = 0; indexInHost < subTemplate.length(); indexInHost++) {
33 | if (subTemplate.charAt(indexInHost) == '\\'
34 | && indexInHost + 1 < subTemplate.length()
35 | && subTemplate.charAt(indexInHost + 1) == '"') {
36 |
37 | indexInHost++; // skip '\'
38 | }
39 |
40 | outChars.append(subTemplate.charAt(indexInHost));
41 |
42 | offsetsFromDecodedToHost[indexInDecoded++] = indexInHost;
43 | offsetsFromDecodedToHost[indexInDecoded] = indexInHost + 1;
44 | }
45 | } else {
46 | offsetsFromDecodedToHost = new int[subTemplate.length() + 1];
47 | for (int i = 0; i < offsetsFromDecodedToHost.length; i++) {
48 | offsetsFromDecodedToHost[i] = i;
49 | }
50 | outChars.append(subTemplate);
51 | }
52 |
53 | return true;
54 | }
55 |
56 | @Override
57 | public int getOffsetInHost(int offsetInDecoded, @NotNull TextRange rangeInsideHost) {
58 | int result = offsetInDecoded < offsetsFromDecodedToHost.length ? offsetsFromDecodedToHost[offsetInDecoded] : -1;
59 | if (result == -1) {
60 | return -1;
61 | }
62 |
63 | return Math.min(result, rangeInsideHost.getLength()) + rangeInsideHost.getStartOffset();
64 | }
65 |
66 | @Override
67 | public boolean isOneLine() {
68 | return false;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/contributors.txt:
--------------------------------------------------------------------------------
1 | ANTLR Project Contributors Certification of Origin and Rights
2 |
3 | *This is the standard contributors.txt file for the ANTLR project
4 | but we explicitly include the StringTemplate jetbrains plugin here.*
5 |
6 | All contributors to ANTLR v4 must formally agree to abide by this
7 | certificate of origin by signing on the bottom with their github
8 | userid, full name, email address (you can obscure your e-mail, but it
9 | must be computable by human), and date.
10 |
11 | By signing this agreement, you are warranting and representing that
12 | you have the right to release code contributions or other content free
13 | of any obligations to third parties and are granting Terence Parr and
14 | ANTLR project contributors, henceforth referred to as The ANTLR
15 | Project, a license to incorporate it into The ANTLR Project tools
16 | (such as ANTLRWorks and StringTemplate) or related works under the BSD
17 | license. You understand that The ANTLR Project may or may not
18 | incorporate your contribution and you warrant and represent the
19 | following:
20 |
21 | 1. I am the creator of all my contributions. I am the author of all
22 | contributed work submitted and further warrant and represent that
23 | such work is my original creation and I have the right to license
24 | it to The ANTLR Project for release under the 3-clause BSD
25 | license. I hereby grant The ANTLR Project a nonexclusive,
26 | irrevocable, royalty-free, worldwide license to reproduce,
27 | distribute, prepare derivative works, and otherwise use this
28 | contribution as part of the ANTLR project, associated
29 | documentation, books, and tools at no cost to The ANTLR Project.
30 |
31 | 2. I have the right to submit. This submission does not violate the
32 | rights of any person or entity and that I have legal authority over
33 | this submission and to make this certification.
34 |
35 | 3. If I violate another's rights, liability lies with me. I agree to
36 | defend, indemnify, and hold The ANTLR Project and ANTLR users
37 | harmless from any claim or demand, including reasonable attorney
38 | fees, made by any third party due to or arising out of my violation
39 | of these terms and conditions or my violation of the rights of
40 | another person or entity.
41 |
42 | 4. I understand and agree that this project and the contribution are
43 | public and that a record of the contribution (including all
44 | personal information I submit with it, including my sign-off) is
45 | maintained indefinitely and may be redistributed consistent with
46 | this project or the open source license indicated in the file.
47 |
48 | I have read this agreement and do so certify by adding my signoff to
49 | the end of the following contributors list.
50 |
51 | CONTRIBUTORS:
52 |
53 | YYYY/MM/DD, github id, Full name, email
54 | 2015/11/09, parrt, Terence Parr, parrt@antlr.org
55 | 2019/01/16, syakovlevdalet, Sergey Yakovlev, syakovlev@dalet.com
56 | 2019/01/17, bjansen, Bastien Jansen, bastien.jansen@gmx.com
57 | 2020/05/19, FHannes, Frédéric Hannes, frederic.hannes@gmail.com
58 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/structview/STGroupTemplateDefItemPresentation.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.structview;
2 |
3 | import com.intellij.extapi.psi.ASTWrapperPsiElement;
4 | import com.intellij.lang.ASTNode;
5 | import com.intellij.navigation.ItemPresentation;
6 | import com.intellij.psi.tree.IElementType;
7 | import com.intellij.psi.tree.TokenSet;
8 | import org.antlr.jetbrains.st4plugin.Icons;
9 | import org.antlr.jetbrains.st4plugin.parsing.STGLexer;
10 | import org.antlr.jetbrains.st4plugin.parsing.STGParser;
11 | import org.jetbrains.annotations.Nullable;
12 |
13 | import javax.swing.*;
14 | import java.util.Arrays;
15 | import java.util.stream.Collectors;
16 |
17 | import static org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes.getRuleElementType;
18 | import static org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes.getTokenElementType;
19 |
20 | public class STGroupTemplateDefItemPresentation implements ItemPresentation {
21 |
22 | private final ASTWrapperPsiElement psiElement;
23 |
24 | public STGroupTemplateDefItemPresentation(ASTWrapperPsiElement psiElement) {
25 | this.psiElement = psiElement;
26 | }
27 |
28 | @Nullable
29 | @Override
30 | public String getPresentableText() {
31 | ASTNode id = psiElement.getNode().findChildByType(getTokenElementType(STGLexer.ID));
32 |
33 | if (id == null) {
34 | return null;
35 | }
36 |
37 | StringBuilder text = new StringBuilder(id.getText());
38 |
39 | ASTNode args = psiElement.getNode().findChildByType(getRuleElementType(STGParser.RULE_formalArgs));
40 |
41 | if (args != null) {
42 | text.append('(');
43 |
44 | ASTNode[] argList = args.getChildren(TokenSet.create(getRuleElementType(STGParser.RULE_formalArg)));
45 |
46 | text.append(Arrays.stream(argList).map(ASTNode::getText).collect(Collectors.joining(", ")));
47 |
48 | text.append(')');
49 | }
50 |
51 | return text.toString();
52 | }
53 |
54 | @Nullable
55 | @Override
56 | public String getLocationString() {
57 | return null;
58 | }
59 |
60 | @Nullable
61 | @Override
62 | public Icon getIcon(boolean unused) {
63 | if (psiElement.getNode().getElementType() == getRuleElementType(STGParser.RULE_dict)) {
64 | return Icons.DICT;
65 | }
66 |
67 | ASTNode content = psiElement.getNode().findChildByType(getRuleElementType(STGParser.RULE_templateContent));
68 | IElementType elementType = null;
69 |
70 | if (content != null) {
71 | ASTNode firstChild = content.getFirstChildNode();
72 |
73 | if (firstChild != null) {
74 | elementType = firstChild.getElementType();
75 | }
76 | }
77 |
78 | if (elementType == getTokenElementType(STGLexer.STRING)) {
79 | return Icons.STRING;
80 | } else if (elementType == getTokenElementType(STGLexer.BIGSTRING_NO_NL)) {
81 | return Icons.BIGSTRING_NONL;
82 | }
83 |
84 | return Icons.BIGSTRING;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/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 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/src/main/resources/st-java-injections.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ST (org.stringtemplate.v4)
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | STGroup (org.stringtemplate.v4)
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | STGroupString (org.stringtemplate.v4)
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/folding/STFoldingBuilder.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.folding;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.lang.folding.CustomFoldingBuilder;
5 | import com.intellij.lang.folding.FoldingDescriptor;
6 | import com.intellij.openapi.editor.Document;
7 | import com.intellij.openapi.util.TextRange;
8 | import com.intellij.psi.PsiElement;
9 | import com.intellij.psi.util.PsiTreeUtil;
10 | import org.antlr.jetbrains.st4plugin.parsing.STLexer;
11 | import org.antlr.jetbrains.st4plugin.parsing.STParser;
12 | import org.antlr.jetbrains.st4plugin.psi.STFile;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | import java.util.List;
16 |
17 | import static org.antlr.jetbrains.st4plugin.psi.STTokenTypes.getRuleElementType;
18 | import static org.antlr.jetbrains.st4plugin.psi.STTokenTypes.getTokenElementType;
19 |
20 | public class STFoldingBuilder extends CustomFoldingBuilder {
21 | @Override
22 | protected void buildLanguageFoldRegions(@NotNull List descriptors,
23 | @NotNull PsiElement root,
24 | @NotNull Document document,
25 | boolean quick) {
26 | if (!(root instanceof STFile)) {
27 | return;
28 | }
29 |
30 | foldRegions(descriptors, root);
31 | foldIf(descriptors, root);
32 | }
33 |
34 | private void foldRegions(List descriptors, PsiElement root) {
35 | PsiTreeUtil.processElements(root, element -> {
36 | if (element.getNode().getElementType() == getRuleElementType(STParser.RULE_region)) {
37 | descriptors.add(new FoldingDescriptor(element, element.getTextRange()));
38 | }
39 |
40 | return true;
41 | });
42 | }
43 |
44 | private void foldIf(List descriptors, PsiElement root) {
45 | PsiTreeUtil.processElements(root, element -> {
46 | if (element.getNode().getElementType() == getRuleElementType(STParser.RULE_ifstat)) {
47 | descriptors.add(new FoldingDescriptor(element, element.getTextRange()));
48 | }
49 |
50 | return true;
51 | });
52 | }
53 |
54 | @Override
55 | protected String getLanguagePlaceholderText(@NotNull ASTNode node, @NotNull TextRange range) {
56 | if (node.getElementType() == getRuleElementType(STParser.RULE_region)) {
57 | ASTNode id = node.findChildByType(getTokenElementType(STLexer.ID));
58 |
59 | return "<@" + (id == null ? "??" : id.getText()) + ">";
60 | } else if (node.getElementType() == getRuleElementType(STParser.RULE_ifstat)) {
61 | ASTNode lDelim = node.findChildByType(getTokenElementType(STLexer.LDELIM));
62 | ASTNode rDelim = node.findChildByType(getTokenElementType(STLexer.RDELIM));
63 |
64 | if (lDelim != null && rDelim != null) {
65 | int startOffset = node.getStartOffset();
66 | return node.getText().substring(lDelim.getStartOffset() - startOffset, rDelim.getStartOffset() + rDelim.getTextLength() - startOffset);
67 | } else {
68 | return "";
69 | }
70 | }
71 |
72 | return "...";
73 | }
74 |
75 | @Override
76 | protected boolean isRegionCollapsedByDefault(@NotNull ASTNode node) {
77 | return false;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/antlr/STGParser.g4:
--------------------------------------------------------------------------------
1 | /* [The "BSD license"]
2 | * Copyright (c) 2011-2014 Terence Parr
3 | * Copyright (c) 2013-2015 Gerald Rosenberg
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions
8 | * are met:
9 | * 1. Redistributions of source code must retain the above copyright
10 | * notice, this list of conditions and the following disclaimer.
11 | * 2. Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * 3. The name of the author may not be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | /* Antlr grammar for StringTemplate v4.
30 | *
31 | * Modified 2013.11.21 gbr
32 | * -- updated
33 | * Modified 2015.06.21 gbr
34 | * -- updated to use imported standard fragments
35 | */
36 |
37 | parser grammar STGParser;
38 |
39 | options {
40 | language=Java;
41 | tokenVocab=STGLexer;
42 | }
43 |
44 | group
45 | : oldStyleHeader? delimiters? imports?
46 | ( template | dict )+
47 | EOF
48 | ;
49 |
50 | // Accepted for retrocompatibility with V3 but ignored by the reference parser
51 | oldStyleHeader
52 | : GROUP ID (COLON ID)? (IMPLEMENTS ID (COMMA ID)* )? SEMI;
53 |
54 | delimiters
55 | : DELIMITERS STRING COMMA STRING
56 | ;
57 |
58 | imports
59 | : ( IMPORT STRING )+
60 | ;
61 |
62 | template
63 | : ( AT ID DOT ID LPAREN RPAREN
64 | | ID LPAREN formalArgs? RPAREN
65 | )
66 | TMPL_ASSIGN templateContent
67 | | ID TMPL_ASSIGN ID // alias one template to another
68 | ;
69 |
70 | templateContent
71 | : STRING // "..."
72 | | BIGSTRING // <<...>>
73 | | BIGSTRING_NO_NL // <%...%>
74 | ;
75 |
76 | formalArgs
77 | : formalArg ( COMMA formalArg )*
78 | ;
79 |
80 | formalArg
81 | : ID ( ASSIGN STRING
82 | | ASSIGN ANON_TEMPLATE
83 | | ASSIGN TRUE
84 | | ASSIGN FALSE
85 | | ASSIGN LBRACK RBRACK
86 | )?
87 | ;
88 |
89 | dict
90 | : ID TMPL_ASSIGN LBRACK dictPairs RBRACK
91 | ;
92 |
93 | dictPairs
94 | : keyValuePair ( COMMA keyValuePair )* ( COMMA defaultValuePair )?
95 | | defaultValuePair
96 | ;
97 |
98 | keyValuePair : STRING COLON keyValue ;
99 | defaultValuePair : DEFAULT COLON keyValue ;
100 |
101 | keyValue
102 | : BIGSTRING
103 | | BIGSTRING_NO_NL
104 | | ANON_TEMPLATE
105 | | STRING
106 | | TRUE
107 | | FALSE
108 | | LBRACK RBRACK
109 | | KEY
110 | ;
111 |
112 | junk : JUNK ; // define to over come https://github.com/antlr/antlr4/issues/1042
113 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/psi/STLanguageInjector.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.psi;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.openapi.util.TextRange;
5 | import com.intellij.psi.InjectedLanguagePlaces;
6 | import com.intellij.psi.LanguageInjector;
7 | import com.intellij.psi.PsiElement;
8 | import com.intellij.psi.PsiLanguageInjectionHost;
9 | import com.intellij.psi.tree.TokenSet;
10 | import org.antlr.jetbrains.st4plugin.STLanguage;
11 | import org.antlr.jetbrains.st4plugin.parsing.STGLexer;
12 | import org.antlr.jetbrains.st4plugin.parsing.STGParser;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | import static org.antlr.jetbrains.st4plugin.parsing.LexerAdaptor.DELIMITERS_PREFIX;
16 | import static org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes.getRuleElementType;
17 | import static org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes.getTokenElementType;
18 |
19 | /**
20 | * Inject the {@link STLanguage} in {@link org.antlr.jetbrains.st4plugin.STGroupLanguage} subtemplates.
21 | */
22 | public class STLanguageInjector implements LanguageInjector {
23 |
24 | @Override
25 | public void getLanguagesToInject(@NotNull PsiLanguageInjectionHost host,
26 | @NotNull InjectedLanguagePlaces injectionPlacesRegistrar) {
27 |
28 | if (host instanceof TemplateContentElement) {
29 | PsiElement firstChild = host.getFirstChild();
30 |
31 | String delimiters = detectDelimiters(host);
32 |
33 | if (firstChild != null
34 | && (firstChild.getNode().getElementType() == getTokenElementType(STGLexer.BIGSTRING) || firstChild.getNode().getElementType() == getTokenElementType(STGLexer.BIGSTRING_NO_NL))
35 | && host.getTextLength() > 4) {
36 | TextRange textRange = TextRange.create(2, host.getTextLength() - 2);
37 | injectionPlacesRegistrar.addPlace(STLanguage.INSTANCE, textRange, delimiters, null);
38 | } else if (firstChild != null
39 | && firstChild.getNode().getElementType() == getTokenElementType(STGLexer.STRING)
40 | && host.getTextLength() > 2) {
41 | TextRange textRange = TextRange.create(1, host.getTextLength() - 1);
42 | injectionPlacesRegistrar.addPlace(STLanguage.INSTANCE, textRange, delimiters, null);
43 | }
44 | }
45 | }
46 |
47 | /**
48 | * If the STGroup file contains a {@code delimiters "x", "y"} section, we pass those delimiters as a special
49 | * prefix to the lexer. The lexer will then detect this prefix and reconfigure itself to support the new
50 | * delimiters.
51 | */
52 | private String detectDelimiters(@NotNull PsiLanguageInjectionHost host) {
53 | ASTNode root = host.getContainingFile().getFirstChild().getNode();
54 |
55 | if (root.getElementType() == getRuleElementType(STGParser.RULE_group)) {
56 | ASTNode delimitersStatement = root.findChildByType(getRuleElementType(STGParser.RULE_delimiters));
57 |
58 | if (delimitersStatement != null) {
59 | ASTNode[] strings = delimitersStatement.getChildren(TokenSet.create(getTokenElementType(STGLexer.STRING)));
60 |
61 | if (strings.length == 2 && strings[0].getTextLength() == 3 && strings[1].getTextLength() == 3) {
62 | return "" + DELIMITERS_PREFIX + strings[0].getText().charAt(1) + strings[1].getText().charAt(1);
63 | }
64 | }
65 | }
66 | return null;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/highlight/STGroupSyntaxHighlighter.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.highlight;
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.adaptor.lexer.ANTLRLexerAdaptor;
10 | import org.antlr.intellij.adaptor.lexer.TokenIElementType;
11 | import org.antlr.jetbrains.st4plugin.STGroupLanguage;
12 | import org.antlr.jetbrains.st4plugin.parsing.STGLexer;
13 | import org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes;
14 | import org.antlr.v4.runtime.Token;
15 | import org.jetbrains.annotations.NotNull;
16 |
17 | import java.util.List;
18 | import java.util.stream.Collectors;
19 | import java.util.stream.Stream;
20 |
21 | import static com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey;
22 | import static org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes.getTokenElementType;
23 |
24 | public class STGroupSyntaxHighlighter extends SyntaxHighlighterBase {
25 |
26 | public static final TextAttributesKey TEMPLATE_NAME =
27 | createTextAttributesKey("STGroup_TEMPLATE_NAME", DefaultLanguageHighlighterColors.INSTANCE_METHOD);
28 | public static final TextAttributesKey LINE_COMMENT =
29 | createTextAttributesKey("STGroup_LINE_COMMENT", DefaultLanguageHighlighterColors.LINE_COMMENT);
30 | public static final TextAttributesKey BLOCK_COMMENT =
31 | createTextAttributesKey("STGroup_BLOCK_COMMENT", DefaultLanguageHighlighterColors.BLOCK_COMMENT);
32 | public static final TextAttributesKey KEYWORD =
33 | createTextAttributesKey("STGroup_KEYWORD", DefaultLanguageHighlighterColors.KEYWORD);
34 | public static final TextAttributesKey STRING =
35 | createTextAttributesKey("STGroup_STRING", DefaultLanguageHighlighterColors.STRING);
36 |
37 | private static final List KEYWORDS = Stream.of(
38 | STGLexer.DELIMITERS, STGLexer.IMPORT, STGLexer.DEFAULT, STGLexer.KEY, STGLexer.GROUP
39 | ).map(STGroupTokenTypes::getTokenElementType).collect(Collectors.toList());
40 |
41 | public static final TextAttributesKey[] NO_ATTRIBUTES = new TextAttributesKey[0];
42 |
43 | @NotNull
44 | @Override
45 | public Lexer getHighlightingLexer() {
46 | return new ANTLRLexerAdaptor(STGroupLanguage.INSTANCE, new STGLexer(null));
47 | }
48 |
49 | @NotNull
50 | @Override
51 | public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
52 | if (getTokenElementType(STGLexer.COMMENT).equals(tokenType)) {
53 | return new TextAttributesKey[]{BLOCK_COMMENT};
54 | } else if (getTokenElementType(STGLexer.LINE_COMMENT).equals(tokenType)) {
55 | return new TextAttributesKey[]{LINE_COMMENT};
56 | } else if (getTokenElementType(STGLexer.STRING).equals(tokenType)) {
57 | return new TextAttributesKey[]{STRING};
58 | } else if (getTokenElementType(STGLexer.ID).equals(tokenType)) {
59 | return new TextAttributesKey[]{TEMPLATE_NAME};
60 | } else if (KEYWORDS.contains(tokenType)) {
61 | return new TextAttributesKey[]{KEYWORD};
62 | } else if (tokenType instanceof TokenIElementType && ((TokenIElementType) tokenType).getANTLRTokenType() == Token.INVALID_TYPE) {
63 | return new TextAttributesKey[]{HighlighterColors.BAD_CHARACTER};
64 | }
65 | return NO_ATTRIBUTES;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/psi/STGroupParserDefinition.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.psi;
2 |
3 | import com.intellij.extapi.psi.ASTWrapperPsiElement;
4 | import com.intellij.lang.ASTNode;
5 | import com.intellij.lang.ParserDefinition;
6 | import com.intellij.lang.PsiParser;
7 | import com.intellij.lexer.Lexer;
8 | import com.intellij.openapi.project.Project;
9 | import com.intellij.psi.FileViewProvider;
10 | import com.intellij.psi.PsiElement;
11 | import com.intellij.psi.PsiFile;
12 | import com.intellij.psi.tree.IElementType;
13 | import com.intellij.psi.tree.IFileElementType;
14 | import com.intellij.psi.tree.TokenSet;
15 | import org.antlr.intellij.adaptor.lexer.ANTLRLexerAdaptor;
16 | import org.antlr.intellij.adaptor.lexer.PSIElementTypeFactory;
17 | import org.antlr.intellij.adaptor.parser.ANTLRParserAdaptor;
18 | import org.antlr.jetbrains.st4plugin.STGroupLanguage;
19 | import org.antlr.jetbrains.st4plugin.parsing.STGLexer;
20 | import org.antlr.jetbrains.st4plugin.parsing.STGParser;
21 | import org.antlr.v4.runtime.Parser;
22 | import org.antlr.v4.runtime.tree.ParseTree;
23 | import org.jetbrains.annotations.NotNull;
24 |
25 | public class STGroupParserDefinition implements ParserDefinition {
26 |
27 | public static final IFileElementType FILE = new IFileElementType(STGroupLanguage.INSTANCE);
28 |
29 | public STGroupParserDefinition() {
30 | STGroupTokenTypes.initIElementTypes();
31 | }
32 |
33 | @NotNull
34 | @Override
35 | public Lexer createLexer(Project project) {
36 | STGLexer lexer = new STGLexer(null);
37 | return new ANTLRLexerAdaptor(STGroupLanguage.INSTANCE, lexer);
38 | }
39 |
40 | @Override
41 | public PsiParser createParser(Project project) {
42 | return new ANTLRParserAdaptor(STGroupLanguage.INSTANCE, new STGParser(null)) {
43 | @Override
44 | protected ParseTree parse(Parser parser, IElementType root) {
45 | return ((STGParser) parser).group();
46 | }
47 | };
48 | }
49 |
50 | @Override
51 | public IFileElementType getFileNodeType() {
52 | return FILE;
53 | }
54 |
55 | @NotNull
56 | @Override
57 | public TokenSet getCommentTokens() {
58 | return PSIElementTypeFactory.createTokenSet(
59 | STGroupLanguage.INSTANCE,
60 | STGLexer.COMMENT,
61 | STGLexer.LINE_COMMENT
62 | );
63 | }
64 |
65 | @NotNull
66 | @Override
67 | public TokenSet getStringLiteralElements() {
68 | return PSIElementTypeFactory.createTokenSet(
69 | STGroupLanguage.INSTANCE,
70 | STGLexer.STRING
71 | );
72 | }
73 |
74 | @NotNull
75 | @Override
76 | public PsiElement createElement(ASTNode node) {
77 | if (node.getElementType() == STGroupTokenTypes.getRuleElementType(STGParser.RULE_templateContent)) {
78 | return new TemplateContentElement(node);
79 | }
80 |
81 | return new ASTWrapperPsiElement(node);
82 | }
83 |
84 | @Override
85 | public PsiFile createFile(FileViewProvider viewProvider) {
86 | return new STGroupFile(viewProvider);
87 | }
88 |
89 | @NotNull
90 | @Override
91 | public TokenSet getWhitespaceTokens() {
92 | return PSIElementTypeFactory.createTokenSet(
93 | STGroupLanguage.INSTANCE,
94 | STGLexer.WS
95 | );
96 | }
97 |
98 | @Override
99 | public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) {
100 | return SpaceRequirements.MAY;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/test/java/org/antlr/jetbrains/st4plugin/psi/TemplateContentLiteralTextEscaperTest.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.psi;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.openapi.util.TextRange;
5 | import org.antlr.intellij.adaptor.lexer.PSIElementTypeFactory;
6 | import org.antlr.jetbrains.st4plugin.STGroupLanguage;
7 | import org.antlr.jetbrains.st4plugin.parsing.STGLexer;
8 | import org.antlr.jetbrains.st4plugin.parsing.STGParser;
9 | import org.junit.BeforeClass;
10 | import org.junit.Test;
11 | import org.mockito.internal.stubbing.answers.ThrowsException;
12 |
13 | import static org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes.getTokenElementType;
14 | import static org.junit.Assert.assertEquals;
15 | import static org.mockito.Mockito.doReturn;
16 | import static org.mockito.Mockito.mock;
17 |
18 | public class TemplateContentLiteralTextEscaperTest {
19 |
20 | private TemplateContentLiteralTextEscaper escaper;
21 |
22 | @BeforeClass
23 | public static void beforeClass() {
24 | PSIElementTypeFactory.defineLanguageIElementTypes(
25 | STGroupLanguage.INSTANCE,
26 | STGLexer.tokenNames,
27 | STGParser.ruleNames
28 | );
29 | }
30 |
31 | @Test
32 | public void testDecodeNoQuotes() {
33 | // Given
34 | String templateText = "\"some template\"";
35 |
36 | TemplateContentElement template = parse(templateText);
37 | escaper = new TemplateContentLiteralTextEscaper(template);
38 |
39 | TextRange rangeInsideHost = TextRange.create(1, templateText.length() - 1);
40 |
41 | StringBuilder outBuilder = new StringBuilder();
42 |
43 | // When
44 | escaper.decode(rangeInsideHost, outBuilder);
45 |
46 | // Then
47 | assertEquals(rangeInsideHost.substring(templateText), outBuilder.toString());
48 |
49 | assertEquals(1, escaper.getOffsetInHost(0, rangeInsideHost));
50 | assertEquals(2, escaper.getOffsetInHost(1, rangeInsideHost));
51 | assertEquals(3, escaper.getOffsetInHost(2, rangeInsideHost));
52 | assertEquals(13, escaper.getOffsetInHost(12, rangeInsideHost));
53 | }
54 |
55 | @Test
56 | public void testDecodeQuotes() {
57 | // Given
58 | String templateText = "\"format=\\\"cap\\\";\"";
59 |
60 | TemplateContentElement template = parse(templateText);
61 | escaper = new TemplateContentLiteralTextEscaper(template);
62 |
63 | TextRange rangeInsideHost = TextRange.create(1, templateText.length() - 1);
64 |
65 | StringBuilder outBuilder = new StringBuilder();
66 |
67 | // When
68 | escaper.decode(rangeInsideHost, outBuilder);
69 |
70 | // Then
71 | assertEquals("format=\"cap\";", outBuilder.toString());
72 |
73 | assertEquals(1, escaper.getOffsetInHost(0, rangeInsideHost)); // f
74 | assertEquals(2, escaper.getOffsetInHost(1, rangeInsideHost)); // o
75 | assertEquals(3, escaper.getOffsetInHost(2, rangeInsideHost)); // r
76 | assertEquals(9, escaper.getOffsetInHost(7, rangeInsideHost)); // "
77 | assertEquals(10, escaper.getOffsetInHost(8, rangeInsideHost)); // c
78 | assertEquals(14, escaper.getOffsetInHost(11, rangeInsideHost)); // "
79 | assertEquals(15, escaper.getOffsetInHost(12, rangeInsideHost)); // ;
80 | }
81 |
82 | private TemplateContentElement parse(String raw) {
83 | TemplateContentElement template = mock(TemplateContentElement.class, new ThrowsException(new UnsupportedOperationException()));
84 | ASTNode astNode = mock(ASTNode.class);
85 |
86 | doReturn(raw).when(template).getText();
87 | doReturn(astNode).when(template).getNode();
88 | doReturn(astNode).when(astNode).getFirstChildNode();
89 | doReturn(getTokenElementType(STGLexer.STRING)).when(astNode).getElementType();
90 |
91 | return template;
92 | }
93 | }
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/psi/STParserDefinition.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.psi;
2 |
3 | import com.intellij.extapi.psi.ASTWrapperPsiElement;
4 | import com.intellij.lang.ASTNode;
5 | import com.intellij.lang.ParserDefinition;
6 | import com.intellij.lang.PsiParser;
7 | import com.intellij.lexer.Lexer;
8 | import com.intellij.openapi.project.Project;
9 | import com.intellij.psi.FileViewProvider;
10 | import com.intellij.psi.PsiElement;
11 | import com.intellij.psi.PsiFile;
12 | import com.intellij.psi.tree.IElementType;
13 | import com.intellij.psi.tree.IFileElementType;
14 | import com.intellij.psi.tree.TokenSet;
15 | import org.antlr.intellij.adaptor.lexer.ANTLRLexerAdaptor;
16 | import org.antlr.intellij.adaptor.lexer.PSIElementTypeFactory;
17 | import org.antlr.intellij.adaptor.parser.ANTLRParserAdaptor;
18 | import org.antlr.jetbrains.st4plugin.STLanguage;
19 | import org.antlr.jetbrains.st4plugin.parsing.STLexer;
20 | import org.antlr.jetbrains.st4plugin.parsing.STParser;
21 | import org.antlr.v4.runtime.Parser;
22 | import org.antlr.v4.runtime.Token;
23 | import org.antlr.v4.runtime.tree.ParseTree;
24 | import org.jetbrains.annotations.NotNull;
25 |
26 | public class STParserDefinition implements ParserDefinition {
27 |
28 | public static final IFileElementType FILE = new IFileElementType(STLanguage.INSTANCE);
29 |
30 | public STParserDefinition() {
31 | STTokenTypes.initIElementTypes();
32 | }
33 |
34 | @NotNull
35 | @Override
36 | public Lexer createLexer(Project project) {
37 | return new ANTLRLexerAdaptor(STLanguage.INSTANCE, new STLexer(null)) {
38 | @Override
39 | public void advance() {
40 | Token before = super.getCurrentToken();
41 | super.advance();
42 | Token after = super.getCurrentToken();
43 |
44 | if (before != null && after != null) {
45 | if (after.getStartIndex() != before.getStopIndex() + 1) {
46 | System.err.println("Lexer gap between tokens\n" + before + "\n\nand\n\n" + after);
47 | }
48 | }
49 | }
50 | };
51 | }
52 |
53 | @Override
54 | public PsiParser createParser(Project project) {
55 | return new ANTLRParserAdaptor(STLanguage.INSTANCE, new STParser(null)) {
56 | @Override
57 | protected ParseTree parse(Parser parser, IElementType root) {
58 | return ((STParser) parser).template();
59 | }
60 | };
61 | }
62 |
63 | @Override
64 | public IFileElementType getFileNodeType() {
65 | return FILE;
66 | }
67 |
68 | @NotNull
69 | @Override
70 | public TokenSet getCommentTokens() {
71 | return PSIElementTypeFactory.createTokenSet(
72 | STLanguage.INSTANCE,
73 | STLexer.TMPL_COMMENT
74 | );
75 | }
76 |
77 | @NotNull
78 | @Override
79 | public TokenSet getStringLiteralElements() {
80 | return PSIElementTypeFactory.createTokenSet(
81 | STLanguage.INSTANCE,
82 | STLexer.STRING
83 | );
84 | }
85 |
86 | @NotNull
87 | @Override
88 | public PsiElement createElement(ASTNode node) {
89 | return new ASTWrapperPsiElement(node);
90 | }
91 |
92 | @Override
93 | public PsiFile createFile(FileViewProvider viewProvider) {
94 | return new STFile(viewProvider);
95 | }
96 |
97 | @NotNull
98 | @Override
99 | public TokenSet getWhitespaceTokens() {
100 | return PSIElementTypeFactory.createTokenSet(
101 | STLanguage.INSTANCE,
102 | STLexer.VERT_WS,
103 | STLexer.HORZ_WS
104 | );
105 | }
106 |
107 | @Override
108 | public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) {
109 | return SpaceRequirements.MAY;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/highlight/STColorSettingsPage.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.highlight;
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.jetbrains.st4plugin.Icons;
9 | import org.jetbrains.annotations.Nls;
10 | import org.jetbrains.annotations.NotNull;
11 | import org.jetbrains.annotations.Nullable;
12 |
13 | import javax.swing.*;
14 | import java.util.HashMap;
15 | import java.util.Map;
16 |
17 | public class STColorSettingsPage implements ColorSettingsPage {
18 |
19 | private static final AttributesDescriptor[] DESCRIPTORS = new AttributesDescriptor[]{
20 | new AttributesDescriptor("Template Name", STGroupSyntaxHighlighter.TEMPLATE_NAME),
21 | new AttributesDescriptor("Template Parameter", STGroupSemanticHighlightAnnotator.TEMPLATE_PARAM),
22 | new AttributesDescriptor("String", STGroupSyntaxHighlighter.STRING),
23 | new AttributesDescriptor("Keyword", STGroupSyntaxHighlighter.KEYWORD),
24 | new AttributesDescriptor("Line Comment", STGroupSyntaxHighlighter.LINE_COMMENT),
25 | new AttributesDescriptor("Block Comment", STGroupSyntaxHighlighter.BLOCK_COMMENT),
26 | new AttributesDescriptor("Option", STSemanticHighlightAnnotator.OPTION)
27 | };
28 |
29 | @Override
30 | public @Nullable Icon getIcon() {
31 | return Icons.STG_FILE;
32 | }
33 |
34 | @Override
35 | public @NotNull SyntaxHighlighter getHighlighter() {
36 | return new STGroupSyntaxHighlighter();
37 | }
38 |
39 | @Override
40 | public @NotNull String getDemoText() {
41 | return "/**\n" +
42 | " * Multi line comment\n" +
43 | " */\n" +
44 | "\n" +
45 | "delimiters \"$\", \"$\"\n" +
46 | "\n" +
47 | "// single line comment\n" +
48 | "myMap ::= [\n" +
49 | " \"key\": \"value\",\n" +
50 | " default: key\n" +
51 | "]\n" +
52 | "\n" +
53 | "myTemplate(param1, param2) ::= <<\n" +
54 | " hello, world\n" +
55 | " \n" +
56 | " <if (param1)>\n" +
57 | " a\n" +
58 | " <elseif (true)>\n" +
59 | " b\n" +
60 | " <else>\n" +
61 | " <param2 separator=\", \">\n" +
62 | " <endif>\n" +
63 | ">>\n" +
64 | "\n" +
65 | "oneLiner(x) ::= \"hello, <x>\"\n";
66 | }
67 |
68 | @Override
69 | public @Nullable Map getAdditionalHighlightingTagToDescriptorMap() {
70 | Map tagToDescriptor = new HashMap<>();
71 | tagToDescriptor.put("param", STGroupSemanticHighlightAnnotator.TEMPLATE_PARAM);
72 | tagToDescriptor.put("keyword", STGroupSyntaxHighlighter.KEYWORD);
73 | tagToDescriptor.put("option", STSemanticHighlightAnnotator.OPTION);
74 | tagToDescriptor.put("comment", STGroupSyntaxHighlighter.BLOCK_COMMENT);
75 | return tagToDescriptor;
76 | }
77 |
78 | @Override
79 | public @NotNull AttributesDescriptor[] getAttributeDescriptors() {
80 | return DESCRIPTORS;
81 | }
82 |
83 | @Override
84 | public @NotNull ColorDescriptor[] getColorDescriptors() {
85 | return ColorDescriptor.EMPTY_ARRAY;
86 | }
87 |
88 | @Override
89 | public @NotNull @Nls(
90 | capitalization = Nls.Capitalization.Title
91 | ) String getDisplayName() {
92 | return "StringTemplate";
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/highlight/STSemanticHighlightAnnotator.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.highlight;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.lang.annotation.AnnotationHolder;
5 | import com.intellij.lang.annotation.Annotator;
6 | import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
7 | import com.intellij.openapi.editor.colors.TextAttributesKey;
8 | import com.intellij.openapi.util.TextRange;
9 | import com.intellij.psi.PsiElement;
10 | import com.intellij.psi.tree.TokenSet;
11 | import com.intellij.psi.util.PsiTreeUtil;
12 | import org.antlr.jetbrains.st4plugin.parsing.STLexer;
13 | import org.antlr.jetbrains.st4plugin.parsing.STParser;
14 | import org.antlr.jetbrains.st4plugin.psi.STTokenTypes;
15 | import org.jetbrains.annotations.NotNull;
16 |
17 | import static com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey;
18 | import static org.antlr.jetbrains.st4plugin.psi.STTokenTypes.getRuleElementType;
19 | import static org.antlr.jetbrains.st4plugin.psi.STTokenTypes.getTokenElementType;
20 |
21 | /**
22 | * Semantic highlighting for .st files.
23 | */
24 | public class STSemanticHighlightAnnotator implements Annotator {
25 |
26 | private static final TextAttributesKey ST_TAG = createTextAttributesKey("ST_TAG");
27 | public static final TextAttributesKey OPTION = createTextAttributesKey("ST_OPTION", DefaultLanguageHighlighterColors.INSTANCE_METHOD);
28 |
29 | @Override
30 | public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
31 | if (element.getNode().getElementType() == STTokenTypes.getTokenElementType(STLexer.ID)) {
32 | if (isPrimary(element) || isSubtemplate(element)) {
33 | holder.createInfoAnnotation(element, null)
34 | .setTextAttributes(STGroupSemanticHighlightAnnotator.TEMPLATE_PARAM);
35 | } else if (isOptionId(element)) {
36 | holder.createInfoAnnotation(element, null)
37 | .setTextAttributes(OPTION);
38 | } else if (isCall(element)) {
39 | holder.createInfoAnnotation(element, null)
40 | .setTextAttributes(STGroupSyntaxHighlighter.TEMPLATE_NAME);
41 | }
42 | }
43 |
44 | if (isTag(element)) {
45 | // use a white/dark background instead of the default green from injected languages
46 | holder.createInfoAnnotation(element, null)
47 | .setTextAttributes(ST_TAG);
48 | }
49 |
50 | if (element.getNode().getElementType() == getRuleElementType(STParser.RULE_ifstat)) {
51 | for (ASTNode ldelim : element.getNode().getChildren(TokenSet.create(getTokenElementType(STLexer.LDELIM)))) {
52 | ASTNode rdelim = element.getNode().findChildByType(getTokenElementType(STLexer.RDELIM), ldelim);
53 |
54 | if (rdelim != null) {
55 | // use a white/dark background instead of the default green from injected languages
56 | holder.createInfoAnnotation(TextRange.create(ldelim.getStartOffset(), rdelim.getStartOffset() + rdelim.getTextLength()), null)
57 | .setTextAttributes(ST_TAG);
58 | }
59 | }
60 | }
61 | }
62 |
63 | private boolean isSubtemplate(@NotNull PsiElement element) {
64 | return element.getParent().getNode().getElementType() == getRuleElementType(STParser.RULE_subtemplate);
65 | }
66 |
67 | private boolean isTag(@NotNull PsiElement element) {
68 | return element.getNode().getElementType() == STTokenTypes.getRuleElementType(STParser.RULE_exprTag);
69 | }
70 |
71 | private boolean isPrimary(@NotNull PsiElement element) {
72 | return element.getParent().getNode().getElementType() == getRuleElementType(STParser.RULE_primary);
73 | }
74 |
75 | private boolean isCall(PsiElement element) {
76 | PsiElement nextVisibleLeaf = PsiTreeUtil.nextVisibleLeaf(element);
77 |
78 | return nextVisibleLeaf != null && nextVisibleLeaf.getNode().getElementType() == STTokenTypes.getTokenElementType(STLexer.LPAREN);
79 | }
80 |
81 | private boolean isOptionId(@NotNull PsiElement element) {
82 | return element.getParent().getNode().getElementType() == getRuleElementType(STParser.RULE_option);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/antlr/STGLexer.g4:
--------------------------------------------------------------------------------
1 | /*
2 | * [The "BSD license"]
3 | * Copyright (c) 2011-2014 Terence Parr
4 | * Copyright (c) 2015 Gerald Rosenberg
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * 3. The name of the author may not be used to endorse or promote products
16 | * derived from this software without specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 |
30 | /**
31 | * A grammar for StringTemplate v4 implemented using Antlr v4 syntax
32 | *
33 | * Modified 2015.06.16 gbr
34 | * -- update for compatibility with Antlr v4.5
35 | * -- use imported standard fragments
36 | */
37 |
38 | lexer grammar STGLexer;
39 |
40 | import LexBasic; // Standard set of fragments
41 |
42 | // ------------------------------------------------------------------------------
43 | // mode default
44 |
45 | COMMENT : BlockComment -> channel(HIDDEN) ;
46 | LINE_COMMENT : LineComment -> channel(HIDDEN) ;
47 |
48 | WS : [ \r\n\t]+ -> channel(HIDDEN) ;
49 |
50 | STRING_START : DQuote -> more, pushMode(STRING_MODE) ;
51 | ANON_TEMPLATE : LBrace ('\\}'|~'}')* RBrace ;
52 | BIGSTRING_START : LDAngle -> more, pushMode(BIGSTRING_MODE) ;
53 | BIGSTRING_NO_NL_START : LPct -> more, pushMode(BIGSTRING_NO_NL_MODE) ;
54 |
55 |
56 | // -----------------------------------
57 | // Symbols
58 |
59 | TMPL_ASSIGN : TmplAssign ;
60 | ASSIGN : Equal ;
61 |
62 | DOT : Dot ;
63 | COMMA : Comma ;
64 | COLON : Colon ;
65 | SEMI : Semi ;
66 | LPAREN : LParen ;
67 | RPAREN : RParen ;
68 | LBRACK : LBrack ;
69 | RBRACK : RBrack ;
70 | AT : At ;
71 | TRUE : True ;
72 | FALSE : False ;
73 | ELLIPSIS : Ellipsis ;
74 |
75 | // -----------------------------------
76 | // Key words
77 |
78 | DELIMITERS : 'delimiters' ;
79 | IMPORT : 'import' ;
80 | DEFAULT : 'default' ;
81 | KEY : 'key' ;
82 |
83 | GROUP : 'group' ; // for compatibility with V3 syntax
84 | IMPLEMENTS : 'implements' ; // for compatibility with V3 syntax
85 |
86 | ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'-'|'_')* ;
87 |
88 | // -----------------------------------
89 | // Grammar specific fragments
90 |
91 | fragment TmplAssign : '::=' ;
92 | fragment LPct : '<%' ;
93 | fragment RPct : '%>' ;
94 | fragment LDAngle : LShift ;
95 | fragment RDAngle : RShift ;
96 |
97 | ERRCHAR : . -> channel (HIDDEN) ;
98 |
99 | mode STRING_MODE;
100 |
101 | STRING_ESC : '\\"' {setText(getText()+"\"");} -> more ;
102 | STRING_NL : '\n' -> more ; // match but it should be an error
103 | STRING : '"' -> popMode ;
104 | EOF_STRING : EOF -> popMode ;
105 | STRING_TEXT : . -> more;
106 |
107 | mode BIGSTRING_MODE;
108 |
109 | BIGSTRING_ESC : '\\>' -> more ;
110 | BIGSTRING : '>>' -> popMode ;
111 | EOF_BIGSTRING : EOF -> popMode ;
112 | BIGSTRING_TEXT : . -> more;
113 |
114 | mode BIGSTRING_NO_NL_MODE;
115 |
116 | BIGSTRING_NO_NL_ESC : '\\%' -> more;
117 | BIGSTRING_NO_NL : '%>' -> popMode ;
118 | EOF_BIGSTRING_NO_NL : EOF -> popMode ;
119 | BIGSTRING_NO_NL_TEXT: . -> more;
120 |
121 |
122 |
--------------------------------------------------------------------------------
/src/main/antlr/STLexer.g4:
--------------------------------------------------------------------------------
1 | /* [The "BSD license"]
2 | * Copyright (c) 2011-2014 Terence Parr
3 | * Copyright (c) 2015 Gerald Rosenberg
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions
8 | * are met:
9 | * 1. Redistributions of source code must retain the above copyright
10 | * notice, this list of conditions and the following disclaimer.
11 | * 2. Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * 3. The name of the author may not be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | /* Antlr grammar for StringTemplate v4.
30 | *
31 | * Modified 2015.06.16 gbr
32 | * -- update for compatibility with Antlr v4.5
33 | * -- use imported standard fragments
34 | */
35 |
36 | lexer grammar STLexer;
37 |
38 | options {
39 | superClass = LexerAdaptor ;
40 | }
41 |
42 | import LexBasic; // Standard set of fragments
43 |
44 | channels {
45 | OFF_CHANNEL // non-default channel for whitespace and comments
46 | }
47 |
48 | tokens {
49 | HORZ_WS, VERT_WS
50 | }
51 |
52 | // -----------------------------------
53 | // default mode = Outside
54 |
55 | TMPL_COMMENT : TmplComment -> channel(OFF_CHANNEL) ;
56 |
57 | ESCAPE : . { isLDelim() }? EscSeq . { isRDelim() }? ; // self contained
58 | LDELIM : . { isLDelim() }? -> mode(Inside) ; // switch mode to inside
59 | RBRACE : RBrace { endsSubTemplate() }? ; // conditional switch to inside
60 |
61 | TEXT : . { adjText(); } ; // have to handle weird terminals
62 |
63 |
64 | // -----------------------------------
65 | mode Inside ;
66 |
67 | INS_HORZ_WS : Hws+ -> type(HORZ_WS), channel(OFF_CHANNEL) ;
68 | INS_VERT_WS : Vws+ -> type(VERT_WS), channel(OFF_CHANNEL) ;
69 |
70 | LBRACE : LBrace { startSubTemplate(); } ;
71 | RDELIM : . { isRDelim() }? -> mode(DEFAULT_MODE) ;
72 |
73 | STRING : DQuoteLiteral ;
74 |
75 | IF : 'if' ;
76 | ELSEIF : 'elseif' ;
77 | ELSE : 'else' ;
78 | ENDIF : 'endif' ;
79 | SUPER : 'super' ;
80 | END : '@end' ;
81 |
82 | TRUE : True ;
83 | FALSE : False ;
84 |
85 | INS_ID : NameStartChar NameChar* -> type(ID);
86 |
87 | AT : At ;
88 | ELLIPSIS : Ellipsis ;
89 | DOT : Dot ;
90 | COMMA : Comma ;
91 | COLON : Colon ;
92 | SEMI : Semi ;
93 | AND : And ;
94 | OR : Or ;
95 | LPAREN : LParen ;
96 | RPAREN : RParen ;
97 | LBRACK : LBrack ;
98 | RBRACK : RBrack ;
99 | EQUALS : Equal ;
100 | BANG : Bang ;
101 |
102 | INS_EOF : EOF;
103 |
104 | // -----------------------------------
105 | // Unknown content in mode Inside
106 | INS_ERR_CHAR : . -> channel(HIDDEN) ;
107 |
108 |
109 | // -----------------------------------
110 | mode SubTemplate ;
111 |
112 | SUB_HORZ_WS : Hws+ -> type(HORZ_WS), channel(OFF_CHANNEL) ;
113 | SUB_VERT_WS : Vws+ -> type(VERT_WS), channel(OFF_CHANNEL) ;
114 |
115 | ID : NameStartChar NameChar* ;
116 | SUB_COMMA : Comma -> type(COMMA) ;
117 | PIPE : Pipe -> mode(DEFAULT_MODE) ;
118 |
119 |
120 | // -----------------------------------
121 | // Grammar specific fragments
122 |
123 | fragment TmplComment : LTmplMark .*? RTmplMark ;
124 |
125 | fragment LTmplMark : . { isLTmplComment() }? Bang ;
126 | fragment RTmplMark : Bang . { isRTmplComment() }? ;
127 |
128 | SUB_EOF : EOF;
129 |
130 | SUB_ERR_CHAR : . -> channel(HIDDEN) ;
131 |
--------------------------------------------------------------------------------
/src/test/java/org/antlr/jetbrains/st4plugin/structview/STGroupTemplateDefItemPresentationTest.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.structview;
2 |
3 | import static org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes.getRuleElementType;
4 |
5 | import com.intellij.extapi.psi.ASTWrapperPsiElement;
6 | import com.intellij.psi.PsiElement;
7 | import com.intellij.psi.PsiFile;
8 | import com.intellij.psi.PsiFileFactory;
9 | import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase;
10 | import javax.swing.Icon;
11 | import org.antlr.jetbrains.st4plugin.Icons;
12 | import org.antlr.jetbrains.st4plugin.STGroupFileType;
13 | import org.antlr.jetbrains.st4plugin.parsing.STGParser;
14 | import org.jetbrains.annotations.NotNull;
15 |
16 | public class STGroupTemplateDefItemPresentationTest extends CodeInsightFixtureTestCase {
17 |
18 | public void testIssue37() {
19 | // Given
20 | ASTWrapperPsiElement template = parseTemplate("A() ::= ");
21 |
22 | STGroupTemplateDefItemPresentation presentation = new STGroupTemplateDefItemPresentation(template);
23 |
24 | // When
25 | Icon icon = presentation.getIcon(false);
26 |
27 | // Then
28 | assertSame(template.getNode().getElementType(), getRuleElementType(STGParser.RULE_template));
29 | assertEquals(Icons.BIGSTRING, icon);
30 | }
31 |
32 | public void testDict() {
33 | // Given
34 | ASTWrapperPsiElement template = parseTemplate("dict ::= [] ");
35 |
36 | STGroupTemplateDefItemPresentation presentation = new STGroupTemplateDefItemPresentation(template);
37 |
38 | // When
39 | Icon icon = presentation.getIcon(false);
40 | String text = presentation.getPresentableText();
41 |
42 | // Then
43 | assertEquals(Icons.DICT, icon);
44 | assertEquals("dict", text);
45 | }
46 |
47 | public void testString() {
48 | // Given
49 | ASTWrapperPsiElement template = parseTemplate("stringTpl() ::= \"\" ");
50 |
51 | STGroupTemplateDefItemPresentation presentation = new STGroupTemplateDefItemPresentation(template);
52 |
53 | // When
54 | Icon icon = presentation.getIcon(false);
55 | String text = presentation.getPresentableText();
56 |
57 | // Then
58 | assertEquals(Icons.STRING, icon);
59 | assertEquals("stringTpl", text);
60 | }
61 |
62 | public void testBigString() {
63 | // Given
64 | ASTWrapperPsiElement template = parseTemplate("bigStringTpl() ::= <<>> ");
65 |
66 | STGroupTemplateDefItemPresentation presentation = new STGroupTemplateDefItemPresentation(template);
67 |
68 | // When
69 | Icon icon = presentation.getIcon(false);
70 | String text = presentation.getPresentableText();
71 |
72 | // Then
73 | assertEquals(Icons.BIGSTRING, icon);
74 | assertEquals("bigStringTpl", text);
75 | }
76 |
77 | public void testBigStringNoNlWithParams() {
78 | // Given
79 | ASTWrapperPsiElement template = parseTemplate("bigStringNoNl(foo, bar) ::= <%%> ");
80 |
81 | STGroupTemplateDefItemPresentation presentation = new STGroupTemplateDefItemPresentation(template);
82 |
83 | // When
84 | Icon icon = presentation.getIcon(false);
85 | String text = presentation.getPresentableText();
86 |
87 | // Then
88 | assertEquals(Icons.BIGSTRING_NONL, icon);
89 | assertEquals("bigStringNoNl(foo, bar)", text);
90 | }
91 |
92 | public void testTemplateAlias() {
93 | // Given
94 | ASTWrapperPsiElement template = parseTemplate("foo ::= bar");
95 |
96 | STGroupTemplateDefItemPresentation presentation = new STGroupTemplateDefItemPresentation(template);
97 |
98 | // When
99 | Icon icon = presentation.getIcon(false);
100 | String text = presentation.getPresentableText();
101 |
102 | // Then
103 | assertEquals(Icons.BIGSTRING, icon);
104 | assertEquals("foo", text);
105 | }
106 |
107 | @NotNull
108 | private ASTWrapperPsiElement parseTemplate(String content) {
109 | PsiFile file = PsiFileFactory.getInstance(myFixture.getProject())
110 | .createFileFromText("a.stg", STGroupFileType.INSTANCE, content);
111 |
112 | PsiElement template = file.getFirstChild().getFirstChild();
113 |
114 | return (ASTWrapperPsiElement) template;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 | org.antlr.jetbrains.st4plugin
3 | StringTemplate v4
4 | will be replaced by gradle
5 | ANTLR Project
6 |
7 |
9 | This plugin is for StringTemplate v4 .stg/.st files. It works with
10 | IntelliJ IDEA 2022.2 and newer. It should work in other IntelliJ-based IDEs.
11 |
12 |
13 | Github source
14 | ]]>
15 |
16 |
18 | Fixed compatibility with IntelliJ 2022.3.x (#41)
19 | Fixed compatibility with Rider 2022.3.x (#42)
20 | Updated to latest versions of ANTLR and StringTemplate
21 |
22 | ]]>
23 |
24 |
25 |
26 |
27 |
28 |
30 |
31 | com.intellij.modules.lang
32 | org.intellij.intelliLang
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
49 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/src/main/antlr/STParser.g4:
--------------------------------------------------------------------------------
1 | /* [The "BSD license"]
2 | * Copyright (c) 2011-2014 Terence Parr
3 | * Copyright (c) 2015 Gerald Rosenberg
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions
8 | * are met:
9 | * 1. Redistributions of source code must retain the above copyright
10 | * notice, this list of conditions and the following disclaimer.
11 | * 2. Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * 3. The name of the author may not be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | /* Antlr grammar for StringTemplate v4.
30 | *
31 | * Modified 2015.06.21 gbr
32 | * -- use imported standard fragments
33 | */
34 |
35 | parser grammar STParser;
36 |
37 | options {
38 | language=Java;
39 | tokenVocab=STLexer;
40 | }
41 |
42 | template
43 | : elements
44 | ;
45 |
46 | elements
47 | : element*
48 | ;
49 |
50 | element
51 | : singleElement
52 | | compoundElement
53 | ;
54 |
55 | singleElement
56 | : exprTag
57 | | (TEXT | ESCAPE)+
58 | ;
59 |
60 | compoundElement
61 | : ifstat
62 | | region
63 | ;
64 |
65 | exprTag
66 | : LDELIM mapExpr ( SEMI exprOptions )? RDELIM
67 | ;
68 |
69 | region
70 | : LDELIM AT ID RDELIM
71 | elements
72 | LDELIM END RDELIM
73 | ;
74 |
75 | subtemplate
76 | : LBRACE ( ID ( COMMA ID )* PIPE )? elements RBRACE
77 | ;
78 |
79 | ifstat
80 | : LDELIM IF LPAREN conditional RPAREN RDELIM
81 | elements
82 | ( LDELIM ELSEIF LPAREN conditional RPAREN RDELIM elements )*
83 | ( LDELIM ELSE RDELIM elements )?
84 | LDELIM ENDIF RDELIM
85 | ;
86 |
87 | conditional
88 | : andConditional ( OR andConditional )*
89 | ;
90 |
91 | andConditional
92 | : notConditional ( AND notConditional )*
93 | ;
94 |
95 | notConditional
96 | : BANG notConditional
97 | | memberExpr
98 | ;
99 |
100 | notConditionalExpr
101 | : ID ( DOT ID
102 | | DOT LPAREN mapExpr RPAREN
103 | )*
104 | ;
105 |
106 | exprOptions
107 | : option ( COMMA option )*
108 | ;
109 |
110 | option
111 | : ID ( EQUALS expr )?
112 | ;
113 |
114 | expr
115 | : memberExpr ( COLON mapTemplateRef )?
116 | ;
117 |
118 | // more complicated than necessary to avoid backtracking,
119 | // which ruins error handling
120 | mapExpr
121 | : memberExpr ( ( COMMA memberExpr )+ COLON mapTemplateRef )?
122 | ( COLON mapTemplateRef ( COMMA mapTemplateRef )* )*
123 | ;
124 |
125 | memberExpr
126 | : includeExpr
127 | ( DOT ID
128 | | DOT LPAREN mapExpr RPAREN
129 | )*
130 | ;
131 |
132 | // expr:template(args) apply template to expr
133 | // expr:{arg | ...} apply subtemplate to expr
134 | // expr:(e)(args) convert e to a string template name and apply to expr
135 | mapTemplateRef
136 | : ID LPAREN args? RPAREN
137 | | subtemplate
138 | | LPAREN mapExpr RPAREN LPAREN argExprList? RPAREN
139 | ;
140 |
141 | includeExpr
142 | : ID LPAREN mapExpr? RPAREN
143 | | SUPER DOT ID LPAREN args? RPAREN
144 | | ID LPAREN args? RPAREN
145 | | AT SUPER DOT ID LPAREN RPAREN
146 | | AT ID LPAREN RPAREN
147 | | primary
148 | ;
149 |
150 | primary
151 | : ID
152 | | STRING
153 | | TRUE
154 | | FALSE
155 | | subtemplate
156 | | list
157 | | LPAREN conditional RPAREN
158 | | LPAREN mapExpr RPAREN ( LPAREN argExprList? RPAREN )?
159 | ;
160 |
161 | list
162 | : LBRACK argExprList? RBRACK
163 | ;
164 |
165 | args
166 | : argExprList
167 | | namedArg ( COMMA namedArg )* ( COMMA ELLIPSIS )?
168 | | ELLIPSIS
169 | ;
170 |
171 | argExprList
172 | : expr ( COMMA expr )*
173 | ;
174 |
175 | namedArg
176 | : ID EQUALS expr
177 | ;
178 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/folding/STGroupFoldingBuilder.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.folding;
2 |
3 | import com.intellij.lang.ASTNode;
4 | import com.intellij.lang.folding.CustomFoldingBuilder;
5 | import com.intellij.lang.folding.FoldingDescriptor;
6 | import com.intellij.openapi.editor.Document;
7 | import com.intellij.openapi.util.TextRange;
8 | import com.intellij.psi.PsiElement;
9 | import com.intellij.psi.tree.TokenSet;
10 | import com.intellij.psi.util.PsiTreeUtil;
11 | import org.antlr.jetbrains.st4plugin.parsing.STGLexer;
12 | import org.antlr.jetbrains.st4plugin.parsing.STGParser;
13 | import org.antlr.jetbrains.st4plugin.psi.STGroupFile;
14 | import org.jetbrains.annotations.NotNull;
15 |
16 | import java.util.List;
17 |
18 | import static org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes.getRuleElementType;
19 | import static org.antlr.jetbrains.st4plugin.psi.STGroupTokenTypes.getTokenElementType;
20 |
21 | public class STGroupFoldingBuilder extends CustomFoldingBuilder {
22 |
23 | @Override
24 | protected void buildLanguageFoldRegions(@NotNull List descriptors,
25 | @NotNull PsiElement root,
26 | @NotNull Document document,
27 | boolean quick) {
28 | if (!(root instanceof STGroupFile)) {
29 | return;
30 | }
31 |
32 | foldTemplates(descriptors, root);
33 | foldDicts(descriptors, root);
34 | foldComments(descriptors, root);
35 | }
36 |
37 | private void foldTemplates(List descriptors, PsiElement root) {
38 | PsiTreeUtil.processElements(root, element -> {
39 | if (element.getNode().getElementType() == getRuleElementType(STGParser.RULE_templateContent)) {
40 | ASTNode bigString = element.getNode().findChildByType(TokenSet.create(
41 | getTokenElementType(STGLexer.BIGSTRING),
42 | getTokenElementType(STGLexer.BIGSTRING_NO_NL)
43 | ));
44 |
45 | if (bigString != null) {
46 | descriptors.add(new FoldingDescriptor(bigString, bigString.getTextRange()));
47 | }
48 | } else if (element.getNode().getElementType() == getRuleElementType(STGParser.RULE_formalArg)) {
49 | ASTNode template = element.getNode().findChildByType(getTokenElementType(STGLexer.ANON_TEMPLATE));
50 |
51 | if (template != null) {
52 | descriptors.add(new FoldingDescriptor(template, template.getTextRange()));
53 | }
54 | }
55 |
56 | return true;
57 | });
58 | }
59 |
60 | private void foldDicts(List descriptors, PsiElement root) {
61 | PsiTreeUtil.processElements(root, element -> {
62 | if (element.getNode().getElementType() == getRuleElementType(STGParser.RULE_dict)) {
63 | ASTNode lbrack = element.getNode().findChildByType(getTokenElementType(STGLexer.LBRACK));
64 | ASTNode rbrack = element.getNode().findChildByType(getTokenElementType(STGLexer.RBRACK));
65 |
66 | if (lbrack != null && rbrack != null) {
67 | TextRange range = lbrack.getTextRange().union(rbrack.getTextRange());
68 | descriptors.add(new FoldingDescriptor(element, range));
69 | }
70 | }
71 |
72 | return true;
73 | });
74 | }
75 |
76 | private void foldComments(List descriptors, PsiElement root) {
77 | PsiTreeUtil.processElements(root, element -> {
78 | if (element.getNode().getElementType() == getTokenElementType(STGLexer.COMMENT)) {
79 | descriptors.add(new FoldingDescriptor(element, element.getTextRange()));
80 | }
81 |
82 | return true;
83 | });
84 |
85 | }
86 |
87 | @Override
88 | protected String getLanguagePlaceholderText(@NotNull ASTNode node, @NotNull TextRange range) {
89 | if (node.getElementType() == getTokenElementType(STGLexer.BIGSTRING)) {
90 | return "<<...>>";
91 | } else if (node.getElementType() == getTokenElementType(STGLexer.BIGSTRING_NO_NL)) {
92 | return "<%...%>";
93 | } else if (node.getElementType() == getTokenElementType(STGLexer.ANON_TEMPLATE)) {
94 | return "{...}";
95 | } else if (node.getElementType() == getRuleElementType(STGParser.RULE_dict)) {
96 | return "[...]";
97 | } else if (node.getElementType() == getTokenElementType(STGLexer.COMMENT)) {
98 | return "/*...*/";
99 | }
100 | return "...";
101 | }
102 |
103 | @Override
104 | protected boolean isRegionCollapsedByDefault(@NotNull ASTNode node) {
105 | return false;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/org/antlr/jetbrains/st4plugin/parsing/LexerAdaptor.java:
--------------------------------------------------------------------------------
1 | package org.antlr.jetbrains.st4plugin.parsing;
2 |
3 | import com.intellij.psi.PsiLanguageInjectionHost;
4 | import org.antlr.v4.runtime.CharStream;
5 | import org.antlr.v4.runtime.CommonToken;
6 | import org.antlr.v4.runtime.IntStream;
7 | import org.antlr.v4.runtime.Lexer;
8 | import org.antlr.v4.runtime.Token;
9 |
10 | public abstract class LexerAdaptor extends Lexer {
11 |
12 | public static final char DELIMITERS_PREFIX = '\u0001';
13 |
14 | private final java.util.Queue queue = new java.util.LinkedList<>();
15 |
16 | private char lDelim = '<';
17 | private char rDelim = '>';
18 |
19 | private int subtemplateDepth;
20 |
21 | public LexerAdaptor(CharStream input) {
22 | super(input);
23 | }
24 |
25 | @Override
26 | public Token nextToken() {
27 | if (_input.index() == 0 && _input.LA(1) == DELIMITERS_PREFIX) {
28 | return lexDelimitersPrefix();
29 | }
30 |
31 | if (!queue.isEmpty()) {
32 | return queue.poll();
33 | }
34 |
35 | Token next = super.nextToken();
36 |
37 | return next.getType() == STLexer.TEXT ? mergeConsecutiveTextTokens(next) : next;
38 | }
39 |
40 | private Token mergeConsecutiveTextTokens(Token next) {
41 | StringBuilder builder = new StringBuilder();
42 | Token startToken = next;
43 |
44 | while (next.getType() == STLexer.TEXT) {
45 | builder.append(next.getText());
46 | next = super.nextToken();
47 | }
48 |
49 | // The `next` will _not_ be a TEXT-token, store it in
50 | // the queue to return the next time!
51 | queue.offer(next);
52 |
53 | CommonToken token = new CommonToken(startToken);
54 | token.setStopIndex(startToken.getStartIndex() + builder.length() - 1);
55 |
56 | return token;
57 | }
58 |
59 | /**
60 | * @see org.antlr.jetbrains.st4plugin.psi.STLanguageInjector#detectDelimiters(PsiLanguageInjectionHost)
61 | */
62 | private Token lexDelimitersPrefix() {
63 | int _lDelim = _input.LA(2);
64 | int _rDelim = _input.LA(3);
65 |
66 | if (_lDelim != -1 && _rDelim != -1) {
67 | setDelimiters((char) _lDelim, (char) _rDelim);
68 |
69 | // Consume the prefix and the delimiters
70 | _input.consume();
71 | _input.consume();
72 | _input.consume();
73 |
74 | return getTokenFactory().create(_tokenFactorySourcePair, STLexer.HORZ_WS, "xxx", HIDDEN, 0, 2, 1, 0);
75 | }
76 |
77 | return super.nextToken();
78 | }
79 |
80 | public void startSubTemplate() {
81 | subtemplateDepth++;
82 |
83 | // look for "{ args ID (',' ID)* '|' ..."
84 | if (isSubTemplateWithArgs()) {
85 | mode(STLexer.SubTemplate);
86 | } else {
87 | mode(STLexer.DEFAULT_MODE);
88 | }
89 | }
90 |
91 | private boolean isSubTemplateWithArgs() {
92 | int position = _input.index();
93 | int mark = _input.mark();
94 |
95 | boolean isSubTemplateWithArgs = matchSubTemplateWithArgs();
96 |
97 | _input.seek(position);
98 | _input.release(mark);
99 |
100 | return isSubTemplateWithArgs;
101 | }
102 |
103 | private boolean matchSubTemplateWithArgs() {
104 | matchWs();
105 | if (!matchId()) {
106 | return false;
107 | }
108 | matchWs();
109 |
110 | while (_input.LA(1) == ',') {
111 | _input.consume();
112 | matchWs();
113 | if (!matchId()) {
114 | return false;
115 | }
116 | matchWs();
117 | }
118 |
119 | return _input.LA(1) == '|';
120 | }
121 |
122 | private boolean matchId() {
123 | boolean isId = false;
124 |
125 | while (isIDLetter((char) _input.LA(1))) {
126 | _input.consume();
127 | isId = true;
128 | }
129 |
130 | return isId;
131 | }
132 |
133 | private void matchWs() {
134 | int c = _input.LA(1);
135 | while (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
136 | _input.consume();
137 | c = _input.LA(1);
138 | }
139 | }
140 |
141 | // if last RBrace, continue with mode Outside
142 | public boolean endsSubTemplate() {
143 | if (subtemplateDepth > 0) {
144 | subtemplateDepth--;
145 | mode(1); // STLexer.Inside
146 |
147 | return true;
148 | }
149 |
150 | return false;
151 | }
152 |
153 | public void setDelimiters(char lDelim, char rDelim) {
154 | this.lDelim = lDelim;
155 | this.rDelim = rDelim;
156 | }
157 |
158 | public boolean isLDelim() {
159 | return lDelim == _input.LA(-1);
160 | }
161 |
162 | public boolean isRDelim() {
163 | return rDelim == _input.LA(-1);
164 | }
165 |
166 | public boolean isLTmplComment() {
167 | return isLDelim() && _input.LA(1) == '!';
168 | }
169 |
170 | public boolean isRTmplComment() {
171 | return isRDelim() && _input.LA(-2) == '!';
172 | }
173 |
174 | public void adjText() {
175 | int c1 = _input.LA(-1);
176 | if (c1 == '\\') {
177 | int c2 = _input.LA(1);
178 | if (c2 == '\\') {
179 | _input.consume(); // convert \\ to \
180 | } else if (c2 == lDelim || c2 == '}') {
181 | _input.consume();
182 | }
183 | }
184 | }
185 |
186 | public Token newTokenFromPreviousChar(int ttype) {
187 | return _factory.create(_tokenFactorySourcePair, ttype, _text, _channel, getCharIndex() - 1, getCharIndex() - 1,
188 | _tokenStartLine, _tokenStartCharPositionInLine);
189 | }
190 |
191 | @Override
192 | public void setInputStream(IntStream input) {
193 | queue.clear();
194 | super.setInputStream(input);
195 | }
196 |
197 | private static boolean isIDLetter(char c) {
198 | return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '-' || c == '_';
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/src/main/antlr/LexBasic.g4:
--------------------------------------------------------------------------------
1 | /*
2 | * [The "BSD license"]
3 | * Copyright (c) 2014-2015 Gerald Rosenberg
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions
8 | * are met:
9 | *
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * 3. The name of the author may not be used to endorse or promote products
16 | * derived from this software without specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 |
30 | /**
31 | * A generally reusable set of fragments for import in to Lexer grammars.
32 | *
33 | * Modified 2015.06.16 gbr -
34 | * -- generalized for inclusion into the ANTLRv4 grammar distribution
35 | *
36 | */
37 |
38 | lexer grammar LexBasic;
39 |
40 | import LexUnicode; // Formal set of Unicode ranges
41 |
42 | // ======================================================
43 | // Lexer fragments
44 | //
45 |
46 |
47 | // -----------------------------------
48 | // Whitespace & Comments
49 |
50 | fragment Ws : Hws | Vws ;
51 | fragment Hws : [ \t] ;
52 | fragment Vws : [\r\n\f] ;
53 |
54 | fragment DocComment : '/**' .*? ('*/' | EOF) ;
55 | fragment BlockComment : '/*' .*? ('*/' | EOF) ;
56 |
57 | fragment LineComment : '//' ~[\r\n]* ;
58 | fragment LineCommentExt : '//' ~'\n'* ( '\n' Hws* '//' ~'\n'* )* ;
59 |
60 |
61 | // -----------------------------------
62 | // Escapes
63 |
64 | // Any kind of escaped character that we can embed within ANTLR literal strings.
65 | fragment EscSeq
66 | : Esc
67 | ( [btnfr"'\\] // The standard escaped character set such as tab, newline, etc.
68 | | UnicodeEsc // A Unicode escape sequence
69 | | . // Invalid escape character
70 | | EOF // Incomplete at EOF
71 | )
72 | ;
73 |
74 | fragment EscAny
75 | : Esc .
76 | ;
77 |
78 | fragment UnicodeEsc
79 | : 'u' (HexDigit (HexDigit (HexDigit HexDigit?)?)?)?
80 | ;
81 |
82 | fragment OctalEscape
83 | : OctalDigit
84 | | OctalDigit OctalDigit
85 | | [0-3] OctalDigit OctalDigit
86 | ;
87 |
88 |
89 | // -----------------------------------
90 | // Numerals
91 |
92 | fragment HexNumeral
93 | : '0' [xX] HexDigits
94 | ;
95 |
96 | fragment OctalNumeral
97 | : '0' '_' OctalDigits
98 | ;
99 |
100 | fragment DecimalNumeral
101 | : '0'
102 | | [1-9] DecDigit*
103 | ;
104 |
105 | fragment BinaryNumeral
106 | : '0' [bB] BinaryDigits
107 | ;
108 |
109 |
110 | // -----------------------------------
111 | // Digits
112 |
113 | fragment HexDigits : HexDigit+ ;
114 | fragment DecDigits : DecDigit+ ;
115 | fragment OctalDigits : OctalDigit+ ;
116 | fragment BinaryDigits : BinaryDigit+ ;
117 |
118 | fragment HexDigit : [0-9a-fA-F] ;
119 | fragment DecDigit : [0-9] ;
120 | fragment OctalDigit : [0-7] ;
121 | fragment BinaryDigit : [01] ;
122 |
123 |
124 | // -----------------------------------
125 | // Literals
126 |
127 | fragment BoolLiteral : True | False ;
128 |
129 | fragment CharLiteral : SQuote ( EscSeq | ~['\r\n\\] ) SQuote ;
130 | fragment SQuoteLiteral : SQuote ( EscSeq | ~['\r\n\\] )* SQuote ;
131 | fragment DQuoteLiteral : DQuote ( EscSeq | ~["\r\n\\] )* DQuote ;
132 | fragment USQuoteLiteral : SQuote ( EscSeq | ~['\r\n\\] )* ;
133 |
134 | fragment DecimalFloatingPointLiteral
135 | : DecDigits DOT DecDigits? ExponentPart? FloatTypeSuffix?
136 | | DOT DecDigits ExponentPart? FloatTypeSuffix?
137 | | DecDigits ExponentPart FloatTypeSuffix?
138 | | DecDigits FloatTypeSuffix
139 | ;
140 |
141 | fragment ExponentPart
142 | : [eE] [+-]? DecDigits
143 | ;
144 |
145 | fragment FloatTypeSuffix
146 | : [fFdD]
147 | ;
148 |
149 | fragment HexadecimalFloatingPointLiteral
150 | : HexSignificand BinaryExponent FloatTypeSuffix?
151 | ;
152 |
153 | fragment HexSignificand
154 | : HexNumeral DOT?
155 | | '0' [xX] HexDigits? DOT HexDigits
156 | ;
157 |
158 | fragment BinaryExponent
159 | : [pP] [+-]? DecDigits
160 | ;
161 |
162 |
163 | // -----------------------------------
164 | // Character ranges
165 |
166 | fragment NameChar
167 | : NameStartChar
168 | | '0'..'9'
169 | | Underscore
170 | | '\u00B7'
171 | | '\u0300'..'\u036F'
172 | | '\u203F'..'\u2040'
173 | ;
174 |
175 | fragment NameStartChar
176 | : 'A'..'Z'
177 | | 'a'..'z'
178 | | '\u00C0'..'\u00D6'
179 | | '\u00D8'..'\u00F6'
180 | | '\u00F8'..'\u02FF'
181 | | '\u0370'..'\u037D'
182 | | '\u037F'..'\u1FFF'
183 | | '\u200C'..'\u200D'
184 | | '\u2070'..'\u218F'
185 | | '\u2C00'..'\u2FEF'
186 | | '\u3001'..'\uD7FF'
187 | | '\uF900'..'\uFDCF'
188 | | '\uFDF0'..'\uFFFD'
189 | ; // ignores | ['\u10000-'\uEFFFF] ;
190 |
191 |
192 | fragment JavaLetter
193 | : [a-zA-Z$_] // "java letters" below 0xFF
194 | | JavaUnicodeChars
195 | ;
196 |
197 | fragment JavaLetterOrDigit
198 | : [a-zA-Z0-9$_] // "java letters or digits" below 0xFF
199 | | JavaUnicodeChars
200 | ;
201 |
202 | // covers all characters above 0xFF which are not a surrogate
203 | // and UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF
204 | fragment JavaUnicodeChars
205 | : ~[\u0000-\u00FF\uD800-\uDBFF] {Character.isJavaIdentifierPart(_input.LA(-1))}?
206 | | [\uD800-\uDBFF] [\uDC00-\uDFFF] {Character.isJavaIdentifierPart(Character.toCodePoint((char)_input.LA(-2), (char)_input.LA(-1)))}?
207 | ;
208 |
209 |
210 | // -----------------------------------
211 | // Types
212 |
213 | fragment Boolean : 'boolean' ;
214 | fragment Byte : 'byte' ;
215 | fragment Short : 'short' ;
216 | fragment Int : 'int' ;
217 | fragment Long : 'long' ;
218 | fragment Char : 'char' ;
219 | fragment Float : 'float' ;
220 | fragment Double : 'double' ;
221 |
222 | fragment True : 'true' ;
223 | fragment False : 'false' ;
224 |
225 |
226 | // -----------------------------------
227 | // Symbols
228 |
229 | fragment Esc : '\\' ;
230 | fragment Colon : ':' ;
231 | fragment DColon : '::' ;
232 | fragment SQuote : '\'' ;
233 | fragment DQuote : '"' ;
234 | fragment BQuote : '`' ;
235 | fragment LParen : '(' ;
236 | fragment RParen : ')' ;
237 | fragment LBrace : '{' ;
238 | fragment RBrace : '}' ;
239 | fragment LBrack : '[' ;
240 | fragment RBrack : ']' ;
241 | fragment RArrow : '->' ;
242 | fragment Lt : '<' ;
243 | fragment Gt : '>' ;
244 | fragment Lte : '<=' ;
245 | fragment Gte : '>=' ;
246 | fragment Equal : '=' ;
247 | fragment NotEqual : '!=' ;
248 | fragment Question : '?' ;
249 | fragment Bang : '!' ;
250 | fragment Star : '*' ;
251 | fragment Slash : '/' ;
252 | fragment Percent : '%' ;
253 | fragment Caret : '^' ;
254 | fragment Plus : '+' ;
255 | fragment Minus : '-' ;
256 | fragment PlusAssign : '+=' ;
257 | fragment MinusAssign : '-=' ;
258 | fragment MulAssign : '*=' ;
259 | fragment DivAssign : '/=' ;
260 | fragment AndAssign : '&=' ;
261 | fragment OrAssign : '|=' ;
262 | fragment XOrAssign : '^=' ;
263 | fragment ModAssign : '%=' ;
264 | fragment LShiftAssign : '<<=' ;
265 | fragment RShiftAssign : '>>=' ;
266 | fragment URShiftAssign : '>>>=';
267 | fragment Underscore : '_' ;
268 | fragment Pipe : '|' ;
269 | fragment Amp : '&' ;
270 | fragment And : '&&' ;
271 | fragment Or : '||' ;
272 | fragment Inc : '++' ;
273 | fragment Dec : '--' ;
274 | fragment LShift : '<<' ;
275 | fragment RShift : '>>' ;
276 | fragment Dollar : '$' ;
277 | fragment Comma : ',' ;
278 | fragment Semi : ';' ;
279 | fragment Dot : '.' ;
280 | fragment Range : '..' ;
281 | fragment Ellipsis : '...' ;
282 | fragment At : '@' ;
283 | fragment Pound : '#' ;
284 | fragment Tilde : '~' ;
285 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | # This is normally unused
84 | # shellcheck disable=SC2034
85 | APP_BASE_NAME=${0##*/}
86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
88 |
89 | # Use the maximum available, or set MAX_FD != -1 to use that value.
90 | MAX_FD=maximum
91 |
92 | warn () {
93 | echo "$*"
94 | } >&2
95 |
96 | die () {
97 | echo
98 | echo "$*"
99 | echo
100 | exit 1
101 | } >&2
102 |
103 | # OS specific support (must be 'true' or 'false').
104 | cygwin=false
105 | msys=false
106 | darwin=false
107 | nonstop=false
108 | case "$( uname )" in #(
109 | CYGWIN* ) cygwin=true ;; #(
110 | Darwin* ) darwin=true ;; #(
111 | MSYS* | MINGW* ) msys=true ;; #(
112 | NONSTOP* ) nonstop=true ;;
113 | esac
114 |
115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
116 |
117 |
118 | # Determine the Java command to use to start the JVM.
119 | if [ -n "$JAVA_HOME" ] ; then
120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
121 | # IBM's JDK on AIX uses strange locations for the executables
122 | JAVACMD=$JAVA_HOME/jre/sh/java
123 | else
124 | JAVACMD=$JAVA_HOME/bin/java
125 | fi
126 | if [ ! -x "$JAVACMD" ] ; then
127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
128 |
129 | Please set the JAVA_HOME variable in your environment to match the
130 | location of your Java installation."
131 | fi
132 | else
133 | JAVACMD=java
134 | if ! command -v java >/dev/null 2>&1
135 | then
136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 | fi
142 |
143 | # Increase the maximum file descriptors if we can.
144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
145 | case $MAX_FD in #(
146 | max*)
147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
148 | # shellcheck disable=SC3045
149 | MAX_FD=$( ulimit -H -n ) ||
150 | warn "Could not query maximum file descriptor limit"
151 | esac
152 | case $MAX_FD in #(
153 | '' | soft) :;; #(
154 | *)
155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
156 | # shellcheck disable=SC3045
157 | ulimit -n "$MAX_FD" ||
158 | warn "Could not set maximum file descriptor limit to $MAX_FD"
159 | esac
160 | fi
161 |
162 | # Collect all arguments for the java command, stacking in reverse order:
163 | # * args from the command line
164 | # * the main class name
165 | # * -classpath
166 | # * -D...appname settings
167 | # * --module-path (only if needed)
168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
169 |
170 | # For Cygwin or MSYS, switch paths to Windows format before running java
171 | if "$cygwin" || "$msys" ; then
172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
174 |
175 | JAVACMD=$( cygpath --unix "$JAVACMD" )
176 |
177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
178 | for arg do
179 | if
180 | case $arg in #(
181 | -*) false ;; # don't mess with options #(
182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
183 | [ -e "$t" ] ;; #(
184 | *) false ;;
185 | esac
186 | then
187 | arg=$( cygpath --path --ignore --mixed "$arg" )
188 | fi
189 | # Roll the args list around exactly as many times as the number of
190 | # args, so each arg winds up back in the position where it started, but
191 | # possibly modified.
192 | #
193 | # NB: a `for` loop captures its iteration list before it begins, so
194 | # changing the positional parameters here affects neither the number of
195 | # iterations, nor the values presented in `arg`.
196 | shift # remove old arg
197 | set -- "$@" "$arg" # push replacement arg
198 | done
199 | fi
200 |
201 |
202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
204 |
205 | # Collect all arguments for the java command;
206 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
207 | # shell script including quotes and variable substitutions, so put them in
208 | # double quotes to make sure that they get re-expanded; and
209 | # * put everything else in single quotes, so that it's not re-expanded.
210 |
211 | set -- \
212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
213 | -classpath "$CLASSPATH" \
214 | org.gradle.wrapper.GradleWrapperMain \
215 | "$@"
216 |
217 | # Stop when "xargs" is not available.
218 | if ! command -v xargs >/dev/null 2>&1
219 | then
220 | die "xargs is not available"
221 | fi
222 |
223 | # Use "xargs" to parse quoted args.
224 | #
225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
226 | #
227 | # In Bash we could simply go:
228 | #
229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
230 | # set -- "${ARGS[@]}" "$@"
231 | #
232 | # but POSIX shell has neither arrays nor command substitution, so instead we
233 | # post-process each arg (as a line of input to sed) to backslash-escape any
234 | # character that might be a shell metacharacter, then use eval to reverse
235 | # that process (while maintaining the separation between arguments), and wrap
236 | # the whole thing up as a single "set" statement.
237 | #
238 | # This will of course break if any of these variables contains a newline or
239 | # an unmatched quote.
240 | #
241 |
242 | eval "set -- $(
243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
244 | xargs -n1 |
245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
246 | tr '\n' ' '
247 | )" '"$@"'
248 |
249 | exec "$JAVACMD" "$@"
250 |
--------------------------------------------------------------------------------
/src/main/antlr/LexUnicode.g4:
--------------------------------------------------------------------------------
1 | /*
2 | * [The "BSD license"]
3 | * Copyright (c) 2014-2015 Gerald Rosenberg
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions
8 | * are met:
9 | *
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * 3. The name of the author may not be used to endorse or promote products
16 | * derived from this software without specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 |
30 | /**
31 | * A generally reusable Unicode character set description for import in to Lexer grammars.
32 | *
33 | * Modified 2015.06.16 gbr -
34 | * -- generalized for inclusion into the ANTLRv4 grammar distribution
35 | *
36 | */
37 |
38 | lexer grammar LexUnicode;
39 |
40 | // ======================================================
41 | // Lexer fragments
42 | //
43 |
44 | fragment UnicodeLetter
45 | : UnicodeClass_LU
46 | | UnicodeClass_LL
47 | | UnicodeClass_LT
48 | | UnicodeClass_LM
49 | | UnicodeClass_LO
50 | ;
51 |
52 | fragment UnicodeClass_LU
53 | : '\u0041'..'\u005a'
54 | | '\u00c0'..'\u00d6'
55 | | '\u00d8'..'\u00de'
56 | | '\u0100'..'\u0136'
57 | | '\u0139'..'\u0147'
58 | | '\u014a'..'\u0178'
59 | | '\u0179'..'\u017d'
60 | | '\u0181'..'\u0182'
61 | | '\u0184'..'\u0186'
62 | | '\u0187'..'\u0189'
63 | | '\u018a'..'\u018b'
64 | | '\u018e'..'\u0191'
65 | | '\u0193'..'\u0194'
66 | | '\u0196'..'\u0198'
67 | | '\u019c'..'\u019d'
68 | | '\u019f'..'\u01a0'
69 | | '\u01a2'..'\u01a6'
70 | | '\u01a7'..'\u01a9'
71 | | '\u01ac'..'\u01ae'
72 | | '\u01af'..'\u01b1'
73 | | '\u01b2'..'\u01b3'
74 | | '\u01b5'..'\u01b7'
75 | | '\u01b8'..'\u01bc'
76 | | '\u01c4'..'\u01cd'
77 | | '\u01cf'..'\u01db'
78 | | '\u01de'..'\u01ee'
79 | | '\u01f1'..'\u01f4'
80 | | '\u01f6'..'\u01f8'
81 | | '\u01fa'..'\u0232'
82 | | '\u023a'..'\u023b'
83 | | '\u023d'..'\u023e'
84 | | '\u0241'..'\u0243'
85 | | '\u0244'..'\u0246'
86 | | '\u0248'..'\u024e'
87 | | '\u0370'..'\u0372'
88 | | '\u0376'..'\u037f'
89 | | '\u0386'..'\u0388'
90 | | '\u0389'..'\u038a'
91 | | '\u038c'..'\u038e'
92 | | '\u038f'..'\u0391'
93 | | '\u0392'..'\u03a1'
94 | | '\u03a3'..'\u03ab'
95 | | '\u03cf'..'\u03d2'
96 | | '\u03d3'..'\u03d4'
97 | | '\u03d8'..'\u03ee'
98 | | '\u03f4'..'\u03f7'
99 | | '\u03f9'..'\u03fa'
100 | | '\u03fd'..'\u042f'
101 | | '\u0460'..'\u0480'
102 | | '\u048a'..'\u04c0'
103 | | '\u04c1'..'\u04cd'
104 | | '\u04d0'..'\u052e'
105 | | '\u0531'..'\u0556'
106 | | '\u10a0'..'\u10c5'
107 | | '\u10c7'..'\u10cd'
108 | | '\u1e00'..'\u1e94'
109 | | '\u1e9e'..'\u1efe'
110 | | '\u1f08'..'\u1f0f'
111 | | '\u1f18'..'\u1f1d'
112 | | '\u1f28'..'\u1f2f'
113 | | '\u1f38'..'\u1f3f'
114 | | '\u1f48'..'\u1f4d'
115 | | '\u1f59'..'\u1f5f'
116 | | '\u1f68'..'\u1f6f'
117 | | '\u1fb8'..'\u1fbb'
118 | | '\u1fc8'..'\u1fcb'
119 | | '\u1fd8'..'\u1fdb'
120 | | '\u1fe8'..'\u1fec'
121 | | '\u1ff8'..'\u1ffb'
122 | | '\u2102'..'\u2107'
123 | | '\u210b'..'\u210d'
124 | | '\u2110'..'\u2112'
125 | | '\u2115'..'\u2119'
126 | | '\u211a'..'\u211d'
127 | | '\u2124'..'\u212a'
128 | | '\u212b'..'\u212d'
129 | | '\u2130'..'\u2133'
130 | | '\u213e'..'\u213f'
131 | | '\u2145'..'\u2183'
132 | | '\u2c00'..'\u2c2e'
133 | | '\u2c60'..'\u2c62'
134 | | '\u2c63'..'\u2c64'
135 | | '\u2c67'..'\u2c6d'
136 | | '\u2c6e'..'\u2c70'
137 | | '\u2c72'..'\u2c75'
138 | | '\u2c7e'..'\u2c80'
139 | | '\u2c82'..'\u2ce2'
140 | | '\u2ceb'..'\u2ced'
141 | | '\u2cf2'..'\ua640'
142 | | '\ua642'..'\ua66c'
143 | | '\ua680'..'\ua69a'
144 | | '\ua722'..'\ua72e'
145 | | '\ua732'..'\ua76e'
146 | | '\ua779'..'\ua77d'
147 | | '\ua77e'..'\ua786'
148 | | '\ua78b'..'\ua78d'
149 | | '\ua790'..'\ua792'
150 | | '\ua796'..'\ua7aa'
151 | | '\ua7ab'..'\ua7ad'
152 | | '\ua7b0'..'\ua7b1'
153 | | '\uff21'..'\uff3a'
154 | ;
155 |
156 | fragment UnicodeClass_LL
157 | : '\u0061'..'\u007A'
158 | | '\u00b5'..'\u00df'
159 | | '\u00e0'..'\u00f6'
160 | | '\u00f8'..'\u00ff'
161 | | '\u0101'..'\u0137'
162 | | '\u0138'..'\u0148'
163 | | '\u0149'..'\u0177'
164 | | '\u017a'..'\u017e'
165 | | '\u017f'..'\u0180'
166 | | '\u0183'..'\u0185'
167 | | '\u0188'..'\u018c'
168 | | '\u018d'..'\u0192'
169 | | '\u0195'..'\u0199'
170 | | '\u019a'..'\u019b'
171 | | '\u019e'..'\u01a1'
172 | | '\u01a3'..'\u01a5'
173 | | '\u01a8'..'\u01aa'
174 | | '\u01ab'..'\u01ad'
175 | | '\u01b0'..'\u01b4'
176 | | '\u01b6'..'\u01b9'
177 | | '\u01ba'..'\u01bd'
178 | | '\u01be'..'\u01bf'
179 | | '\u01c6'..'\u01cc'
180 | | '\u01ce'..'\u01dc'
181 | | '\u01dd'..'\u01ef'
182 | | '\u01f0'..'\u01f3'
183 | | '\u01f5'..'\u01f9'
184 | | '\u01fb'..'\u0233'
185 | | '\u0234'..'\u0239'
186 | | '\u023c'..'\u023f'
187 | | '\u0240'..'\u0242'
188 | | '\u0247'..'\u024f'
189 | | '\u0250'..'\u0293'
190 | | '\u0295'..'\u02af'
191 | | '\u0371'..'\u0373'
192 | | '\u0377'..'\u037b'
193 | | '\u037c'..'\u037d'
194 | | '\u0390'..'\u03ac'
195 | | '\u03ad'..'\u03ce'
196 | | '\u03d0'..'\u03d1'
197 | | '\u03d5'..'\u03d7'
198 | | '\u03d9'..'\u03ef'
199 | | '\u03f0'..'\u03f3'
200 | | '\u03f5'..'\u03fb'
201 | | '\u03fc'..'\u0430'
202 | | '\u0431'..'\u045f'
203 | | '\u0461'..'\u0481'
204 | | '\u048b'..'\u04bf'
205 | | '\u04c2'..'\u04ce'
206 | | '\u04cf'..'\u052f'
207 | | '\u0561'..'\u0587'
208 | | '\u1d00'..'\u1d2b'
209 | | '\u1d6b'..'\u1d77'
210 | | '\u1d79'..'\u1d9a'
211 | | '\u1e01'..'\u1e95'
212 | | '\u1e96'..'\u1e9d'
213 | | '\u1e9f'..'\u1eff'
214 | | '\u1f00'..'\u1f07'
215 | | '\u1f10'..'\u1f15'
216 | | '\u1f20'..'\u1f27'
217 | | '\u1f30'..'\u1f37'
218 | | '\u1f40'..'\u1f45'
219 | | '\u1f50'..'\u1f57'
220 | | '\u1f60'..'\u1f67'
221 | | '\u1f70'..'\u1f7d'
222 | | '\u1f80'..'\u1f87'
223 | | '\u1f90'..'\u1f97'
224 | | '\u1fa0'..'\u1fa7'
225 | | '\u1fb0'..'\u1fb4'
226 | | '\u1fb6'..'\u1fb7'
227 | | '\u1fbe'..'\u1fc2'
228 | | '\u1fc3'..'\u1fc4'
229 | | '\u1fc6'..'\u1fc7'
230 | | '\u1fd0'..'\u1fd3'
231 | | '\u1fd6'..'\u1fd7'
232 | | '\u1fe0'..'\u1fe7'
233 | | '\u1ff2'..'\u1ff4'
234 | | '\u1ff6'..'\u1ff7'
235 | | '\u210a'..'\u210e'
236 | | '\u210f'..'\u2113'
237 | | '\u212f'..'\u2139'
238 | | '\u213c'..'\u213d'
239 | | '\u2146'..'\u2149'
240 | | '\u214e'..'\u2184'
241 | | '\u2c30'..'\u2c5e'
242 | | '\u2c61'..'\u2c65'
243 | | '\u2c66'..'\u2c6c'
244 | | '\u2c71'..'\u2c73'
245 | | '\u2c74'..'\u2c76'
246 | | '\u2c77'..'\u2c7b'
247 | | '\u2c81'..'\u2ce3'
248 | | '\u2ce4'..'\u2cec'
249 | | '\u2cee'..'\u2cf3'
250 | | '\u2d00'..'\u2d25'
251 | | '\u2d27'..'\u2d2d'
252 | | '\ua641'..'\ua66d'
253 | | '\ua681'..'\ua69b'
254 | | '\ua723'..'\ua72f'
255 | | '\ua730'..'\ua731'
256 | | '\ua733'..'\ua771'
257 | | '\ua772'..'\ua778'
258 | | '\ua77a'..'\ua77c'
259 | | '\ua77f'..'\ua787'
260 | | '\ua78c'..'\ua78e'
261 | | '\ua791'..'\ua793'
262 | | '\ua794'..'\ua795'
263 | | '\ua797'..'\ua7a9'
264 | | '\ua7fa'..'\uab30'
265 | | '\uab31'..'\uab5a'
266 | | '\uab64'..'\uab65'
267 | | '\ufb00'..'\ufb06'
268 | | '\ufb13'..'\ufb17'
269 | | '\uff41'..'\uff5a'
270 | ;
271 |
272 | fragment UnicodeClass_LT
273 | : '\u01c5'..'\u01cb'
274 | | '\u01f2'..'\u1f88'
275 | | '\u1f89'..'\u1f8f'
276 | | '\u1f98'..'\u1f9f'
277 | | '\u1fa8'..'\u1faf'
278 | | '\u1fbc'..'\u1fcc'
279 | | '\u1ffc'..'\u1ffc'
280 | ;
281 |
282 | fragment UnicodeClass_LM
283 | : '\u02b0'..'\u02c1'
284 | | '\u02c6'..'\u02d1'
285 | | '\u02e0'..'\u02e4'
286 | | '\u02ec'..'\u02ee'
287 | | '\u0374'..'\u037a'
288 | | '\u0559'..'\u0640'
289 | | '\u06e5'..'\u06e6'
290 | | '\u07f4'..'\u07f5'
291 | | '\u07fa'..'\u081a'
292 | | '\u0824'..'\u0828'
293 | | '\u0971'..'\u0e46'
294 | | '\u0ec6'..'\u10fc'
295 | | '\u17d7'..'\u1843'
296 | | '\u1aa7'..'\u1c78'
297 | | '\u1c79'..'\u1c7d'
298 | | '\u1d2c'..'\u1d6a'
299 | | '\u1d78'..'\u1d9b'
300 | | '\u1d9c'..'\u1dbf'
301 | | '\u2071'..'\u207f'
302 | | '\u2090'..'\u209c'
303 | | '\u2c7c'..'\u2c7d'
304 | | '\u2d6f'..'\u2e2f'
305 | | '\u3005'..'\u3031'
306 | | '\u3032'..'\u3035'
307 | | '\u303b'..'\u309d'
308 | | '\u309e'..'\u30fc'
309 | | '\u30fd'..'\u30fe'
310 | | '\ua015'..'\ua4f8'
311 | | '\ua4f9'..'\ua4fd'
312 | | '\ua60c'..'\ua67f'
313 | | '\ua69c'..'\ua69d'
314 | | '\ua717'..'\ua71f'
315 | | '\ua770'..'\ua788'
316 | | '\ua7f8'..'\ua7f9'
317 | | '\ua9cf'..'\ua9e6'
318 | | '\uaa70'..'\uaadd'
319 | | '\uaaf3'..'\uaaf4'
320 | | '\uab5c'..'\uab5f'
321 | | '\uff70'..'\uff9e'
322 | | '\uff9f'..'\uff9f'
323 | ;
324 |
325 | fragment UnicodeClass_LO
326 | : '\u00aa'..'\u00ba'
327 | | '\u01bb'..'\u01c0'
328 | | '\u01c1'..'\u01c3'
329 | | '\u0294'..'\u05d0'
330 | | '\u05d1'..'\u05ea'
331 | | '\u05f0'..'\u05f2'
332 | | '\u0620'..'\u063f'
333 | | '\u0641'..'\u064a'
334 | | '\u066e'..'\u066f'
335 | | '\u0671'..'\u06d3'
336 | | '\u06d5'..'\u06ee'
337 | | '\u06ef'..'\u06fa'
338 | | '\u06fb'..'\u06fc'
339 | | '\u06ff'..'\u0710'
340 | | '\u0712'..'\u072f'
341 | | '\u074d'..'\u07a5'
342 | | '\u07b1'..'\u07ca'
343 | | '\u07cb'..'\u07ea'
344 | | '\u0800'..'\u0815'
345 | | '\u0840'..'\u0858'
346 | | '\u08a0'..'\u08b2'
347 | | '\u0904'..'\u0939'
348 | | '\u093d'..'\u0950'
349 | | '\u0958'..'\u0961'
350 | | '\u0972'..'\u0980'
351 | | '\u0985'..'\u098c'
352 | | '\u098f'..'\u0990'
353 | | '\u0993'..'\u09a8'
354 | | '\u09aa'..'\u09b0'
355 | | '\u09b2'..'\u09b6'
356 | | '\u09b7'..'\u09b9'
357 | | '\u09bd'..'\u09ce'
358 | | '\u09dc'..'\u09dd'
359 | | '\u09df'..'\u09e1'
360 | | '\u09f0'..'\u09f1'
361 | | '\u0a05'..'\u0a0a'
362 | | '\u0a0f'..'\u0a10'
363 | | '\u0a13'..'\u0a28'
364 | | '\u0a2a'..'\u0a30'
365 | | '\u0a32'..'\u0a33'
366 | | '\u0a35'..'\u0a36'
367 | | '\u0a38'..'\u0a39'
368 | | '\u0a59'..'\u0a5c'
369 | | '\u0a5e'..'\u0a72'
370 | | '\u0a73'..'\u0a74'
371 | | '\u0a85'..'\u0a8d'
372 | | '\u0a8f'..'\u0a91'
373 | | '\u0a93'..'\u0aa8'
374 | | '\u0aaa'..'\u0ab0'
375 | | '\u0ab2'..'\u0ab3'
376 | | '\u0ab5'..'\u0ab9'
377 | | '\u0abd'..'\u0ad0'
378 | | '\u0ae0'..'\u0ae1'
379 | | '\u0b05'..'\u0b0c'
380 | | '\u0b0f'..'\u0b10'
381 | | '\u0b13'..'\u0b28'
382 | | '\u0b2a'..'\u0b30'
383 | | '\u0b32'..'\u0b33'
384 | | '\u0b35'..'\u0b39'
385 | | '\u0b3d'..'\u0b5c'
386 | | '\u0b5d'..'\u0b5f'
387 | | '\u0b60'..'\u0b61'
388 | | '\u0b71'..'\u0b83'
389 | | '\u0b85'..'\u0b8a'
390 | | '\u0b8e'..'\u0b90'
391 | | '\u0b92'..'\u0b95'
392 | | '\u0b99'..'\u0b9a'
393 | | '\u0b9c'..'\u0b9e'
394 | | '\u0b9f'..'\u0ba3'
395 | | '\u0ba4'..'\u0ba8'
396 | | '\u0ba9'..'\u0baa'
397 | | '\u0bae'..'\u0bb9'
398 | | '\u0bd0'..'\u0c05'
399 | | '\u0c06'..'\u0c0c'
400 | | '\u0c0e'..'\u0c10'
401 | | '\u0c12'..'\u0c28'
402 | | '\u0c2a'..'\u0c39'
403 | | '\u0c3d'..'\u0c58'
404 | | '\u0c59'..'\u0c60'
405 | | '\u0c61'..'\u0c85'
406 | | '\u0c86'..'\u0c8c'
407 | | '\u0c8e'..'\u0c90'
408 | | '\u0c92'..'\u0ca8'
409 | | '\u0caa'..'\u0cb3'
410 | | '\u0cb5'..'\u0cb9'
411 | | '\u0cbd'..'\u0cde'
412 | | '\u0ce0'..'\u0ce1'
413 | | '\u0cf1'..'\u0cf2'
414 | | '\u0d05'..'\u0d0c'
415 | | '\u0d0e'..'\u0d10'
416 | | '\u0d12'..'\u0d3a'
417 | | '\u0d3d'..'\u0d4e'
418 | | '\u0d60'..'\u0d61'
419 | | '\u0d7a'..'\u0d7f'
420 | | '\u0d85'..'\u0d96'
421 | | '\u0d9a'..'\u0db1'
422 | | '\u0db3'..'\u0dbb'
423 | | '\u0dbd'..'\u0dc0'
424 | | '\u0dc1'..'\u0dc6'
425 | | '\u0e01'..'\u0e30'
426 | | '\u0e32'..'\u0e33'
427 | | '\u0e40'..'\u0e45'
428 | | '\u0e81'..'\u0e82'
429 | | '\u0e84'..'\u0e87'
430 | | '\u0e88'..'\u0e8a'
431 | | '\u0e8d'..'\u0e94'
432 | | '\u0e95'..'\u0e97'
433 | | '\u0e99'..'\u0e9f'
434 | | '\u0ea1'..'\u0ea3'
435 | | '\u0ea5'..'\u0ea7'
436 | | '\u0eaa'..'\u0eab'
437 | | '\u0ead'..'\u0eb0'
438 | | '\u0eb2'..'\u0eb3'
439 | | '\u0ebd'..'\u0ec0'
440 | | '\u0ec1'..'\u0ec4'
441 | | '\u0edc'..'\u0edf'
442 | | '\u0f00'..'\u0f40'
443 | | '\u0f41'..'\u0f47'
444 | | '\u0f49'..'\u0f6c'
445 | | '\u0f88'..'\u0f8c'
446 | | '\u1000'..'\u102a'
447 | | '\u103f'..'\u1050'
448 | | '\u1051'..'\u1055'
449 | | '\u105a'..'\u105d'
450 | | '\u1061'..'\u1065'
451 | | '\u1066'..'\u106e'
452 | | '\u106f'..'\u1070'
453 | | '\u1075'..'\u1081'
454 | | '\u108e'..'\u10d0'
455 | | '\u10d1'..'\u10fa'
456 | | '\u10fd'..'\u1248'
457 | | '\u124a'..'\u124d'
458 | | '\u1250'..'\u1256'
459 | | '\u1258'..'\u125a'
460 | | '\u125b'..'\u125d'
461 | | '\u1260'..'\u1288'
462 | | '\u128a'..'\u128d'
463 | | '\u1290'..'\u12b0'
464 | | '\u12b2'..'\u12b5'
465 | | '\u12b8'..'\u12be'
466 | | '\u12c0'..'\u12c2'
467 | | '\u12c3'..'\u12c5'
468 | | '\u12c8'..'\u12d6'
469 | | '\u12d8'..'\u1310'
470 | | '\u1312'..'\u1315'
471 | | '\u1318'..'\u135a'
472 | | '\u1380'..'\u138f'
473 | | '\u13a0'..'\u13f4'
474 | | '\u1401'..'\u166c'
475 | | '\u166f'..'\u167f'
476 | | '\u1681'..'\u169a'
477 | | '\u16a0'..'\u16ea'
478 | | '\u16f1'..'\u16f8'
479 | | '\u1700'..'\u170c'
480 | | '\u170e'..'\u1711'
481 | | '\u1720'..'\u1731'
482 | | '\u1740'..'\u1751'
483 | | '\u1760'..'\u176c'
484 | | '\u176e'..'\u1770'
485 | | '\u1780'..'\u17b3'
486 | | '\u17dc'..'\u1820'
487 | | '\u1821'..'\u1842'
488 | | '\u1844'..'\u1877'
489 | | '\u1880'..'\u18a8'
490 | | '\u18aa'..'\u18b0'
491 | | '\u18b1'..'\u18f5'
492 | | '\u1900'..'\u191e'
493 | | '\u1950'..'\u196d'
494 | | '\u1970'..'\u1974'
495 | | '\u1980'..'\u19ab'
496 | | '\u19c1'..'\u19c7'
497 | | '\u1a00'..'\u1a16'
498 | | '\u1a20'..'\u1a54'
499 | | '\u1b05'..'\u1b33'
500 | | '\u1b45'..'\u1b4b'
501 | | '\u1b83'..'\u1ba0'
502 | | '\u1bae'..'\u1baf'
503 | | '\u1bba'..'\u1be5'
504 | | '\u1c00'..'\u1c23'
505 | | '\u1c4d'..'\u1c4f'
506 | | '\u1c5a'..'\u1c77'
507 | | '\u1ce9'..'\u1cec'
508 | | '\u1cee'..'\u1cf1'
509 | | '\u1cf5'..'\u1cf6'
510 | | '\u2135'..'\u2138'
511 | | '\u2d30'..'\u2d67'
512 | | '\u2d80'..'\u2d96'
513 | | '\u2da0'..'\u2da6'
514 | | '\u2da8'..'\u2dae'
515 | | '\u2db0'..'\u2db6'
516 | | '\u2db8'..'\u2dbe'
517 | | '\u2dc0'..'\u2dc6'
518 | | '\u2dc8'..'\u2dce'
519 | | '\u2dd0'..'\u2dd6'
520 | | '\u2dd8'..'\u2dde'
521 | | '\u3006'..'\u303c'
522 | | '\u3041'..'\u3096'
523 | | '\u309f'..'\u30a1'
524 | | '\u30a2'..'\u30fa'
525 | | '\u30ff'..'\u3105'
526 | | '\u3106'..'\u312d'
527 | | '\u3131'..'\u318e'
528 | | '\u31a0'..'\u31ba'
529 | | '\u31f0'..'\u31ff'
530 | | '\u3400'..'\u4db5'
531 | | '\u4e00'..'\u9fcc'
532 | | '\ua000'..'\ua014'
533 | | '\ua016'..'\ua48c'
534 | | '\ua4d0'..'\ua4f7'
535 | | '\ua500'..'\ua60b'
536 | | '\ua610'..'\ua61f'
537 | | '\ua62a'..'\ua62b'
538 | | '\ua66e'..'\ua6a0'
539 | | '\ua6a1'..'\ua6e5'
540 | | '\ua7f7'..'\ua7fb'
541 | | '\ua7fc'..'\ua801'
542 | | '\ua803'..'\ua805'
543 | | '\ua807'..'\ua80a'
544 | | '\ua80c'..'\ua822'
545 | | '\ua840'..'\ua873'
546 | | '\ua882'..'\ua8b3'
547 | | '\ua8f2'..'\ua8f7'
548 | | '\ua8fb'..'\ua90a'
549 | | '\ua90b'..'\ua925'
550 | | '\ua930'..'\ua946'
551 | | '\ua960'..'\ua97c'
552 | | '\ua984'..'\ua9b2'
553 | | '\ua9e0'..'\ua9e4'
554 | | '\ua9e7'..'\ua9ef'
555 | | '\ua9fa'..'\ua9fe'
556 | | '\uaa00'..'\uaa28'
557 | | '\uaa40'..'\uaa42'
558 | | '\uaa44'..'\uaa4b'
559 | | '\uaa60'..'\uaa6f'
560 | | '\uaa71'..'\uaa76'
561 | | '\uaa7a'..'\uaa7e'
562 | | '\uaa7f'..'\uaaaf'
563 | | '\uaab1'..'\uaab5'
564 | | '\uaab6'..'\uaab9'
565 | | '\uaaba'..'\uaabd'
566 | | '\uaac0'..'\uaac2'
567 | | '\uaadb'..'\uaadc'
568 | | '\uaae0'..'\uaaea'
569 | | '\uaaf2'..'\uab01'
570 | | '\uab02'..'\uab06'
571 | | '\uab09'..'\uab0e'
572 | | '\uab11'..'\uab16'
573 | | '\uab20'..'\uab26'
574 | | '\uab28'..'\uab2e'
575 | | '\uabc0'..'\uabe2'
576 | | '\uac00'..'\ud7a3'
577 | | '\ud7b0'..'\ud7c6'
578 | | '\ud7cb'..'\ud7fb'
579 | | '\uf900'..'\ufa6d'
580 | | '\ufa70'..'\ufad9'
581 | | '\ufb1d'..'\ufb1f'
582 | | '\ufb20'..'\ufb28'
583 | | '\ufb2a'..'\ufb36'
584 | | '\ufb38'..'\ufb3c'
585 | | '\ufb3e'..'\ufb40'
586 | | '\ufb41'..'\ufb43'
587 | | '\ufb44'..'\ufb46'
588 | | '\ufb47'..'\ufbb1'
589 | | '\ufbd3'..'\ufd3d'
590 | | '\ufd50'..'\ufd8f'
591 | | '\ufd92'..'\ufdc7'
592 | | '\ufdf0'..'\ufdfb'
593 | | '\ufe70'..'\ufe74'
594 | | '\ufe76'..'\ufefc'
595 | | '\uff66'..'\uff6f'
596 | | '\uff71'..'\uff9d'
597 | | '\uffa0'..'\uffbe'
598 | | '\uffc2'..'\uffc7'
599 | | '\uffca'..'\uffcf'
600 | | '\uffd2'..'\uffd7'
601 | | '\uffda'..'\uffdc'
602 | ;
603 |
604 | fragment UnicodeDigit // UnicodeClass_ND
605 | : '\u0030'..'\u0039'
606 | | '\u0660'..'\u0669'
607 | | '\u06f0'..'\u06f9'
608 | | '\u07c0'..'\u07c9'
609 | | '\u0966'..'\u096f'
610 | | '\u09e6'..'\u09ef'
611 | | '\u0a66'..'\u0a6f'
612 | | '\u0ae6'..'\u0aef'
613 | | '\u0b66'..'\u0b6f'
614 | | '\u0be6'..'\u0bef'
615 | | '\u0c66'..'\u0c6f'
616 | | '\u0ce6'..'\u0cef'
617 | | '\u0d66'..'\u0d6f'
618 | | '\u0de6'..'\u0def'
619 | | '\u0e50'..'\u0e59'
620 | | '\u0ed0'..'\u0ed9'
621 | | '\u0f20'..'\u0f29'
622 | | '\u1040'..'\u1049'
623 | | '\u1090'..'\u1099'
624 | | '\u17e0'..'\u17e9'
625 | | '\u1810'..'\u1819'
626 | | '\u1946'..'\u194f'
627 | | '\u19d0'..'\u19d9'
628 | | '\u1a80'..'\u1a89'
629 | | '\u1a90'..'\u1a99'
630 | | '\u1b50'..'\u1b59'
631 | | '\u1bb0'..'\u1bb9'
632 | | '\u1c40'..'\u1c49'
633 | | '\u1c50'..'\u1c59'
634 | | '\ua620'..'\ua629'
635 | | '\ua8d0'..'\ua8d9'
636 | | '\ua900'..'\ua909'
637 | | '\ua9d0'..'\ua9d9'
638 | | '\ua9f0'..'\ua9f9'
639 | | '\uaa50'..'\uaa59'
640 | | '\uabf0'..'\uabf9'
641 | | '\uff10'..'\uff19'
642 | ;
643 |
--------------------------------------------------------------------------------