diff --git a/src/main/java/org/jastadd/tooling/java/AstNodeAnnotationBasedHighlighter.java b/src/main/java/org/jastadd/tooling/java/AstNodeAnnotationBasedHighlighter.java new file mode 100644 index 0000000000000000000000000000000000000000..d52ff7f61a521f2f5277ed39ed1a29efb00458be --- /dev/null +++ b/src/main/java/org/jastadd/tooling/java/AstNodeAnnotationBasedHighlighter.java @@ -0,0 +1,56 @@ +package org.jastadd.tooling.java; + +import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.lang.annotation.AnnotationHolder; +import com.intellij.lang.annotation.Annotator; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiMethodCallExpression; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Objects; + + +public class AstNodeAnnotationBasedHighlighter implements Annotator { + + @Override + public void annotate(@NotNull final PsiElement element, @NotNull AnnotationHolder holder) { + + if (!(element instanceof PsiMethodCallExpression)) { + return; + } + PsiMethodCallExpression psiMethodCallExpression = (PsiMethodCallExpression) element; + + PsiMethod value = psiMethodCallExpression.resolveMethod(); + if (value == null) { + return; + } + + // TODO check if ASTNodeAnnotation can be renamed + try { + if (Arrays.stream(value.getAnnotations()).noneMatch(x -> Objects.requireNonNull(x.getQualifiedName()).contains("ASTNodeAnnotation.Attribute"))) { + return; + } + } catch (NullPointerException e) { + return; + } + + PsiElement referenceElement = psiMethodCallExpression.getMethodExpression().getReferenceNameElement(); + if (referenceElement == null) { + return; + } + + // highlight + // TODO add more info in tooltip + holder.newAnnotation(HighlightSeverity.INFORMATION, "JastAdd Attribute") + .range(referenceElement.getTextRange()) + .highlightType(ProblemHighlightType.INFORMATION) + .textAttributes(JavaSyntaxHighlighter.ATTRIBUTE_CALL) + .tooltip("<b>JastAdd Attribute</b><br/>" + element.getContainingFile().getVirtualFile().getPath() + ":" + GeneratedCodeUtil.getLine(element)) + .create(); + } + + +} diff --git a/src/main/java/org/jastadd/tooling/java/AstNodeJavaDocBasedHighlighter.java b/src/main/java/org/jastadd/tooling/java/AstNodeJavaDocBasedHighlighter.java new file mode 100644 index 0000000000000000000000000000000000000000..1ea64a6c713531313bf62455e16fb80989d85080 --- /dev/null +++ b/src/main/java/org/jastadd/tooling/java/AstNodeJavaDocBasedHighlighter.java @@ -0,0 +1,84 @@ +package org.jastadd.tooling.java; + +import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.lang.annotation.AnnotationHolder; +import com.intellij.lang.annotation.Annotator; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiMethodCallExpression; +import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.javadoc.PsiDocTag; +import com.intellij.psi.javadoc.PsiDocTagValue; +import org.jetbrains.annotations.NotNull; + + +public class AstNodeJavaDocBasedHighlighter implements Annotator { + + @Override + public void annotate(@NotNull final PsiElement element, @NotNull AnnotationHolder holder) { + + if (!(element instanceof PsiMethodCallExpression)) { + return; + } + PsiMethodCallExpression psiMethodCallExpression = (PsiMethodCallExpression) element; + + PsiMethod targetMethod = psiMethodCallExpression.resolveMethod(); + if (targetMethod == null) { + return; + } + + PsiDocComment docComment = targetMethod.getDocComment(); + if (docComment == null) { + return; + } + + PsiDocTag apiLevelTag = docComment.findTagByName("apilevel"); + if (apiLevelTag == null) { + return; + } + + PsiDocTagValue value = apiLevelTag.getValueElement(); + if (value == null) { + return; + } + + TextAttributesKey highlightKey; + String description; + + switch (value.getText()) { + case "high": + highlightKey = JavaSyntaxHighlighter.HIGHLEVEL_API_USE; + description = "JastAdd high-level API use"; + break; + case "low": + highlightKey = JavaSyntaxHighlighter.LOWLEVEL_API_USE; + description = "JastAdd low-level API use"; + break; + case "internal": + highlightKey = JavaSyntaxHighlighter.INTERNAL_API_USE; + description = "JastAdd internal API use"; + break; + default: + // ignore error case + return; + } + + + PsiElement referenceElement = psiMethodCallExpression.getMethodExpression().getReferenceNameElement(); + if (referenceElement == null) { + return; + } + + // highlight + // TODO add more info in tooltip + holder.newAnnotation(HighlightSeverity.INFORMATION, description) + .range(referenceElement.getTextRange()) + .highlightType(ProblemHighlightType.INFORMATION) + .textAttributes(highlightKey) + .tooltip("<b>" + description + "</b><br/>" + element.getContainingFile().getVirtualFile().getPath() + ":" + GeneratedCodeUtil.getLine(element)) + .create(); + } + +} diff --git a/src/main/java/org/jastadd/tooling/java/GeneratedCodeUtil.java b/src/main/java/org/jastadd/tooling/java/GeneratedCodeUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..88d50093e23731a81ea2af183efa7373a5225cb8 --- /dev/null +++ b/src/main/java/org/jastadd/tooling/java/GeneratedCodeUtil.java @@ -0,0 +1,22 @@ +package org.jastadd.tooling.java; + +import com.intellij.openapi.editor.Document; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; + +public class GeneratedCodeUtil { + /** + * Get the line of the PSI element within its document + * + * @param element a PSI element + * @return the line (first line is 1, if no line could be determined, 0 is returned) + */ + public static int getLine(@NotNull PsiElement element) { + int line = 0; + Document document = element.getContainingFile().getViewProvider().getDocument(); + if (document != null) { + line = document.getLineNumber(element.getTextRange().getStartOffset() + 1); + } + return line; + } +} diff --git a/src/main/java/org/jastadd/tooling/java/JavaColorSettingsPage.java b/src/main/java/org/jastadd/tooling/java/JavaColorSettingsPage.java new file mode 100644 index 0000000000000000000000000000000000000000..ea402dfe1be2cefbfcaaf140d01ef9afe8e9f744 --- /dev/null +++ b/src/main/java/org/jastadd/tooling/java/JavaColorSettingsPage.java @@ -0,0 +1,82 @@ +package org.jastadd.tooling.java; + +import com.intellij.ide.highlighter.JavaFileHighlighter; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.fileTypes.SyntaxHighlighter; +import com.intellij.openapi.options.colors.AttributesDescriptor; +import com.intellij.openapi.options.colors.ColorDescriptor; +import com.intellij.openapi.options.colors.ColorSettingsPage; +import org.jastadd.tooling.util.JastAddIcons; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.HashMap; +import java.util.Map; + +public class JavaColorSettingsPage implements ColorSettingsPage { + + private static final AttributesDescriptor[] DESCRIPTORS = new AttributesDescriptor[]{ + new AttributesDescriptor("Nonterminal Use", JavaSyntaxHighlighter.NT_USE), + new AttributesDescriptor("High-Level API Use", JavaSyntaxHighlighter.HIGHLEVEL_API_USE), + new AttributesDescriptor("Low-Level API Use", JavaSyntaxHighlighter.LOWLEVEL_API_USE), + new AttributesDescriptor("Internal API Use", JavaSyntaxHighlighter.INTERNAL_API_USE), + new AttributesDescriptor("Attribute Call", JavaSyntaxHighlighter.ATTRIBUTE_CALL), + new AttributesDescriptor("Inter-Type Declaration Use", JavaSyntaxHighlighter.INTERTYPE_DECL_USE) + }; + + @Nullable + @Override + public Icon getIcon() { + return JastAddIcons.FILE; + } + + @NotNull + @Override + public SyntaxHighlighter getHighlighter() { + return new JavaFileHighlighter(); + } + + @NotNull + @Override + public String getDemoText() { + return "<NT>Marking</NT> m; // nonterminal\n" + + "String name = m.<HAPI>getName()</HAPI>; // high-level API call\n" + + "ASTNode child = m.<LAPI>getChild(0)</LAPI>; // low-level API call\n" + + "boolean b = m.<IAPI>canRewrite()</IAPI>; // internal API call\n" + + "m = petriNet.<ATT>initialMarking()</ATT>; // (nonterminal) attribute\n" + + "m.<ITD>fire()</ITD>; // inter-type declaration call\n"; + } + + @Nullable + @Override + public Map<String, TextAttributesKey> getAdditionalHighlightingTagToDescriptorMap() { + Map<String, TextAttributesKey> m = new HashMap<>(); + m.put("ATT", JavaSyntaxHighlighter.ATTRIBUTE_CALL); + m.put("HAPI", JavaSyntaxHighlighter.HIGHLEVEL_API_USE); + m.put("LAPI", JavaSyntaxHighlighter.LOWLEVEL_API_USE); + m.put("IAPI", JavaSyntaxHighlighter.INTERNAL_API_USE); + m.put("NT", JavaSyntaxHighlighter.NT_USE); + m.put("ITD", JavaSyntaxHighlighter.INTERTYPE_DECL_USE); + return m; + } + + @NotNull + @Override + public AttributesDescriptor[] getAttributeDescriptors() { + return DESCRIPTORS; + } + + @NotNull + @Override + public ColorDescriptor[] getColorDescriptors() { + return ColorDescriptor.EMPTY_ARRAY; + } + + @NotNull + @Override + public String getDisplayName() { + return "JastAdd Java Extension"; + } + +} diff --git a/src/main/java/org/jastadd/tooling/java/JavaSyntaxHighlighter.java b/src/main/java/org/jastadd/tooling/java/JavaSyntaxHighlighter.java new file mode 100644 index 0000000000000000000000000000000000000000..3a3adacf309da4db812ba8b8969e4f046a51656e --- /dev/null +++ b/src/main/java/org/jastadd/tooling/java/JavaSyntaxHighlighter.java @@ -0,0 +1,43 @@ +package org.jastadd.tooling.java; + +import com.intellij.lexer.JavaHighlightingLexer; +import com.intellij.lexer.Lexer; +import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.fileTypes.SyntaxHighlighterBase; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; + +import static com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey; + +public class JavaSyntaxHighlighter extends SyntaxHighlighterBase { + + public static final TextAttributesKey NT_USE = + createTextAttributesKey("NT_USE", DefaultLanguageHighlighterColors.HIGHLIGHTED_REFERENCE); + public static final TextAttributesKey HIGHLEVEL_API_USE = + createTextAttributesKey("HIGHLEVEL_API_USE", DefaultLanguageHighlighterColors.HIGHLIGHTED_REFERENCE); + public static final TextAttributesKey LOWLEVEL_API_USE = + createTextAttributesKey("LOWLEVEL_API_USE", DefaultLanguageHighlighterColors.HIGHLIGHTED_REFERENCE); + public static final TextAttributesKey INTERNAL_API_USE = + createTextAttributesKey("INTERNAL_API_USE", DefaultLanguageHighlighterColors.HIGHLIGHTED_REFERENCE); + public static final TextAttributesKey ATTRIBUTE_CALL = + createTextAttributesKey("ATTRIBUTE_CALL", DefaultLanguageHighlighterColors.HIGHLIGHTED_REFERENCE); + public static final TextAttributesKey INTERTYPE_DECL_USE = + createTextAttributesKey("INTERTYPE_DECL_USE", DefaultLanguageHighlighterColors.HIGHLIGHTED_REFERENCE); + + private static final TextAttributesKey[] EMPTY_KEYS = new TextAttributesKey[0]; + + @NotNull + @Override + public Lexer getHighlightingLexer() { + return new JavaHighlightingLexer(LanguageLevel.HIGHEST); + } + + @NotNull + @Override + public TextAttributesKey @NotNull [] getTokenHighlights(IElementType tokenType) { + return EMPTY_KEYS; + } + +} diff --git a/src/main/java/org/jastadd/tooling/grammar/GrammarJavaAnnotator.java b/src/main/java/org/jastadd/tooling/java/NonterminalUseAnnotator.java similarity index 88% rename from src/main/java/org/jastadd/tooling/grammar/GrammarJavaAnnotator.java rename to src/main/java/org/jastadd/tooling/java/NonterminalUseAnnotator.java index 3b409aa6321bb4b4955d7835a7682d335c5bf5a9..40db0a21ef5a2d9295c30f6314e131dac081332b 100644 --- a/src/main/java/org/jastadd/tooling/grammar/GrammarJavaAnnotator.java +++ b/src/main/java/org/jastadd/tooling/java/NonterminalUseAnnotator.java @@ -1,11 +1,10 @@ -package org.jastadd.tooling.grammar; +package org.jastadd.tooling.java; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; import com.intellij.lang.annotation.HighlightSeverity; -import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.javadoc.PsiDocComment; @@ -18,7 +17,7 @@ import java.util.stream.Collectors; import static org.jastadd.tooling.grammar.GrammarUtil.asReferenceToTypeDecl; -public class GrammarJavaAnnotator implements Annotator { +public class NonterminalUseAnnotator implements Annotator { @Override public void annotate(@NotNull final PsiElement element, @NotNull AnnotationHolder holder) { @@ -44,7 +43,7 @@ public class GrammarJavaAnnotator implements Annotator { holder.newAnnotation(HighlightSeverity.INFORMATION, "JastAdd Nonterminal: " + production) .range(element.getTextRange()) .highlightType(ProblemHighlightType.INFORMATION) - .textAttributes(DefaultLanguageHighlighterColors.HIGHLIGHTED_REFERENCE) + .textAttributes(JavaSyntaxHighlighter.NT_USE) .tooltip("<b>JastAdd Nonterminal</b><br/>Production: <i>" + production + "</i><br/><i>Declared at </i>" + declaredAt) .create(); } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 93ed476fbc164fd7d666d62428724d143a1e60ae..a3cea52acb61ef2cc9b857830a6334f049d65bcb 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -20,7 +20,7 @@ <colorSettingsPage implementation="org.jastadd.tooling.grammar.GrammarColorSettingsPage"/> - <annotator language="JAVA" implementationClass="org.jastadd.tooling.grammar.GrammarJavaAnnotator"/> + <annotator language="JAVA" implementationClass="org.jastadd.tooling.java.NonterminalUseAnnotator"/> <annotator language="JastAddGrammar" implementationClass="org.jastadd.tooling.grammar.GrammarAnnotator"/> @@ -73,6 +73,11 @@ implementationClass="org.jastadd.tooling.aspect.AspectSyntaxHighlighterFactory"/> <colorSettingsPage implementation="org.jastadd.tooling.aspect.AspectColorSettingsPage"/> + + <annotator language="JAVA" implementationClass="org.jastadd.tooling.java.AstNodeAnnotationBasedHighlighter"/> + <annotator language="JAVA" implementationClass="org.jastadd.tooling.java.AstNodeJavaDocBasedHighlighter"/> + + <colorSettingsPage implementation="org.jastadd.tooling.java.JavaColorSettingsPage"/> </extensions> <actions>