From a03de6c394b827f4ee0e0609988ae53cd4efb59b Mon Sep 17 00:00:00 2001 From: chrisly42 Date: Sat, 25 Sep 2021 15:11:02 +0200 Subject: [PATCH] Added documentation provider info for global labels. Shows directives and comments above. Fixed BNF for labels with preprocessor statements. Bumped versions. --- README.md | 12 +++-- build.gradle | 37 ++++----------- .../plugins/m68k/parser/M68kParser.java | 42 +++++++++-------- .../m68k/psi/M68kPreprocessorDirective.java | 7 --- .../impl/M68kPreprocessorDirectiveImpl.java | 13 ----- .../M68kGlobalLabelDocumentationProvider.kt | 47 +++++++++++++++++++ ...8kSymbolDefinitionDocumentationProvider.kt | 2 +- .../platon42/intellij/plugins/m68k/m68k.bnf | 7 ++- .../plugins/m68k/psi/M68kPsiImplUtil.kt | 2 +- src/main/resources/META-INF/plugin.xml | 2 + ...68kGlobalLabelDocumentationProviderTest.kt | 43 +++++++++++++++++ .../dc_b_with_strings_and_global_label.txt | 8 ++-- .../directives/include_file_unquoted.txt | 6 +-- 13 files changed, 144 insertions(+), 84 deletions(-) create mode 100644 src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kGlobalLabelDocumentationProvider.kt create mode 100644 src/test/java/de/platon42/intellij/plugins/m68k/documentation/M68kGlobalLabelDocumentationProviderTest.kt diff --git a/README.md b/README.md index aec1116..989f04c 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,7 @@ If the current statement has no valid syntax, the instruction details of all mat ## Known issues - `Find Usages` always shows _"Unclassified"_ though it shouldn't (?) +- Typing in the `END` keyword will sometimes mess up the parsing for the next tokens. - Macro invocations are not yet evaluated, thus no referencing to symbols defined via macros (e.g. `STRUCT`). - Scoping for global symbols and labels is currently the whole project. - No support for register replacement (e.g. registers replaced by `EQUR` or `EQURL` will cause syntax errors) @@ -142,19 +143,22 @@ make it work with JUnit 5. Feel free to use the code (in package ```de.platon42. ## Feedback -I guess there are currently about 100 users of this plugin and while I wrote this mainly for myself, I'm only doing this in my spare time. Feedback -and [rating](https://plugins.jetbrains.com/plugin/17268-mc68000-assembly-language-support/reviews) -are appreciated. They really are, because they do keep me motivated to continue development. +I guess there are currently over 500 users of this plugin and while I wrote this mainly for myself, I'm only doing this in my spare time. + +Feedback and [rating](https://plugins.jetbrains.com/plugin/17268-mc68000-assembly-language-support/reviews) +are appreciated. It really is keeping me motivated to continue development. ## Changelog -### V0.7 (unreleased) +### V0.7 (26-Sep-21) - Bugfix: `btst` with pc-relative and weird immediate mode was missing (courtesy of Yann). - Bugfix: `movem` with pc-relative mode was missing for weird immediate mode (courtesy of Yann). - Bugfix: Special registers for address mode matching only worked with lower case register names (courtesy of Yann). - Enhancement: Assembler syntax with implicit immediate 1 for shifts and rotations no longer cause syntax errors (courtesy of Yann). - Enhancement: Documentation for instruction with special register shows specific register expected. +- New: Added documentation provider info for global labels. Shows directives and comments above. +- Bugfix: Fixed BNF for labels with preprocessor statements. ### V0.6 (09-Aug-21) diff --git a/build.gradle b/build.gradle index 79be03f..b9b3ab3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,9 @@ plugins { id 'java' - id 'org.jetbrains.intellij' version '1.1.5' + id 'org.jetbrains.intellij' version '1.1.6' id 'org.jetbrains.kotlin.jvm' version '1.5.21' id 'jacoco' - id 'com.github.kt3k.coveralls' version '2.11.0' + id 'com.github.kt3k.coveralls' version '2.12.0' } group = 'de.platon42' @@ -22,9 +22,9 @@ repositories { dependencies { implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' - testImplementation "org.assertj:assertj-core:3.20.2" - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.0-M1' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.0-M1' + testImplementation "org.assertj:assertj-core:3.21.0" + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' testImplementation "org.jetbrains.kotlin:kotlin-test" testImplementation "org.jetbrains.kotlin:kotlin-reflect" // testImplementation "org.jetbrains.kotlin:kotlin-test-junit" @@ -57,35 +57,16 @@ runPluginVerifier { patchPluginXml { setChangeNotes(""" -

V0.7 (unreleased)

+

I still got zero feedback and zero ratings :-(

+

V0.7 (26-Sep-21)

-

V0.6 (09-Aug-21)

- -

V0.5 (06-Aug-21)

-

Full changelog available at Github project site.

""") diff --git a/src/main/gen/de/platon42/intellij/plugins/m68k/parser/M68kParser.java b/src/main/gen/de/platon42/intellij/plugins/m68k/parser/M68kParser.java index db53253..4b6341c 100644 --- a/src/main/gen/de/platon42/intellij/plugins/m68k/parser/M68kParser.java +++ b/src/main/gen/de/platon42/intellij/plugins/m68k/parser/M68kParser.java @@ -562,9 +562,13 @@ public class M68kParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // Instruction + // Instruction|PreprocessorDirective static boolean InstructionOnly(PsiBuilder b, int l) { - return Instruction(b, l + 1); + if (!recursion_guard_(b, l, "InstructionOnly")) return false; + boolean r; + r = Instruction(b, l + 1); + if (!r) r = PreprocessorDirective(b, l + 1); + return r; } /* ********************************************************** */ @@ -596,18 +600,27 @@ public class M68kParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // Label Instruction + // Label (Instruction|PreprocessorDirective) static boolean LabelWithInstruction(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "LabelWithInstruction")) return false; if (!nextTokenIs(b, "", GLOBAL_LABEL_DEF, LOCAL_LABEL_DEF)) return false; boolean r; Marker m = enter_section_(b); r = Label(b, l + 1); - r = r && Instruction(b, l + 1); + r = r && LabelWithInstruction_1(b, l + 1); exit_section_(b, m, null, r); return r; } + // Instruction|PreprocessorDirective + private static boolean LabelWithInstruction_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "LabelWithInstruction_1")) return false; + boolean r; + r = Instruction(b, l + 1); + if (!r) r = PreprocessorDirective(b, l + 1); + return r; + } + /* ********************************************************** */ // LOCAL_LABEL_DEF COLON? public static boolean LocalLabel(PsiBuilder b, int l) { @@ -817,28 +830,21 @@ public class M68kParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // Label? PreprocessorKeyword PreprocessorOperands? + // PreprocessorKeyword PreprocessorOperands? public static boolean PreprocessorDirective(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "PreprocessorDirective")) return false; + if (!nextTokenIs(b, "", DATA_DIRECTIVE, OTHER_DIRECTIVE)) return false; boolean r; Marker m = enter_section_(b, l, _NONE_, PREPROCESSOR_DIRECTIVE, ""); - r = PreprocessorDirective_0(b, l + 1); - r = r && PreprocessorKeyword(b, l + 1); - r = r && PreprocessorDirective_2(b, l + 1); + r = PreprocessorKeyword(b, l + 1); + r = r && PreprocessorDirective_1(b, l + 1); exit_section_(b, l, m, r, false, null); return r; } - // Label? - private static boolean PreprocessorDirective_0(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "PreprocessorDirective_0")) return false; - Label(b, l + 1); - return true; - } - // PreprocessorOperands? - private static boolean PreprocessorDirective_2(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "PreprocessorDirective_2")) return false; + private static boolean PreprocessorDirective_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "PreprocessorDirective_1")) return false; PreprocessorOperands(b, l + 1); return true; } @@ -1220,14 +1226,12 @@ public class M68kParser implements PsiParser, LightPsiParser { /* ********************************************************** */ // Assignment - // | PreprocessorDirective // | LabelInsts public static boolean statement(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "statement")) return false; boolean r; Marker m = enter_section_(b, l, _NONE_, STATEMENT, ""); r = Assignment(b, l + 1); - if (!r) r = PreprocessorDirective(b, l + 1); if (!r) r = LabelInsts(b, l + 1); exit_section_(b, l, m, r, false, M68kParser::statement_recover); return r; diff --git a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kPreprocessorDirective.java b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kPreprocessorDirective.java index 56d6d31..7706a82 100644 --- a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kPreprocessorDirective.java +++ b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kPreprocessorDirective.java @@ -2,18 +2,11 @@ package de.platon42.intellij.plugins.m68k.psi; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; public interface M68kPreprocessorDirective extends M68kPsiElement { - @Nullable - M68kGlobalLabel getGlobalLabel(); - - @Nullable - M68kLocalLabel getLocalLabel(); - @NotNull M68kPreprocessorKeyword getPreprocessorKeyword(); diff --git a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kPreprocessorDirectiveImpl.java b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kPreprocessorDirectiveImpl.java index fba03a7..92b4ed4 100644 --- a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kPreprocessorDirectiveImpl.java +++ b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kPreprocessorDirectiveImpl.java @@ -6,7 +6,6 @@ import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.util.PsiTreeUtil; import de.platon42.intellij.plugins.m68k.psi.*; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; @@ -26,18 +25,6 @@ public class M68kPreprocessorDirectiveImpl extends M68kPreprocessorDirectiveMixi else super.accept(visitor); } - @Override - @Nullable - public M68kGlobalLabel getGlobalLabel() { - return PsiTreeUtil.getChildOfType(this, M68kGlobalLabel.class); - } - - @Override - @Nullable - public M68kLocalLabel getLocalLabel() { - return PsiTreeUtil.getChildOfType(this, M68kLocalLabel.class); - } - @Override @NotNull public M68kPreprocessorKeyword getPreprocessorKeyword() { diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kGlobalLabelDocumentationProvider.kt b/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kGlobalLabelDocumentationProvider.kt new file mode 100644 index 0000000..bc94919 --- /dev/null +++ b/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kGlobalLabelDocumentationProvider.kt @@ -0,0 +1,47 @@ +package de.platon42.intellij.plugins.m68k.documentation + +import com.intellij.lang.documentation.AbstractDocumentationProvider +import com.intellij.lang.documentation.DocumentationMarkup +import com.intellij.openapi.util.text.StringUtil +import com.intellij.psi.PsiComment +import com.intellij.psi.PsiElement +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.util.SmartList +import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel +import de.platon42.intellij.plugins.m68k.psi.M68kStatement + +class M68kGlobalLabelDocumentationProvider : AbstractDocumentationProvider() { + + override fun getQuickNavigateInfo(element: PsiElement, originalElement: PsiElement?): String? { + return generateDoc(element, originalElement) + } + + override fun generateDoc(element: PsiElement, originalElement: PsiElement?): String? { + return if (element is M68kGlobalLabel) { + // TODO find out how we can generate inner links for more symbol references inside the expression (DocumentationManagerUtil) + val statement = element.parent as M68kStatement + var preprocessorDirective = statement.preprocessorDirective + if ((preprocessorDirective == null) && (statement.asmInstruction == null) && (statement.macroCall == null)) { + val nextLineStatement = PsiTreeUtil.skipWhitespacesAndCommentsForward(PsiTreeUtil.skipWhitespacesAndCommentsForward(statement)) + as? M68kStatement + preprocessorDirective = nextLineStatement?.preprocessorDirective + } + val content = if (preprocessorDirective != null) + DocumentationMarkup.CONTENT_START + StringUtil.escapeXmlEntities(preprocessorDirective.text) + DocumentationMarkup.CONTENT_END + else "" + val comments = SmartList() + var prevToken: PsiElement? = statement + do { + prevToken = PsiTreeUtil.skipWhitespacesBackward(prevToken) + if (prevToken !is PsiComment) break + comments.add(prevToken.text) + } while (true) + val commentpart = + if (comments.isNotEmpty()) comments.asReversed().joinToString("
", DocumentationMarkup.GRAYED_START, DocumentationMarkup.GRAYED_END) else "" + + commentpart + + DocumentationMarkup.DEFINITION_START + StringUtil.escapeXmlEntities(element.name!!) + DocumentationMarkup.DEFINITION_END + + content + } else null + } +} \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kSymbolDefinitionDocumentationProvider.kt b/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kSymbolDefinitionDocumentationProvider.kt index e03df8b..a38f473 100644 --- a/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kSymbolDefinitionDocumentationProvider.kt +++ b/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kSymbolDefinitionDocumentationProvider.kt @@ -16,7 +16,7 @@ class M68kSymbolDefinitionDocumentationProvider : AbstractDocumentationProvider( override fun generateDoc(element: PsiElement, originalElement: PsiElement?): String? { return if (element is M68kSymbolDefinition) { // TODO find out how we can generate inner links for more symbol references inside the expression (DocumentationManagerUtil) - val value = (element.getParent() as M68kAssignment).expr.text + val value = (element.parent as M68kAssignment).expr.text DocumentationMarkup.DEFINITION_START + StringUtil.escapeXmlEntities(element.name!!) + DocumentationMarkup.DEFINITION_END + DocumentationMarkup.CONTENT_START + StringUtil.escapeXmlEntities(value) + DocumentationMarkup.CONTENT_END } else null diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/m68k.bnf b/src/main/java/de/platon42/intellij/plugins/m68k/m68k.bnf index e07cf14..ae1b77c 100644 --- a/src/main/java/de/platon42/intellij/plugins/m68k/m68k.bnf +++ b/src/main/java/de/platon42/intellij/plugins/m68k/m68k.bnf @@ -121,7 +121,6 @@ M68kFile ::= line* private line ::= !<> (MacroDefinition | statement) (<>|EOL) statement ::= (Assignment - | PreprocessorDirective | LabelInsts) {pin = 1 recoverWhile = statement_recover} @@ -140,8 +139,8 @@ Assignment ::= SymbolDefinition COLON? (OP_ASSIGN|EQU) expr private LabelInsts ::= LabelWithInstruction | LabelOnly | InstructionOnly private LabelOnly ::= Label -private LabelWithInstruction ::= Label Instruction -private InstructionOnly ::= Instruction +private LabelWithInstruction ::= Label (Instruction|PreprocessorDirective) +private InstructionOnly ::= (Instruction|PreprocessorDirective) LocalLabel ::= LOCAL_LABEL_DEF COLON? { name = "local label" @@ -175,7 +174,7 @@ AsmOp ::= MNEMONIC OperandSize? { PreprocessorKeyword ::= (DATA_DIRECTIVE | OTHER_DIRECTIVE) -PreprocessorDirective ::= Label? PreprocessorKeyword PreprocessorOperands? { +PreprocessorDirective ::= PreprocessorKeyword PreprocessorOperands? { mixin = "de.platon42.intellij.plugins.m68k.psi.M68kPreprocessorDirectiveMixin" } diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiImplUtil.kt b/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiImplUtil.kt index 2d7165c..eaa91a7 100644 --- a/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiImplUtil.kt +++ b/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiImplUtil.kt @@ -29,7 +29,7 @@ object M68kPsiImplUtil { // Local Label @JvmStatic - fun getName(element: M68kLocalLabel): String = element.firstChild?.text ?: "" + fun getName(element: M68kLocalLabel): String? = element.firstChild?.text @JvmStatic fun setName(element: M68kLocalLabel, name: String): PsiElement { diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index a4e1cc8..dc874d9 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -39,6 +39,8 @@ implementationClass="de.platon42.intellij.plugins.m68k.refs.M68kPreprocessorDirectiveElementManipulator"/> + me + """ + ) + assertThat(generateDocumentation(myFixture)) + .isEqualTo("; inputs: d0 = number
; output: d0 = square
squareme
include "fancysquarecode.asm"
") + } + + @Test + internal fun check_documentation_for_a_label_definition_next_line(@MyFixture myFixture: CodeInsightTestFixture) { + myFixture.configureByText( + "documentme.asm", """ +; output: d0 = square +squareme: +; oh man + include "fancysquarecode.asm" + """ + ) + assertThat(generateDocumentation(myFixture)) + .isEqualTo("; output: d0 = square
squareme
include "fancysquarecode.asm"
") + } +} \ No newline at end of file diff --git a/src/test/resources/parser/directives/dc_b_with_strings_and_global_label.txt b/src/test/resources/parser/directives/dc_b_with_strings_and_global_label.txt index 8a8d13a..9d42208 100644 --- a/src/test/resources/parser/directives/dc_b_with_strings_and_global_label.txt +++ b/src/test/resources/parser/directives/dc_b_with_strings_and_global_label.txt @@ -1,10 +1,10 @@ Assembly File: a.asm M68kStatementImpl(STATEMENT) + M68kGlobalLabelImpl(GLOBAL_LABEL) + PsiElement(M68kTokenType.GLOBAL_LABEL_DEF)('foo') + PsiElement(M68kTokenType.COLON)(':') + PsiWhiteSpace(' ') M68kPreprocessorDirectiveImpl(PREPROCESSOR_DIRECTIVE) - M68kGlobalLabelImpl(GLOBAL_LABEL) - PsiElement(M68kTokenType.GLOBAL_LABEL_DEF)('foo') - PsiElement(M68kTokenType.COLON)(':') - PsiWhiteSpace(' ') M68kPreprocessorKeywordImpl(PREPROCESSOR_KEYWORD) PsiElement(M68kTokenType.DATA_DIRECTIVE)('dc.b') PsiWhiteSpace(' ') diff --git a/src/test/resources/parser/directives/include_file_unquoted.txt b/src/test/resources/parser/directives/include_file_unquoted.txt index 440b525..a3a12fc 100644 --- a/src/test/resources/parser/directives/include_file_unquoted.txt +++ b/src/test/resources/parser/directives/include_file_unquoted.txt @@ -1,9 +1,9 @@ Assembly File: a.asm M68kStatementImpl(STATEMENT) + M68kGlobalLabelImpl(GLOBAL_LABEL) + PsiElement(M68kTokenType.GLOBAL_LABEL_DEF)('howto') + PsiElement(M68kTokenType.COLON)(':') M68kPreprocessorDirectiveImpl(PREPROCESSOR_DIRECTIVE) - M68kGlobalLabelImpl(GLOBAL_LABEL) - PsiElement(M68kTokenType.GLOBAL_LABEL_DEF)('howto') - PsiElement(M68kTokenType.COLON)(':') M68kPreprocessorKeywordImpl(PREPROCESSOR_KEYWORD) PsiElement(M68kTokenType.OTHER_DIRECTIVE)('incbin') PsiWhiteSpace(' ')