From 932a89fe0397b92874645fcb003d78e57b64dd8c Mon Sep 17 00:00:00 2001 From: azerr Date: Tue, 13 Jun 2023 08:00:30 +0200 Subject: [PATCH] Improve completion Signed-off-by: azerr --- .../lsp4ij/internal/SupportedFeatures.java | 24 +- .../completion/LSPCompletionConfidence.java | 15 ++ .../intellij/qute/lang/QuteASTNode.java | 17 +- .../intellij/qute/lang/QuteFileType.java | 4 + .../qute/lang/QuteFileViewProvider.java | 30 ++- .../lang/QuteFileViewProviderFactory.java | 9 +- .../intellij/qute/lang/QuteLanguage.java | 5 + .../qute/lang/QuteLanguageSubstitutor.java | 14 +- .../intellij/qute/lang/QuteLexer.java | 98 -------- .../qute/lang/QuteParserDefinition.java | 14 +- .../intellij/qute/lang/QuteToken.java | 42 ++++ .../highlighter/QuteEditorHighlighter.java | 27 ++ .../QuteEditorHighlighterProvider.java | 17 ++ .../highlighter/QuteSyntaxHighlighter.java | 42 ++++ .../QuteSyntaxHighlighterFactory.java | 13 + .../intellij/qute/lang/psi/QuteLexer.java | 231 ++++++++++++++++++ .../qute/lang/{ => psi}/QuteParser.java | 30 ++- .../intellij/qute/lang/psi/QuteParsing.java | 129 ++++++++++ .../qute/lang/{ => psi}/QutePsiFile.java | 7 +- .../lang/{ => psi/tree}/QuteElementType.java | 3 +- .../lang/{ => psi/tree}/QuteElementTypes.java | 20 +- .../lang/psi/tree/QutePsiElementFactory.java | 11 + .../qute/lang/psi/tree/QuteTokenType.java | 32 +++ src/main/resources/META-INF/lsp4ij-qute.xml | 1 + src/main/resources/META-INF/plugin.xml | 2 + 25 files changed, 684 insertions(+), 153 deletions(-) create mode 100644 src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/completion/LSPCompletionConfidence.java delete mode 100644 src/main/java/com/redhat/devtools/intellij/qute/lang/QuteLexer.java create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/lang/QuteToken.java create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteEditorHighlighter.java create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteEditorHighlighterProvider.java create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteSyntaxHighlighter.java create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteSyntaxHighlighterFactory.java create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QuteLexer.java rename src/main/java/com/redhat/devtools/intellij/qute/lang/{ => psi}/QuteParser.java (63%) create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QuteParsing.java rename src/main/java/com/redhat/devtools/intellij/qute/lang/{ => psi}/QutePsiFile.java (82%) rename src/main/java/com/redhat/devtools/intellij/qute/lang/{ => psi/tree}/QuteElementType.java (88%) rename src/main/java/com/redhat/devtools/intellij/qute/lang/{ => psi/tree}/QuteElementTypes.java (75%) create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QutePsiElementFactory.java create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QuteTokenType.java diff --git a/src/main/java/com/redhat/devtools/intellij/lsp4ij/internal/SupportedFeatures.java b/src/main/java/com/redhat/devtools/intellij/lsp4ij/internal/SupportedFeatures.java index deea74ff8..24fa8c63e 100644 --- a/src/main/java/com/redhat/devtools/intellij/lsp4ij/internal/SupportedFeatures.java +++ b/src/main/java/com/redhat/devtools/intellij/lsp4ij/internal/SupportedFeatures.java @@ -78,11 +78,11 @@ public class SupportedFeatures { textDocumentClientCapabilities.setInlayHint(new InlayHintCapabilities()); // TODO : support textDocument/colorPresentation // textDocumentClientCapabilities.setColorProvider(new ColorProviderCapabilities()); - final var completionItemCapabilities = new CompletionItemCapabilities(Boolean.TRUE); + final var completionItemCapabilities = new CompletionItemCapabilities(Boolean.FALSE); completionItemCapabilities .setDocumentationFormat(Arrays.asList(MarkupKind.MARKDOWN, MarkupKind.PLAINTEXT)); - completionItemCapabilities.setInsertTextModeSupport(new CompletionItemInsertTextModeSupportCapabilities(List.of(InsertTextMode.AsIs, InsertTextMode.AdjustIndentation))); - completionItemCapabilities.setResolveSupport(new CompletionItemResolveSupportCapabilities(List.of("documentation", "detail", "additionalTextEdits"))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + // completionItemCapabilities.setInsertTextModeSupport(new CompletionItemInsertTextModeSupportCapabilities(List.of(InsertTextMode.AsIs, InsertTextMode.AdjustIndentation))); + // completionItemCapabilities.setResolveSupport(new CompletionItemResolveSupportCapabilities(List.of("documentation", "detail", "additionalTextEdits"))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ textDocumentClientCapabilities.setCompletion(new CompletionCapabilities(completionItemCapabilities)); final var definitionCapabilities = new DefinitionCapabilities(); definitionCapabilities.setLinkSupport(Boolean.TRUE); @@ -115,11 +115,13 @@ public class SupportedFeatures { textDocumentClientCapabilities.setOnTypeFormatting(null); // TODO // TODO : support textDocument/rangeFormatting // textDocumentClientCapabilities.setRangeFormatting(new RangeFormattingCapabilities()); - textDocumentClientCapabilities.setReferences(new ReferencesCapabilities()); - final var renameCapabilities = new RenameCapabilities(); - renameCapabilities.setPrepareSupport(true); - textDocumentClientCapabilities.setRename(renameCapabilities); - // TODO + // TODO : support textDocument/references + // textDocumentClientCapabilities.setReferences(new ReferencesCapabilities()); + // TODO : support textDocument/rename + //final var renameCapabilities = new RenameCapabilities(); + //renameCapabilities.setPrepareSupport(true); + //textDocumentClientCapabilities.setRename(renameCapabilities); + // TODO : support textDocument/signatureHelp // textDocumentClientCapabilities.setSignatureHelp(new SignatureHelpCapabilities()); textDocumentClientCapabilities .setSynchronization(new SynchronizationCapabilities(Boolean.TRUE, Boolean.TRUE, Boolean.TRUE)); @@ -151,9 +153,9 @@ public class SupportedFeatures { public static WindowClientCapabilities getWindowClientCapabilities() { final var windowClientCapabilities = new WindowClientCapabilities(); - windowClientCapabilities.setShowDocument(new ShowDocumentCapabilities(true)); - windowClientCapabilities.setWorkDoneProgress(true); - windowClientCapabilities.setShowMessage(new WindowShowMessageRequestCapabilities()); + //windowClientCapabilities.setShowDocument(new ShowDocumentCapabilities(true)); + //windowClientCapabilities.setWorkDoneProgress(true); + //windowClientCapabilities.setShowMessage(new WindowShowMessageRequestCapabilities()); return windowClientCapabilities; } diff --git a/src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/completion/LSPCompletionConfidence.java b/src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/completion/LSPCompletionConfidence.java new file mode 100644 index 000000000..81307a0b9 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/completion/LSPCompletionConfidence.java @@ -0,0 +1,15 @@ +package com.redhat.devtools.intellij.lsp4ij.operations.completion; + +import com.intellij.codeInsight.completion.CompletionConfidence; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.util.ThreeState; +import org.jetbrains.annotations.NotNull; + +public class LSPCompletionConfidence extends CompletionConfidence { + + @Override + public @NotNull ThreeState shouldSkipAutopopup(@NotNull PsiElement contextElement, @NotNull PsiFile psiFile, int offset) { + return ThreeState.NO; + } +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteASTNode.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteASTNode.java index 011336178..0ff6a9764 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteASTNode.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteASTNode.java @@ -11,10 +11,12 @@ package com.redhat.devtools.intellij.qute.lang; import com.intellij.psi.impl.source.tree.CompositeElement; -import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.impl.source.tree.TreeElement; +import com.intellij.psi.templateLanguages.OuterLanguageElementImpl; +import com.redhat.devtools.intellij.qute.lang.psi.tree.QuteElementTypes; import com.redhat.qute.parser.template.ASTVisitor; import com.redhat.qute.parser.template.Node; +import com.redhat.qute.parser.template.NodeKind; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -29,19 +31,26 @@ public QuteASTNode(Node node) { int end = node.getStart(); for(Node child : getChildren(node)) { if (end != -1 && end < child.getStart()) { - rawAddChildrenWithoutNotifications(new LeafPsiElement(QuteElementTypes.QUTE_TEXT, child.getOwnerTemplate().getText(end, child.getStart()))); + rawAddChildrenWithoutNotifications(new QuteToken(QuteElementTypes.QUTE_TEXT, child.getOwnerTemplate().getText(end, child.getStart()))); } rawAddChildrenWithoutNotifications(getNode(child)); end = child.getEnd(); } if (end < node.getEnd()) { - rawAddChildrenWithoutNotifications(new LeafPsiElement(QuteElementTypes.QUTE_CONTENT, node.getOwnerTemplate().getText(end, node.getEnd()))); + rawAddChildrenWithoutNotifications(new QuteToken(QuteElementTypes.QUTE_CONTENT, node.getOwnerTemplate().getText(end, node.getEnd()))); } } @NotNull public static TreeElement getNode(Node child) { - return getChildren(child).isEmpty()?new LeafPsiElement(QuteElementTypes.fromNode(child), child.getOwnerTemplate().getText(child.getStart(), child.getEnd())):new QuteASTNode(child); + if (child.getKind() == NodeKind.Text) { + return new OuterLanguageElementImpl(QuteElementTypes.fromNode(child), child.getOwnerTemplate().getText(child.getStart(), child.getEnd())); + } + if (child.getKind() == NodeKind.ExpressionPart) { + + } + return getChildren(child).isEmpty()?new QuteToken(QuteElementTypes.fromNode(child), child.getOwnerTemplate().getText(child.getStart(), child.getEnd())) + :new QuteASTNode(child); } private static List getChildren(Node node) { diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteFileType.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteFileType.java index 455011a38..3d175ab24 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteFileType.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteFileType.java @@ -32,9 +32,13 @@ import javax.swing.Icon; +/** + * Qute language file type. + */ public class QuteFileType extends LanguageFileType { private static final Icon QUARKUS_ICON = IconLoader.findIcon("/quarkus_icon_rgb_16px_default.png", QuarkusIconProvider.class); + @NotNull public static final QuteFileType QUTE = new QuteFileType(); private QuteFileType() { diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteFileViewProvider.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteFileViewProvider.java index 5cb510550..2cb6a6ee9 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteFileViewProvider.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteFileViewProvider.java @@ -13,6 +13,9 @@ import com.intellij.lang.Language; import com.intellij.lang.LanguageParserDefinitions; import com.intellij.lang.ParserDefinition; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.MultiplePsiFilesPerDocumentFileViewProvider; import com.intellij.psi.PsiFile; @@ -20,22 +23,41 @@ import com.intellij.psi.impl.source.PsiFileImpl; import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider; import com.intellij.psi.tree.IElementType; +import com.redhat.devtools.intellij.qute.lang.psi.tree.QuteElementTypes; import org.jetbrains.annotations.NotNull; -import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; +/** + * Qute file view provider. + */ public class QuteFileViewProvider extends MultiplePsiFilesPerDocumentFileViewProvider implements TemplateLanguageFileViewProvider { private final Language language; private final Language templateLanguage; - public QuteFileViewProvider(VirtualFile file, Language language, Language templateLanguage, PsiManager manager, boolean eventSystemEnabled) { + public QuteFileViewProvider(VirtualFile file, Language language, PsiManager manager, boolean eventSystemEnabled) { + this(file, language, getTemplateLanguage(file), manager, eventSystemEnabled); + } + + private QuteFileViewProvider(VirtualFile file, Language language, Language templateLanguage, PsiManager manager, boolean eventSystemEnabled) { super(manager, file, eventSystemEnabled); this.language = language; this.templateLanguage = templateLanguage; } + /** + * Returns the template language of the given file (ex : "HTML", "YAML", language etc) and the "Qute_" language otherwise. + * + * @param file the virtual file. + * + * @return the template language of the given file (ex : "HTML", "YAML", language etc) and the "Qute_" language otherwise. + */ + public static Language getTemplateLanguage(VirtualFile file) { + FileType fileType = FileTypeManager.getInstance().getFileTypeByExtension(file.getExtension()); + return fileType instanceof LanguageFileType ? ((LanguageFileType) fileType).getLanguage() : QuteLanguage.INSTANCE; + } + protected PsiFile createFile(@NotNull Language lang) { if (lang == getTemplateDataLanguage()) { final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(lang); @@ -58,8 +80,8 @@ protected PsiFile createFile(@NotNull Language lang) { @Override public @NotNull Set getLanguages() { Set languages = new LinkedHashSet<>(); - languages.add(getTemplateDataLanguage()); languages.add(getBaseLanguage()); + languages.add(getTemplateDataLanguage()); return languages; } @@ -70,7 +92,7 @@ protected PsiFile createFile(@NotNull Language lang) { @Override public IElementType getContentElementType(@NotNull Language language) { - return language == getTemplateDataLanguage()?QuteElementTypes.QUTE_FILE_DATA:null; + return language == getTemplateDataLanguage() ? QuteElementTypes.QUTE_FILE_DATA : null; } @Override diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteFileViewProviderFactory.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteFileViewProviderFactory.java index 8a484fe1a..cd1def295 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteFileViewProviderFactory.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteFileViewProviderFactory.java @@ -11,19 +11,18 @@ package com.redhat.devtools.intellij.qute.lang; import com.intellij.lang.Language; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.FileTypeManager; -import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.FileViewProvider; import com.intellij.psi.FileViewProviderFactory; import com.intellij.psi.PsiManager; import org.jetbrains.annotations.NotNull; +/** + * Qute file view provider factory. + */ public class QuteFileViewProviderFactory implements FileViewProviderFactory { @Override public @NotNull FileViewProvider createFileViewProvider(@NotNull VirtualFile file, Language language, @NotNull PsiManager manager, boolean eventSystemEnabled) { - FileType fileType = FileTypeManager.getInstance().getFileTypeByExtension(file.getExtension()); - return new QuteFileViewProvider(file, language, fileType instanceof LanguageFileType?((LanguageFileType) fileType).getLanguage():language, manager, eventSystemEnabled); + return new QuteFileViewProvider(file, language, manager, eventSystemEnabled); } } diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteLanguage.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteLanguage.java index ffccfb105..97f0ea97a 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteLanguage.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteLanguage.java @@ -16,7 +16,12 @@ import com.intellij.psi.templateLanguages.TemplateLanguage; import org.jetbrains.annotations.NotNull; +/** + * Qute language. + */ public class QuteLanguage extends Language implements TemplateLanguage, InjectableLanguage { + + @NotNull public static final QuteLanguage INSTANCE = new QuteLanguage(); private QuteLanguage() { diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteLanguageSubstitutor.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteLanguageSubstitutor.java index f37d1892d..6769bb165 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteLanguageSubstitutor.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteLanguageSubstitutor.java @@ -11,8 +11,6 @@ package com.redhat.devtools.intellij.qute.lang; import com.intellij.lang.Language; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.FileTypeRegistry; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleUtilCore; @@ -27,7 +25,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; - +/** + * Qute language substitutor to force some language file (ex:HTML, YAML, etc) to "_Qute" language when: + *
    + *
  • the HTML, YAML, etc file is hosted in a Qute project.
  • + *
  • the HTML, YAML, etc file is hosted in the src/main/resources/templates folder.
  • + *
+ */ public class QuteLanguageSubstitutor extends LanguageSubstitutor { protected boolean isTemplate(VirtualFile file, Module module) { return file.getPath().contains("templates") && ModuleRootManager.getInstance(module).getFileIndex().isInSourceContent(file); @@ -51,8 +55,8 @@ public static boolean isQuteLibrary(@NotNull LibraryOrderEntry libraryOrderEntry } private Module findModule(VirtualFile file) { - for(Project project : ProjectManager.getInstance().getOpenProjects()) { - for(Module module : ModuleManager.getInstance(project).getModules()) { + for (Project project : ProjectManager.getInstance().getOpenProjects()) { + for (Module module : ModuleManager.getInstance(project).getModules()) { if (ModuleUtilCore.moduleContainsFile(module, file, false)) { return module; } diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteLexer.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteLexer.java deleted file mode 100644 index a5e19e233..000000000 --- a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteLexer.java +++ /dev/null @@ -1,98 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2022 Red Hat, Inc. - * Distributed under license by Red Hat, Inc. All rights reserved. - * This program is made available under the terms of the - * Eclipse Public License v2.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v20.html - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - ******************************************************************************/ -package com.redhat.devtools.intellij.qute.lang; - -import com.intellij.lexer.Lexer; -import com.intellij.lexer.LexerPosition; -import com.intellij.psi.tree.IElementType; -import com.redhat.qute.parser.template.Node; -import com.redhat.qute.parser.template.Template; -import com.redhat.qute.parser.template.TemplateParser; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class QuteLexer extends Lexer { - Template template; - private CharSequence buffer; - private int endOffset; - - private int index; - - @Override - public void start(@NotNull CharSequence buffer, int startOffset, int endOffset, int initialState) { - this.buffer = buffer; - this.endOffset = endOffset; - template = TemplateParser.parse(buffer.subSequence(startOffset, endOffset).toString(), ""); - this.index = initialState; - } - - @Override - public int getState() { - return index; - } - - private Node getToken() { - return index< template.getChildCount()?template.getChild(index):null; - } - @Override - public @Nullable IElementType getTokenType() { - Node node = getToken(); - return node!=null?QuteElementTypes.fromNode(node):null; - } - - @Override - public int getTokenStart() { - Node node = getToken(); - return node!=null?node.getStart():-1; - } - - @Override - public int getTokenEnd() { - Node node = getToken(); - return node!=null?node.getEnd():-1; - - } - - @Override - public void advance() { - ++index; - } - - @Override - public @NotNull LexerPosition getCurrentPosition() { - return new LexerPosition() { - @Override - public int getOffset() { - return getTokenStart(); - } - - @Override - public int getState() { - return getState(); - } - }; - } - - @Override - public void restore(@NotNull LexerPosition position) { - index = position.getState(); - } - - @Override - public @NotNull CharSequence getBufferSequence() { - return buffer; - } - - @Override - public int getBufferEnd() { - return endOffset; - } -} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteParserDefinition.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteParserDefinition.java index 91ce0c345..f0e0f8682 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteParserDefinition.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteParserDefinition.java @@ -10,7 +10,6 @@ ******************************************************************************/ package com.redhat.devtools.intellij.qute.lang; -import com.intellij.extapi.psi.ASTWrapperPsiElement; import com.intellij.lang.ASTNode; import com.intellij.lang.ParserDefinition; import com.intellij.lang.PsiParser; @@ -21,9 +20,18 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.tree.IFileElementType; import com.intellij.psi.tree.TokenSet; +import com.redhat.devtools.intellij.qute.lang.psi.QuteLexer; +import com.redhat.devtools.intellij.qute.lang.psi.QuteParser; +import com.redhat.devtools.intellij.qute.lang.psi.QutePsiFile; +import com.redhat.devtools.intellij.qute.lang.psi.tree.QuteElementTypes; +import com.redhat.devtools.intellij.qute.lang.psi.tree.QutePsiElementFactory; import org.jetbrains.annotations.NotNull; +/** + * Qute parser definition. + */ public class QuteParserDefinition implements ParserDefinition { + @Override public @NotNull Lexer createLexer(Project project) { return new QuteLexer(); @@ -41,7 +49,7 @@ public IFileElementType getFileNodeType() { @Override public @NotNull TokenSet getCommentTokens() { - return TokenSet.create(QuteElementTypes.QUTE_CONTENT, QuteElementTypes.QUTE_COMMENT); + return TokenSet.create(QuteElementTypes.QUTE_COMMENT); } @Override @@ -51,7 +59,7 @@ public IFileElementType getFileNodeType() { @Override public @NotNull PsiElement createElement(ASTNode node) { - return new ASTWrapperPsiElement(node); + return QutePsiElementFactory.createPsiElement(node); } @Override diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteToken.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteToken.java new file mode 100644 index 000000000..bfa87c2e6 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteToken.java @@ -0,0 +1,42 @@ +package com.redhat.devtools.intellij.qute.lang; + +import com.intellij.psi.*; +import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; +import com.intellij.psi.impl.source.tree.LeafPsiElement; +import com.intellij.psi.impl.source.xml.TagNameReference; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.xml.XmlToken; +import com.intellij.psi.xml.XmlTokenType; +import org.jetbrains.annotations.NotNull; + +public class QuteToken extends LeafPsiElement { + + public QuteToken(@NotNull IElementType type, CharSequence text) { + super(type, text); + } + + @Override + public PsiReference @NotNull [] getReferences() { + return getReferences(PsiReferenceService.Hints.NO_HINTS); + } + + //@Override + public PsiReference @NotNull [] getReferences(PsiReferenceService.@NotNull Hints hints) { + /*final IElementType elementType = getElementType(); + + if (elementType == XmlTokenType.XML_DATA_CHARACTERS || + elementType == XmlTokenType.XML_CHAR_ENTITY_REF) { + return ReferenceProvidersRegistry.getReferencesFromProviders(this, hints); + } else if (elementType == XmlTokenType.XML_NAME && getParent() instanceof PsiErrorElement) { + final PsiElement element = getPrevSibling(); + + if (element instanceof XmlToken && ((XmlToken)element).getTokenType() == XmlTokenType.XML_END_TAG_START) { + return new PsiReference[] {TagNameReference.createTagNameReference(this, getNode(), false)}; + } + } + + return super.getReferences();*/ + return null; + } + +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteEditorHighlighter.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteEditorHighlighter.java new file mode 100644 index 000000000..48de29540 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteEditorHighlighter.java @@ -0,0 +1,27 @@ +package com.redhat.devtools.intellij.qute.lang.highlighter; + +import com.intellij.lang.Language; +import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.ex.util.LayerDescriptor; +import com.intellij.openapi.editor.ex.util.LayeredLexerEditorHighlighter; +import com.intellij.openapi.fileTypes.SyntaxHighlighter; +import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.redhat.devtools.intellij.qute.lang.QuteFileViewProvider; +import com.redhat.devtools.intellij.qute.lang.psi.tree.QuteElementTypes; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class QuteEditorHighlighter extends LayeredLexerEditorHighlighter { + + public QuteEditorHighlighter(@Nullable Project project, @Nullable VirtualFile virtualFile, @NotNull EditorColorsScheme scheme) { + super(new QuteSyntaxHighlighter(), scheme); + if (virtualFile != null) { + Language templateLanguage = QuteFileViewProvider.getTemplateLanguage(virtualFile); + this.registerLayer(QuteElementTypes.QUTE_TEXT, + new LayerDescriptor( + SyntaxHighlighterFactory.getSyntaxHighlighter(templateLanguage, project, virtualFile),"")); + } + } +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteEditorHighlighterProvider.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteEditorHighlighterProvider.java new file mode 100644 index 000000000..67419efd9 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteEditorHighlighterProvider.java @@ -0,0 +1,17 @@ +package com.redhat.devtools.intellij.qute.lang.highlighter; + +import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.highlighter.EditorHighlighter; +import com.intellij.openapi.fileTypes.EditorHighlighterProvider; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class QuteEditorHighlighterProvider implements EditorHighlighterProvider { + @Override + public EditorHighlighter getEditorHighlighter(@Nullable Project project, @NotNull FileType fileType, @Nullable VirtualFile virtualFile, @NotNull EditorColorsScheme colors) { + return new QuteEditorHighlighter(project, virtualFile, colors); + } +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteSyntaxHighlighter.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteSyntaxHighlighter.java new file mode 100644 index 000000000..1360f9bfa --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteSyntaxHighlighter.java @@ -0,0 +1,42 @@ +package com.redhat.devtools.intellij.qute.lang.highlighter; + +import com.intellij.lexer.Lexer; +import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; +import com.intellij.openapi.editor.XmlHighlighterColors; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.fileTypes.SyntaxHighlighterBase; +import com.intellij.psi.tree.IElementType; +import com.intellij.util.containers.MultiMap; +import com.redhat.devtools.intellij.qute.lang.psi.QuteLexer; +import com.redhat.devtools.intellij.qute.lang.psi.tree.QuteElementTypes; +import com.redhat.devtools.intellij.qute.lang.psi.tree.QuteTokenType; +import org.jetbrains.annotations.NotNull; + +public class QuteSyntaxHighlighter extends SyntaxHighlighterBase { + + private static final TextAttributesKey COMMENT = TextAttributesKey.createTextAttributesKey("COMMENT", DefaultLanguageHighlighterColors.LINE_COMMENT); + + private static final TextAttributesKey EXPRESSION = TextAttributesKey.createTextAttributesKey("EXPRESSION", XmlHighlighterColors.XML_TAG); + + private static final MultiMap ourMap = MultiMap.create(); + + static { + // Qute Comments + ourMap.putValue(QuteTokenType.QUTE_COMMENT_START, COMMENT); + ourMap.putValue(QuteTokenType.QUTE_COMMENT_END, COMMENT); + ourMap.putValue(QuteElementTypes.QUTE_COMMENT, COMMENT); + // Qute expression + ourMap.putValue(QuteTokenType.QUTE_START_EXPRESSION, EXPRESSION); + ourMap.putValue(QuteTokenType.QUTE_END_EXPRESSION, EXPRESSION); + } + + @Override + public @NotNull Lexer getHighlightingLexer() { + return new QuteLexer(); + } + + @Override + public TextAttributesKey @NotNull [] getTokenHighlights(IElementType tokenType) { + return ourMap.get(tokenType).toArray(TextAttributesKey.EMPTY_ARRAY); + } +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteSyntaxHighlighterFactory.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteSyntaxHighlighterFactory.java new file mode 100644 index 000000000..3d61baa01 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/highlighter/QuteSyntaxHighlighterFactory.java @@ -0,0 +1,13 @@ +package com.redhat.devtools.intellij.qute.lang.highlighter; + +import com.intellij.openapi.fileTypes.SingleLazyInstanceSyntaxHighlighterFactory; +import com.intellij.openapi.fileTypes.SyntaxHighlighter; +import org.jetbrains.annotations.NotNull; + +public class QuteSyntaxHighlighterFactory extends SingleLazyInstanceSyntaxHighlighterFactory { + @Override + @NotNull + protected SyntaxHighlighter createHighlighter() { + return new QuteSyntaxHighlighter(); + } +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QuteLexer.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QuteLexer.java new file mode 100644 index 000000000..d8e578ddd --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QuteLexer.java @@ -0,0 +1,231 @@ +/******************************************************************************* + * Copyright (c) 2022 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.intellij.qute.lang.psi; + +import com.intellij.lexer.LexerBase; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.psi.tree.IElementType; +import com.redhat.devtools.intellij.qute.lang.psi.tree.QuteElementTypes; +import com.redhat.devtools.intellij.qute.lang.psi.tree.QuteTokenType; +import com.redhat.qute.parser.expression.scanner.ExpressionScanner; +import com.redhat.qute.parser.template.scanner.ScannerState; +import com.redhat.qute.parser.template.scanner.TemplateScanner; +import com.redhat.qute.parser.template.scanner.TokenType; +import org.jetbrains.annotations.NotNull; + +/** + * Qute lexer based on the Qute LS scanner. + */ +public class QuteLexer extends LexerBase { + + private IElementType myTokenType; + private CharSequence myText; + + private int myTokenStart; + private int myTokenEnd; + + private int myBufferEnd; + private int myState; + + private boolean myFailed; + + private TemplateScanner scanner; + + private boolean withinExpression; + + private ExpressionScanner expressionScanner; + private int startExpressionOffset = -1; + private int endExpressionOffset = -1; + private boolean hasEndExpression; + + @Override + public void start(@NotNull CharSequence buffer, int startOffset, int endOffset, int initialState) { + myText = buffer; + myTokenStart = myTokenEnd = startOffset; + myBufferEnd = endOffset; + //myFlex.reset(myText, startOffset, endOffset, initialState); + scanner = (TemplateScanner) TemplateScanner.createScanner(buffer.subSequence(startOffset, endOffset).toString(), 0); + myTokenType = null; + } + + @Override + public int getState() { + locateToken(); + return myState; + } + + @Override + public IElementType getTokenType() { + locateToken(); + return myTokenType; + } + + @Override + public int getTokenStart() { + locateToken(); + return myTokenStart; + } + + @Override + public int getTokenEnd() { + locateToken(); + return myTokenEnd; + } + + @Override + public void advance() { + locateToken(); + myTokenType = null; + } + + @NotNull + @Override + public CharSequence getBufferSequence() { + return myText; + } + + @Override + public int getBufferEnd() { + return myBufferEnd; + } + + protected void locateToken() { + if (myTokenType != null) return; + + myTokenStart = myTokenEnd; + if (myFailed) return; + + try { + + if (startExpressionOffset != -1 && expressionScanner == null) { + hasEndExpression = false; + TokenType tokenType = scanner.scan(); + while (tokenType != TokenType.EOS) { + if (tokenType == TokenType.EndExpression) { + hasEndExpression = true; + break; + } + tokenType = scanner.scan(); + } + endExpressionOffset = scanner.getTokenOffset(); + expressionScanner = ExpressionScanner.createScanner(myText.toString(),true,startExpressionOffset, endExpressionOffset); + } + boolean parse = expressionScanner == null; + if (expressionScanner != null) { + com.redhat.qute.parser.expression.scanner.TokenType tokenType = expressionScanner.scan(); + while (tokenType != com.redhat.qute.parser.expression.scanner.TokenType.EOS) { + IElementType elementType = getTokenType(tokenType); + if (elementType != null) { + myState = getStateAsInt(expressionScanner.getScannerState()); + myTokenType = elementType; + myTokenEnd = expressionScanner.getTokenEnd(); + break; + } + tokenType = expressionScanner.scan(); + } + if (tokenType == com.redhat.qute.parser.expression.scanner.TokenType.EOS) { + if (hasEndExpression) { + myState = getStateAsInt(scanner.getScannerState()); + myTokenType = getTokenType(scanner.getTokenType()); + myTokenEnd = scanner.getTokenEnd(); + } else { + parse = true; + myTokenType = null; + } + startExpressionOffset = -1; + endExpressionOffset = -1; + expressionScanner = null; + } + } + + if (parse){ + TokenType tokenType = scanner.scan(); + while (tokenType != TokenType.EOS) { + IElementType elementType = getTokenType(tokenType); + if (elementType != null) { + myState = getStateAsInt(scanner.getScannerState()); + myTokenType = elementType; + myTokenEnd = scanner.getTokenEnd(); + if (myTokenType == QuteTokenType.QUTE_START_EXPRESSION) { + startExpressionOffset = scanner.getTokenEnd(); + } + break; + } + tokenType = scanner.scan(); + } + } + } catch (ProcessCanceledException e) { + throw e; + } catch (Throwable e) { + myFailed = true; + myTokenType = com.intellij.psi.TokenType.BAD_CHARACTER; + myTokenEnd = myBufferEnd; + //LOG.warn(myFlex.getClass().getName(), e); + } + } + + private int getStateAsInt(com.redhat.qute.parser.expression.scanner.ScannerState state) { + return 10 + state.ordinal(); + } + + private static IElementType getTokenType(TokenType tokenType) { + switch (tokenType) { + case StartComment: + return QuteTokenType.QUTE_COMMENT_START; + case Comment: + return QuteElementTypes.QUTE_COMMENT; + case EndComment: + return QuteTokenType.QUTE_COMMENT_END; + case StartParameterDeclaration: + return QuteTokenType.QUTE_START_PARAMETER_DECLARATION; + case EndParameterDeclaration: + return QuteTokenType.QUTE_END_PARAMETER_DECLARATION; + case StartExpression: + return QuteTokenType.QUTE_START_EXPRESSION; + case EndExpression: + return QuteTokenType.QUTE_END_EXPRESSION; + case StartTagOpen: + return QuteTokenType.QUTE_START_TAG_OPEN; + case StartTag: + return QuteTokenType.QUTE_START_TAG; + case EndTag: + return QuteTokenType.QUTE_END_TAG; + case EndTagSelfClose: + return QuteTokenType.QUTE_END_TAG_SELF_CLOSE; + case EndTagOpen: + return QuteTokenType.QUTE_END_TAG_OPEN; + case EndTagClose: + return QuteTokenType.QUTE_END_TAG_CLOSE; + case Whitespace: + return QuteTokenType.QUTE_WHITESPACE; + case ParameterTag: + return QuteTokenType.QUTE_PARAMETER_TAG; + } + return QuteElementTypes.QUTE_TEXT; + } + + private static IElementType getTokenType(com.redhat.qute.parser.expression.scanner.TokenType tokenType) { + switch (tokenType) { + case ObjectPart: + return QuteTokenType.QUTE_EXPRESSION_OBJECT_PART; + } + return null; + } + private static int getStateAsInt(ScannerState state) { + return state.ordinal(); + } + + @Override + public String toString() { + return "QuteLexer for " + scanner.getClass().getName(); + } + +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteParser.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QuteParser.java similarity index 63% rename from src/main/java/com/redhat/devtools/intellij/qute/lang/QuteParser.java rename to src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QuteParser.java index 7fde3252f..f85d6129b 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteParser.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QuteParser.java @@ -8,32 +8,40 @@ * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ -package com.redhat.devtools.intellij.qute.lang; +package com.redhat.devtools.intellij.qute.lang.psi; -import com.intellij.lang.ASTFactory; -import com.intellij.lang.ASTNode; -import com.intellij.lang.PsiBuilder; -import com.intellij.lang.PsiParser; +import com.intellij.lang.*; import com.intellij.psi.impl.source.tree.LazyParseableElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.ILazyParseableElementType; +import com.intellij.psi.tree.TokenSet; +import com.redhat.devtools.intellij.qute.lang.QuteASTNode; +import com.redhat.devtools.intellij.qute.lang.psi.tree.QuteElementType; +import com.redhat.devtools.intellij.qute.lang.psi.tree.QuteTokenType; import com.redhat.qute.parser.template.Template; import com.redhat.qute.parser.template.TemplateParser; import org.jetbrains.annotations.NotNull; /** - * Qute parser. Reqyired because some features are related to special + * Qute parser. Required because some features are related to special * PSI nodes thus we need to implement them. * Inspired by TemplateParser as there seem no way to reuse it. * * @see https://github.com/redhat-developer/quarkus-ls/blob/HEAD/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/TemplateParser.java */ -public class QuteParser implements PsiParser { +public class QuteParser implements PsiParser, LightPsiParser { + @Override public @NotNull ASTNode parse(@NotNull IElementType root, @NotNull PsiBuilder builder) { - Template template = TemplateParser.parse(builder.getOriginalText().toString(), ""); - LazyParseableElement rootNode = ASTFactory.lazy((ILazyParseableElementType) root, null); - template.getChildren().forEach(child -> rootNode.rawAddChildrenWithoutNotifications(QuteASTNode.getNode(child))); - return rootNode; + this.parseLight(root, builder); + return builder.getTreeBuilt(); + } + + @Override + public void parseLight(IElementType root, PsiBuilder builder) { + builder.enforceCommentTokens(TokenSet.EMPTY); + final PsiBuilder.Marker file = builder.mark(); + new QuteParsing(builder).parseTemplate(); + file.done(root); } } diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QuteParsing.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QuteParsing.java new file mode 100644 index 000000000..c32c60372 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QuteParsing.java @@ -0,0 +1,129 @@ +package com.redhat.devtools.intellij.qute.lang.psi; + +import static com.intellij.psi.xml.XmlTokenType.XML_START_TAG_START; +import static com.redhat.devtools.intellij.qute.lang.psi.tree.QuteElementTypes.*; +import static com.redhat.devtools.intellij.qute.lang.psi.tree.QuteTokenType.*; + +import com.intellij.lang.PsiBuilder; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.Nullable; + +public class QuteParsing { + + private final PsiBuilder myBuilder; + + public QuteParsing(PsiBuilder builder) { + myBuilder = builder; + } + + public void parseTemplate() { + final PsiBuilder.Marker template = mark(); + + while (isCommentToken(token())) { + parseComment(); + } + + while (!eof()) { + final IElementType tt = token(); + if (tt == QUTE_START_EXPRESSION) { + parseExpression(); + } else if (isCommentToken(tt)) { + parseComment(); + } else if (tt == QUTE_TEXT) { + parseText(); + } else { + advance(); + } + } + + template.done(QUTE_CONTENT); + } + + private void parseText() { + final PsiBuilder.Marker text = mark(); + advance(); + text.done(QUTE_TEXT); + } + + private void parseExpression() { + final PsiBuilder.Marker expression = mark(); + advance(); + + while (true) { + final IElementType tt = token(); + if (tt == null) { + break; + } else if (tt == QUTE_EXPRESSION) { + // Comment content : foo in {! foo !} + advance(); + continue; + } else if (tt == QUTE_END_EXPRESSION) { + // End expression: } + advance(); + } else if (tt == QUTE_EXPRESSION_OBJECT_PART) { + final PsiBuilder.Marker objectPart = mark(); + advance(); + objectPart.done(QUTE_EXPRESSION_OBJECT_PART); + continue; + + } else { + final PsiBuilder.Marker error = mark(); + advance(); + // error.error("BAD comments!"); + continue; + } + break; + } + expression.done(QUTE_EXPRESSION); + } + + + private void parseComment() { + final PsiBuilder.Marker comment = mark(); + advance(); + while (true) { + final IElementType tt = token(); + if (tt == null) { + // Case when comment is not closed. + // ex : {! foo + break; + } else if (tt == QUTE_COMMENT) { + // Comment content : foo in {! foo !} + advance(); + continue; + } else if (tt == QUTE_COMMENT_END) { + // End comment: !} + advance(); + } else { + //final PsiBuilder.Marker error = mark(); + advance(); + // error.error("BAD comments!"); + continue; + } + break; + } + comment.done(QUTE_COMMENT); + } + + protected boolean isCommentToken(final IElementType tt) { + // Start comment: {! + return tt == QUTE_COMMENT_START; + } + + protected final PsiBuilder.Marker mark() { + return myBuilder.mark(); + } + + @Nullable + protected final IElementType token() { + return myBuilder.getTokenType(); + } + + protected final boolean eof() { + return myBuilder.eof(); + } + + protected final void advance() { + myBuilder.advanceLexer(); + } +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/QutePsiFile.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QutePsiFile.java similarity index 82% rename from src/main/java/com/redhat/devtools/intellij/qute/lang/QutePsiFile.java rename to src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QutePsiFile.java index cc942b627..8f14193e3 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lang/QutePsiFile.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/QutePsiFile.java @@ -8,13 +8,18 @@ * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ -package com.redhat.devtools.intellij.qute.lang; +package com.redhat.devtools.intellij.qute.lang.psi; import com.intellij.extapi.psi.PsiFileBase; import com.intellij.openapi.fileTypes.FileType; import com.intellij.psi.FileViewProvider; +import com.redhat.devtools.intellij.qute.lang.QuteFileType; +import com.redhat.devtools.intellij.qute.lang.QuteLanguage; import org.jetbrains.annotations.NotNull; +/** + * Qute Psi file. + */ public class QutePsiFile extends PsiFileBase { public QutePsiFile(FileViewProvider viewProvider) { super(viewProvider, QuteLanguage.INSTANCE); diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteElementType.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QuteElementType.java similarity index 88% rename from src/main/java/com/redhat/devtools/intellij/qute/lang/QuteElementType.java rename to src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QuteElementType.java index 753aa4377..e1718c05d 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteElementType.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QuteElementType.java @@ -8,9 +8,10 @@ * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ -package com.redhat.devtools.intellij.qute.lang; +package com.redhat.devtools.intellij.qute.lang.psi.tree; import com.intellij.psi.tree.IElementType; +import com.redhat.devtools.intellij.qute.lang.QuteLanguage; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteElementTypes.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QuteElementTypes.java similarity index 75% rename from src/main/java/com/redhat/devtools/intellij/qute/lang/QuteElementTypes.java rename to src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QuteElementTypes.java index 4107666c6..965df6bf0 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lang/QuteElementTypes.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QuteElementTypes.java @@ -8,15 +8,16 @@ * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ -package com.redhat.devtools.intellij.qute.lang; +package com.redhat.devtools.intellij.qute.lang.psi.tree; import com.intellij.psi.templateLanguages.TemplateDataElementType; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IFileElementType; import com.intellij.psi.tree.OuterLanguageElementType; +import com.redhat.devtools.intellij.qute.lang.QuteLanguage; +import com.redhat.devtools.intellij.qute.lang.psi.tree.QuteElementType; import com.redhat.qute.parser.template.Node; -import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -26,25 +27,24 @@ public class QuteElementTypes { /* Non Qute content in Qute PSI file */ - public static final IElementType QUTE_CONTENT = new QuteElementType("#text"); + public static final IElementType QUTE_CONTENT = new QuteElementType("QUTE_CONTENT"); /* Qute comment */ - public static final IElementType QUTE_COMMENT = new QuteElementType("#comment"); + public static final IElementType QUTE_COMMENT = new QuteElementType("QUTE_COMMENT"); - public static final IElementType QUTE_TEXT = new QuteElementType("TEXT"); + public static final IElementType QUTE_EXPRESSION = new QuteElementType("QUTE_EXPRESSION"); - /* - Qute block in non Qute PSI file - */ - public static final IElementType QUTE_BLOCK = new OuterLanguageElementType("QUTE-BLOCK", QuteLanguage.INSTANCE); + public static final IElementType QUTE_TEXT = new OuterLanguageElementType("QUTE_TEXT", QuteLanguage.INSTANCE); + + public static final IElementType QUTE_OUTER_BLOCK = new OuterLanguageElementType("QUTE_TEMPLATE_BLOCK", QuteLanguage.INSTANCE); /* This is the pseudo type that will be assigned to the Qute PSI file so that Qute blocks in non Qute PSI file is assigned the OuterLanguageElement so that it is not used by completion,... */ - public static final IElementType QUTE_FILE_DATA = new TemplateDataElementType("QUTE_FILE_DATA", QuteLanguage.INSTANCE, QUTE_CONTENT, QUTE_BLOCK); + public static final IElementType QUTE_FILE_DATA = new TemplateDataElementType("QUTE_FILE_DATA", QuteLanguage.INSTANCE, QUTE_TEXT, QUTE_OUTER_BLOCK); private static final Map types = new ConcurrentHashMap<>(); static { diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QutePsiElementFactory.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QutePsiElementFactory.java new file mode 100644 index 000000000..109dc5a87 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QutePsiElementFactory.java @@ -0,0 +1,11 @@ +package com.redhat.devtools.intellij.qute.lang.psi.tree; + +import com.intellij.extapi.psi.ASTWrapperPsiElement; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; + +public class QutePsiElementFactory { + public static PsiElement createPsiElement(ASTNode node) { + return new ASTWrapperPsiElement(node); + } +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QuteTokenType.java b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QuteTokenType.java new file mode 100644 index 000000000..b4737c8ab --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/lang/psi/tree/QuteTokenType.java @@ -0,0 +1,32 @@ +package com.redhat.devtools.intellij.qute.lang.psi.tree; + +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.xml.IXmlLeafElementType; +import com.redhat.devtools.intellij.qute.lang.psi.tree.QuteElementType; + +public interface QuteTokenType { + + IElementType QUTE_COMMENT_START = new QuteElementType("QUTE_COMMENT_START"); + + IElementType QUTE_COMMENT_END = new QuteElementType("QUTE_COMMENT_END"); + + IElementType QUTE_START_PARAMETER_DECLARATION = new QuteElementType("QUTE_START_PARAMETER_DECLARATION"); + + IElementType QUTE_END_PARAMETER_DECLARATION = new QuteElementType("QUTE_END_PARAMETER_DECLARATION"); + + IElementType QUTE_START_EXPRESSION = new QuteElementType("QUTE_START_EXPRESSION"); + + IElementType QUTE_END_EXPRESSION = new QuteElementType("QUTE_END_EXPRESSION"); + + IElementType QUTE_START_TAG = new QuteElementType("QUTE_START_TAG"); + IElementType QUTE_END_TAG = new QuteElementType("QUTE_END_TAG"); + IElementType QUTE_END_TAG_SELF_CLOSE = new QuteElementType("QUTE_END_TAG_SELF_CLOSE"); + IElementType QUTE_END_TAG_OPEN = new QuteElementType("QUTE_END_TAG_OPEN"); + IElementType QUTE_END_TAG_CLOSE = new QuteElementType("QUTE_END_TAG_CLOSE"); + IElementType QUTE_START_TAG_OPEN = new QuteElementType("QUTE_START_TAG_OPEN"); + IElementType QUTE_WHITESPACE = new QuteElementType("QUTE_WHITESPACE"); + IElementType QUTE_PARAMETER_TAG = new QuteElementType("QUTE_PARAMETER_TAG"); + + // Qute expression + IElementType QUTE_EXPRESSION_OBJECT_PART = new QuteElementType("QUTE_EXPRESSION_OBJECT_PART"); +} diff --git a/src/main/resources/META-INF/lsp4ij-qute.xml b/src/main/resources/META-INF/lsp4ij-qute.xml index 926de215b..8dd6166ac 100644 --- a/src/main/resources/META-INF/lsp4ij-qute.xml +++ b/src/main/resources/META-INF/lsp4ij-qute.xml @@ -42,6 +42,7 @@ implementationClass="com.redhat.devtools.intellij.lsp4ij.operations.diagnostics.LSPDiagnosticAnnotator"/> + diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index a4bf1ab23..077ee4cdf 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -285,6 +285,8 @@ +