diff --git a/README.md b/README.md index ee524bc..14d4e1b 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,10 @@ weak warnings as missing macro evaluation will not resolve symbols defined via ` Provides the assigned value of a `=`, `set` or `equ` symbol definition when hovering over a symbol. +#### M68kMacroDefinition + +When used over a macro invocation, shows the expanded macro contents. + #### M68kLabel Shows the comments above the label (local or global) and an end-of-line comment, if available. If the first statement after the label is a directive @@ -160,6 +164,7 @@ are appreciated. It really is keeping me motivated to continue development. - Enhancement: Label documentation now also works for local labels and includes end-of-line comment for label, too. - Enhancement: Symbol definition documentation now also includes comments in the same way as the label documentation does. +- New: Macro definition / invocation documentation provider that even tries to expand macros. ### V0.7 (26-Sep-21) diff --git a/build.gradle b/build.gradle index 41a97ac..2f8f26b 100644 --- a/build.gradle +++ b/build.gradle @@ -62,6 +62,7 @@ patchPluginXml {

Full changelog available at Github project site.

""") diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/documentation/AbstractM68kDocumentationProvider.kt b/src/main/java/de/platon42/intellij/plugins/m68k/documentation/AbstractM68kDocumentationProvider.kt index 032cf3f..da64798 100644 --- a/src/main/java/de/platon42/intellij/plugins/m68k/documentation/AbstractM68kDocumentationProvider.kt +++ b/src/main/java/de/platon42/intellij/plugins/m68k/documentation/AbstractM68kDocumentationProvider.kt @@ -6,7 +6,7 @@ import com.intellij.openapi.util.text.HtmlBuilder import com.intellij.openapi.util.text.HtmlChunk import com.intellij.psi.PsiElement import de.platon42.intellij.plugins.m68k.psi.M68kNamedElement -import de.platon42.intellij.plugins.m68k.psi.M68kPsiWalkUtil +import de.platon42.intellij.plugins.m68k.psi.utils.M68kPsiWalkUtil abstract class AbstractM68kDocumentationProvider : AbstractDocumentationProvider() { @@ -27,6 +27,9 @@ abstract class AbstractM68kDocumentationProvider : AbstractDocumentationProvider fun getContent(element: PsiElement) = HtmlBuilder().append(HtmlChunk.text(element.text).code()).wrapWith(DocumentationMarkup.CONTENT_ELEMENT) + fun getContent(chunk: HtmlChunk) = + HtmlBuilder().append(chunk).wrapWith(DocumentationMarkup.CONTENT_ELEMENT) + fun getContent(value: String) = HtmlBuilder().append(value).wrapWith(DocumentationMarkup.CONTENT_ELEMENT) } \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kMacroDefinitionDocumentationProvider.kt b/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kMacroDefinitionDocumentationProvider.kt new file mode 100644 index 0000000..7fe0a93 --- /dev/null +++ b/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kMacroDefinitionDocumentationProvider.kt @@ -0,0 +1,42 @@ +package de.platon42.intellij.plugins.m68k.documentation + +import com.intellij.openapi.util.text.HtmlBuilder +import com.intellij.openapi.util.text.HtmlChunk +import com.intellij.psi.PsiElement +import com.intellij.psi.util.PsiTreeUtil +import de.platon42.intellij.plugins.m68k.psi.M68kMacroCall +import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition +import de.platon42.intellij.plugins.m68k.psi.utils.M68kMacroExpansionUtil + +class M68kMacroDefinitionDocumentationProvider : AbstractM68kDocumentationProvider() { + + override fun getQuickNavigateInfo(element: PsiElement, originalElement: PsiElement?): String? { + return generateDoc(element, originalElement) + } + + override fun generateDoc(element: PsiElement, originalElement: PsiElement?): String? { + return if (element is M68kMacroDefinition) createDoc(element, originalElement, 100) else null // TODO make this configurable + } + + override fun generateHoverDoc(element: PsiElement, originalElement: PsiElement?): String? { + return if (element is M68kMacroDefinition) createDoc(element, originalElement, 4) else null // TODO make this configurable + } + + private fun createDoc(macrodef: M68kMacroDefinition, originalElement: PsiElement?, linesLimit: Int): String { + val macroCall = PsiTreeUtil.getParentOfType(originalElement, M68kMacroCall::class.java) + val expandedMacro = M68kMacroExpansionUtil.expandMacro(macrodef, macroCall) + val builder = HtmlBuilder() + return builder + .append(getComments(macrodef)) + .append(getDefinition(HtmlChunk.text(macrodef.name!!).code())) + .append( + getContent( + HtmlBuilder().appendWithSeparators( + HtmlChunk.br(), + expandedMacro.take(linesLimit).map { HtmlChunk.text(it).code() }.toList() + ).toFragment() + ) + ) + .toString() + } +} \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kLookupUtil.kt b/src/main/java/de/platon42/intellij/plugins/m68k/psi/utils/M68kLookupUtil.kt similarity index 98% rename from src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kLookupUtil.kt rename to src/main/java/de/platon42/intellij/plugins/m68k/psi/utils/M68kLookupUtil.kt index 74c01f3..bee4b48 100644 --- a/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kLookupUtil.kt +++ b/src/main/java/de/platon42/intellij/plugins/m68k/psi/utils/M68kLookupUtil.kt @@ -1,9 +1,10 @@ -package de.platon42.intellij.plugins.m68k.psi +package de.platon42.intellij.plugins.m68k.psi.utils import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.stubs.StubIndex import com.intellij.psi.util.PsiTreeUtil +import de.platon42.intellij.plugins.m68k.psi.* import de.platon42.intellij.plugins.m68k.stubs.M68kGlobalLabelStubIndex import de.platon42.intellij.plugins.m68k.stubs.M68kMacroDefinitionStubIndex import de.platon42.intellij.plugins.m68k.stubs.M68kSymbolDefinitionStubIndex diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/psi/utils/M68kMacroExpansionUtil.kt b/src/main/java/de/platon42/intellij/plugins/m68k/psi/utils/M68kMacroExpansionUtil.kt new file mode 100644 index 0000000..165c907 --- /dev/null +++ b/src/main/java/de/platon42/intellij/plugins/m68k/psi/utils/M68kMacroExpansionUtil.kt @@ -0,0 +1,25 @@ +package de.platon42.intellij.plugins.m68k.psi.utils + +import de.platon42.intellij.plugins.m68k.psi.M68kMacroCall +import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition + +object M68kMacroExpansionUtil { + + fun expandMacro(macroDefinition: M68kMacroDefinition, macroCall: M68kMacroCall?): List { + val params = macroCall?.exprList?.map { it.text }?.toTypedArray() ?: emptyArray() + + if (params.isEmpty()) return macroDefinition.macroPlainLineList.map { it.text } + + val originalContent = macroDefinition.macroPlainLineList.joinToString("\n", transform = { it.text }) + var modifiedContent = originalContent + for (param in params.withIndex()) { + val paramRef = when (param.index) { + in 0..8 -> "\\" + (param.index + 1) + in 9..34 -> "\\" + ('a' + (param.index - 9)) + else -> "seriously?" + } + modifiedContent = modifiedContent.replace(paramRef, param.value) + } + return modifiedContent.split("\n") + } +} \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiWalkUtil.kt b/src/main/java/de/platon42/intellij/plugins/m68k/psi/utils/M68kPsiWalkUtil.kt similarity index 60% rename from src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiWalkUtil.kt rename to src/main/java/de/platon42/intellij/plugins/m68k/psi/utils/M68kPsiWalkUtil.kt index 093a12b..a2c53aa 100644 --- a/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiWalkUtil.kt +++ b/src/main/java/de/platon42/intellij/plugins/m68k/psi/utils/M68kPsiWalkUtil.kt @@ -1,16 +1,23 @@ -package de.platon42.intellij.plugins.m68k.psi +package de.platon42.intellij.plugins.m68k.psi.utils import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement import com.intellij.psi.util.PsiTreeUtil import com.intellij.util.SmartList import com.intellij.util.containers.addIfNotNull +import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition object M68kPsiWalkUtil { fun collectRelatedComments(element: PsiElement): List { val comments = SmartList() - val eolComment = PsiTreeUtil.skipWhitespacesForward(element) as? PsiComment + val eolComment = if (element is M68kMacroDefinition) { + // macro definition needs special handling of EOL comments + PsiTreeUtil.findChildOfType(element, PsiComment::class.java) + } else { + PsiTreeUtil.skipWhitespacesForward(element) as? PsiComment + } + comments.addIfNotNull(eolComment) var prevToken: PsiElement? = element do { diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/refs/M68kGlobalLabelSymbolCompletionContributor.kt b/src/main/java/de/platon42/intellij/plugins/m68k/refs/M68kGlobalLabelSymbolCompletionContributor.kt index 174aec5..9254e49 100644 --- a/src/main/java/de/platon42/intellij/plugins/m68k/refs/M68kGlobalLabelSymbolCompletionContributor.kt +++ b/src/main/java/de/platon42/intellij/plugins/m68k/refs/M68kGlobalLabelSymbolCompletionContributor.kt @@ -6,8 +6,8 @@ import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.patterns.PlatformPatterns import com.intellij.util.ProcessingContext import de.platon42.intellij.plugins.m68k.M68kIcons -import de.platon42.intellij.plugins.m68k.psi.M68kLookupUtil import de.platon42.intellij.plugins.m68k.psi.M68kTypes +import de.platon42.intellij.plugins.m68k.psi.utils.M68kLookupUtil class M68kGlobalLabelSymbolCompletionContributor : CompletionContributor() { diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/refs/M68kMacroCallCompletionContributor.kt b/src/main/java/de/platon42/intellij/plugins/m68k/refs/M68kMacroCallCompletionContributor.kt index c87369f..9df0456 100644 --- a/src/main/java/de/platon42/intellij/plugins/m68k/refs/M68kMacroCallCompletionContributor.kt +++ b/src/main/java/de/platon42/intellij/plugins/m68k/refs/M68kMacroCallCompletionContributor.kt @@ -4,8 +4,8 @@ import com.intellij.codeInsight.completion.* import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.patterns.PlatformPatterns import com.intellij.util.ProcessingContext -import de.platon42.intellij.plugins.m68k.psi.M68kLookupUtil import de.platon42.intellij.plugins.m68k.psi.M68kTypes +import de.platon42.intellij.plugins.m68k.psi.utils.M68kLookupUtil class M68kMacroCallCompletionContributor : CompletionContributor() { diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/structureview/M68kStructureViewElement.kt b/src/main/java/de/platon42/intellij/plugins/m68k/structureview/M68kStructureViewElement.kt index 461f911..7371209 100644 --- a/src/main/java/de/platon42/intellij/plugins/m68k/structureview/M68kStructureViewElement.kt +++ b/src/main/java/de/platon42/intellij/plugins/m68k/structureview/M68kStructureViewElement.kt @@ -6,8 +6,8 @@ import com.intellij.navigation.ItemPresentation import com.intellij.psi.NavigatablePsiElement import de.platon42.intellij.plugins.m68k.psi.M68kFile import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel -import de.platon42.intellij.plugins.m68k.psi.M68kLookupUtil -import de.platon42.intellij.plugins.m68k.psi.M68kLookupUtil.findAllLocalLabels +import de.platon42.intellij.plugins.m68k.psi.utils.M68kLookupUtil +import de.platon42.intellij.plugins.m68k.psi.utils.M68kLookupUtil.findAllLocalLabels class M68kStructureViewElement(private val myElement: NavigatablePsiElement) : StructureViewTreeElement { override fun getValue(): Any = myElement diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 4512213..0255fbe 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -41,6 +41,8 @@ implementationClass="de.platon42.intellij.plugins.m68k.documentation.M68kSymbolDefinitionDocumentationProvider"/> + ANIA MACRO ; the bestest macro + move.l \1,d0 + mulu d0,d0 + ENDM + """ + ) + assertThat(generateDocumentation(myFixture)) + .isEqualTo("; the bestest macro
MOLVANIA
move.l \\1,d0
mulu d0,d0
") + } + + @Test + internal fun check_expanded_documentation_for_a_macro_invocation(@MyFixture myFixture: CodeInsightTestFixture) { + myFixture.configureByText( + "documentme.asm", """ +MOLVANIA MACRO ; the bestest macro + move.l \1,d0 + mulu d0,d0 + ENDM + + MOLVANIA d1 + """ + ) + assertThat(generateDocumentation(myFixture)) + .isEqualTo("; the bestest macro
MOLVANIA
move.l d1,d0
mulu d0,d0
") + } + + @Test + internal fun check_expanded_documentation_for_a_macro_invocation_with_lots_of_params(@MyFixture myFixture: CodeInsightTestFixture) { + myFixture.configureByText( + "documentme.asm", """ +; compress nibbles +DTW MACRO + dc.b ((\1)<<4)|(\2),((\3)<<4)|(\4),((\5)<<4)|(\6),((\7)<<4)|(\8),((\9)<<4)|(\a),((\b)<<4)|(\c),((\d)<<4)|(\e),((\f)<<4)|(\g) + ENDM + + DTW 15,14,14,10,1,2,3,4,10,11,10,12,5,3,9,10 + """ + ) + assertThat(generateDocumentation(myFixture)) + .isEqualTo("; compress nibbles
DTW
dc.b ((15)<<4)|(14),((14)<<4)|(10),((1)<<4)|(2),((3)<<4)|(4),((10)<<4)|(11),((10)<<4)|(12),((5)<<4)|(3),((9)<<4)|(10)
") + } +} \ No newline at end of file