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.
|
||||
|
||||
#### 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)
|
||||
|
||||
|
@ -62,6 +62,7 @@ patchPluginXml {
|
||||
<ul>
|
||||
<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>New: Macro definition / invocation documentation provider that even tries to expand macros.
|
||||
</ul>
|
||||
<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.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)
|
||||
}
|
@ -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.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
|
@ -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.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<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)
|
||||
var prevToken: PsiElement? = element
|
||||
do {
|
@ -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() {
|
||||
|
||||
|
@ -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() {
|
||||
|
||||
|
@ -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
|
||||
|
@ -41,6 +41,8 @@
|
||||
implementationClass="de.platon42.intellij.plugins.m68k.documentation.M68kSymbolDefinitionDocumentationProvider"/>
|
||||
<lang.documentationProvider language="MC68000"
|
||||
implementationClass="de.platon42.intellij.plugins.m68k.documentation.M68kLabelDocumentationProvider"/>
|
||||
<lang.documentationProvider language="MC68000"
|
||||
implementationClass="de.platon42.intellij.plugins.m68k.documentation.M68kMacroDefinitionDocumentationProvider"/>
|
||||
<lang.documentationProvider language="MC68000"
|
||||
implementationClass="de.platon42.intellij.plugins.m68k.documentation.M68kRegisterFlowDocumentationProvider"/>
|
||||
<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