Macro definition / invocation documentation provider that even tries to expand macros.
Moved some util classes around.
This commit is contained in:
parent
cbffc3d841
commit
680b811e22
@ -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.
|
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
|
#### 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
|
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: 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.
|
- 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)
|
### V0.7 (26-Sep-21)
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ patchPluginXml {
|
|||||||
<ul>
|
<ul>
|
||||||
<li>Enhancement: Label documentation now also works for local labels and includes end-of-line comment for label, too.
|
<li>Enhancement: Label documentation now also works for local labels and includes end-of-line comment for label, too.
|
||||||
<li>Enhancement: Symbol definition documentation now also includes comments in the same way as the label documentation does.
|
<li>Enhancement: Symbol definition documentation now also includes comments in the same way as the label documentation does.
|
||||||
|
<li>New: Macro definition / invocation documentation provider that even tries to expand macros.
|
||||||
</ul>
|
</ul>
|
||||||
<p>Full changelog available at <a href="https://github.com/chrisly42/mc68000-asm-plugin#changelog">Github project site</a>.</p>
|
<p>Full changelog available at <a href="https://github.com/chrisly42/mc68000-asm-plugin#changelog">Github project site</a>.</p>
|
||||||
""")
|
""")
|
||||||
|
@ -6,7 +6,7 @@ import com.intellij.openapi.util.text.HtmlBuilder
|
|||||||
import com.intellij.openapi.util.text.HtmlChunk
|
import com.intellij.openapi.util.text.HtmlChunk
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import de.platon42.intellij.plugins.m68k.psi.M68kNamedElement
|
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() {
|
abstract class AbstractM68kDocumentationProvider : AbstractDocumentationProvider() {
|
||||||
|
|
||||||
@ -27,6 +27,9 @@ abstract class AbstractM68kDocumentationProvider : AbstractDocumentationProvider
|
|||||||
fun getContent(element: PsiElement) =
|
fun getContent(element: PsiElement) =
|
||||||
HtmlBuilder().append(HtmlChunk.text(element.text).code()).wrapWith(DocumentationMarkup.CONTENT_ELEMENT)
|
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) =
|
fun getContent(value: String) =
|
||||||
HtmlBuilder().append(value).wrapWith(DocumentationMarkup.CONTENT_ELEMENT)
|
HtmlBuilder().append(value).wrapWith(DocumentationMarkup.CONTENT_ELEMENT)
|
||||||
}
|
}
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
@ -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.openapi.project.Project
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.stubs.StubIndex
|
import com.intellij.psi.stubs.StubIndex
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
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.M68kGlobalLabelStubIndex
|
||||||
import de.platon42.intellij.plugins.m68k.stubs.M68kMacroDefinitionStubIndex
|
import de.platon42.intellij.plugins.m68k.stubs.M68kMacroDefinitionStubIndex
|
||||||
import de.platon42.intellij.plugins.m68k.stubs.M68kSymbolDefinitionStubIndex
|
import de.platon42.intellij.plugins.m68k.stubs.M68kSymbolDefinitionStubIndex
|
@ -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<String> {
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
@ -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.PsiComment
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import com.intellij.util.SmartList
|
import com.intellij.util.SmartList
|
||||||
import com.intellij.util.containers.addIfNotNull
|
import com.intellij.util.containers.addIfNotNull
|
||||||
|
import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition
|
||||||
|
|
||||||
object M68kPsiWalkUtil {
|
object M68kPsiWalkUtil {
|
||||||
|
|
||||||
fun collectRelatedComments(element: PsiElement): List<PsiComment> {
|
fun collectRelatedComments(element: PsiElement): List<PsiComment> {
|
||||||
val comments = SmartList<PsiComment>()
|
val comments = SmartList<PsiComment>()
|
||||||
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)
|
comments.addIfNotNull(eolComment)
|
||||||
var prevToken: PsiElement? = element
|
var prevToken: PsiElement? = element
|
||||||
do {
|
do {
|
@ -6,8 +6,8 @@ import com.intellij.codeInsight.lookup.LookupElementBuilder
|
|||||||
import com.intellij.patterns.PlatformPatterns
|
import com.intellij.patterns.PlatformPatterns
|
||||||
import com.intellij.util.ProcessingContext
|
import com.intellij.util.ProcessingContext
|
||||||
import de.platon42.intellij.plugins.m68k.M68kIcons
|
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.M68kTypes
|
||||||
|
import de.platon42.intellij.plugins.m68k.psi.utils.M68kLookupUtil
|
||||||
|
|
||||||
class M68kGlobalLabelSymbolCompletionContributor : CompletionContributor() {
|
class M68kGlobalLabelSymbolCompletionContributor : CompletionContributor() {
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ import com.intellij.codeInsight.completion.*
|
|||||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||||
import com.intellij.patterns.PlatformPatterns
|
import com.intellij.patterns.PlatformPatterns
|
||||||
import com.intellij.util.ProcessingContext
|
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.M68kTypes
|
||||||
|
import de.platon42.intellij.plugins.m68k.psi.utils.M68kLookupUtil
|
||||||
|
|
||||||
class M68kMacroCallCompletionContributor : CompletionContributor() {
|
class M68kMacroCallCompletionContributor : CompletionContributor() {
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@ import com.intellij.navigation.ItemPresentation
|
|||||||
import com.intellij.psi.NavigatablePsiElement
|
import com.intellij.psi.NavigatablePsiElement
|
||||||
import de.platon42.intellij.plugins.m68k.psi.M68kFile
|
import de.platon42.intellij.plugins.m68k.psi.M68kFile
|
||||||
import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel
|
import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel
|
||||||
import de.platon42.intellij.plugins.m68k.psi.M68kLookupUtil
|
import de.platon42.intellij.plugins.m68k.psi.utils.M68kLookupUtil
|
||||||
import de.platon42.intellij.plugins.m68k.psi.M68kLookupUtil.findAllLocalLabels
|
import de.platon42.intellij.plugins.m68k.psi.utils.M68kLookupUtil.findAllLocalLabels
|
||||||
|
|
||||||
class M68kStructureViewElement(private val myElement: NavigatablePsiElement) : StructureViewTreeElement {
|
class M68kStructureViewElement(private val myElement: NavigatablePsiElement) : StructureViewTreeElement {
|
||||||
override fun getValue(): Any = myElement
|
override fun getValue(): Any = myElement
|
||||||
|
@ -41,6 +41,8 @@
|
|||||||
implementationClass="de.platon42.intellij.plugins.m68k.documentation.M68kSymbolDefinitionDocumentationProvider"/>
|
implementationClass="de.platon42.intellij.plugins.m68k.documentation.M68kSymbolDefinitionDocumentationProvider"/>
|
||||||
<lang.documentationProvider language="MC68000"
|
<lang.documentationProvider language="MC68000"
|
||||||
implementationClass="de.platon42.intellij.plugins.m68k.documentation.M68kLabelDocumentationProvider"/>
|
implementationClass="de.platon42.intellij.plugins.m68k.documentation.M68kLabelDocumentationProvider"/>
|
||||||
|
<lang.documentationProvider language="MC68000"
|
||||||
|
implementationClass="de.platon42.intellij.plugins.m68k.documentation.M68kMacroDefinitionDocumentationProvider"/>
|
||||||
<lang.documentationProvider language="MC68000"
|
<lang.documentationProvider language="MC68000"
|
||||||
implementationClass="de.platon42.intellij.plugins.m68k.documentation.M68kRegisterFlowDocumentationProvider"/>
|
implementationClass="de.platon42.intellij.plugins.m68k.documentation.M68kRegisterFlowDocumentationProvider"/>
|
||||||
<lang.documentationProvider language="MC68000"
|
<lang.documentationProvider language="MC68000"
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
package de.platon42.intellij.plugins.m68k.documentation
|
||||||
|
|
||||||
|
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
||||||
|
import de.platon42.intellij.jupiter.LightCodeInsightExtension
|
||||||
|
import de.platon42.intellij.jupiter.MyFixture
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith
|
||||||
|
|
||||||
|
@ExtendWith(LightCodeInsightExtension::class)
|
||||||
|
internal class M68kMacroDefinitionDocumentationProviderTest : AbstractDocumentationProviderTest() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
internal fun check_expanded_documentation_for_a_macro_definition(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||||
|
myFixture.configureByText(
|
||||||
|
"documentme.asm", """
|
||||||
|
MOLV<caret>ANIA MACRO ; the bestest macro
|
||||||
|
move.l \1,d0
|
||||||
|
mulu d0,d0
|
||||||
|
ENDM
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
assertThat(generateDocumentation(myFixture))
|
||||||
|
.isEqualTo("<span class=\"grayed\">; the bestest macro</span><div class=\"definition\"><code>MOLVANIA</code></div><div class=\"content\"><code> move.l \\1,d0</code><br/><code> mulu d0,d0</code></div>")
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
|
MOLV<caret>ANIA d1
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
assertThat(generateDocumentation(myFixture))
|
||||||
|
.isEqualTo("<span class=\"grayed\">; the bestest macro</span><div class=\"definition\"><code>MOLVANIA</code></div><div class=\"content\"><code> move.l d1,d0</code><br/><code> mulu d0,d0</code></div>")
|
||||||
|
}
|
||||||
|
|
||||||
|
@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<caret> 15,14,14,10,1,2,3,4,10,11,10,12,5,3,9,10
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
assertThat(generateDocumentation(myFixture))
|
||||||
|
.isEqualTo("<span class=\"grayed\">; compress nibbles</span><div class=\"definition\"><code>DTW</code></div><div class=\"content\"><code> 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)</code></div>")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user