diff --git a/build.gradle b/build.gradle index 4e43411..5ee55a4 100644 --- a/build.gradle +++ b/build.gradle @@ -66,6 +66,7 @@ patchPluginXml {
  • New: Added semantic highlighting. Currently available for data and address registers and local labels.
  • Bugfix: addq/subq for address register stated it would affect the condition codes, which it in fact doesn't.
  • New: Added simple custom navigation bar. +
  • New: Added folding support for functions and macro definitions.

    Full changelog available at Github project site.

    """) diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/folding/M68kFoldingBuilder.kt b/src/main/java/de/platon42/intellij/plugins/m68k/folding/M68kFoldingBuilder.kt new file mode 100644 index 0000000..a708622 --- /dev/null +++ b/src/main/java/de/platon42/intellij/plugins/m68k/folding/M68kFoldingBuilder.kt @@ -0,0 +1,67 @@ +package de.platon42.intellij.plugins.m68k.folding + +import com.intellij.lang.ASTNode +import com.intellij.lang.folding.FoldingBuilderEx +import com.intellij.lang.folding.FoldingDescriptor +import com.intellij.openapi.editor.Document +import com.intellij.openapi.project.DumbAware +import com.intellij.psi.PsiElement +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.refactoring.suggested.endOffset +import com.intellij.refactoring.suggested.startOffset +import de.platon42.intellij.plugins.m68k.psi.M68kFile +import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition +import de.platon42.intellij.plugins.m68k.psi.M68kStatement +import de.platon42.intellij.plugins.m68k.psi.utils.M68kPsiWalkUtil.getBeginningOfRelatedComment +import de.platon42.intellij.plugins.m68k.psi.utils.M68kPsiWalkUtil.isSignificantLine + +class M68kFoldingBuilder : FoldingBuilderEx(), DumbAware { + + override fun buildFoldRegions(root: PsiElement, document: Document, quick: Boolean): Array { + if (root !is M68kFile) return FoldingDescriptor.EMPTY + + val descriptors = ArrayList() + var lineElement = root.firstChild + var foldingOpen = false + var foldingStart: PsiElement? = null + var foldingName: String? = null + var lastStatement = lineElement as? M68kStatement + while (lineElement != null) { + if (lineElement is M68kMacroDefinition) { + val fd = FoldingDescriptor(lineElement, lineElement.startOffset, lineElement.endOffset, null, "[[[ MACRO " + lineElement.name!! + " ]]]") + descriptors.add(fd) + } + if (lineElement is M68kStatement) { + val label = lineElement.globalLabel + if (label != null) { + foldingOpen = true + foldingStart = getBeginningOfRelatedComment(lineElement) + foldingName = "[[[ ${label.name} ]]]" + } + lastStatement = lineElement + } + lineElement = PsiTreeUtil.skipWhitespacesAndCommentsForward(lineElement) + if (foldingOpen) { + val stopIt = (lineElement == null) || isSignificantLine(lineElement) + if (stopIt) { + val fd = FoldingDescriptor( + foldingStart!!.parent!!, + foldingStart.startOffsetInParent, lastStatement!!.textRangeInParent.endOffset, + null, foldingName!! + ) + descriptors.add(fd) + foldingOpen = false + } + } + } + return descriptors.toArray(FoldingDescriptor.EMPTY) + } + + override fun getPlaceholderText(node: ASTNode): String? { + return "..." + } + + override fun isCollapsedByDefault(node: ASTNode): Boolean { + return false + } +} \ No newline at end of file diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/psi/utils/M68kPsiWalkUtil.kt b/src/main/java/de/platon42/intellij/plugins/m68k/psi/utils/M68kPsiWalkUtil.kt index 2e48435..b645f7a 100644 --- a/src/main/java/de/platon42/intellij/plugins/m68k/psi/utils/M68kPsiWalkUtil.kt +++ b/src/main/java/de/platon42/intellij/plugins/m68k/psi/utils/M68kPsiWalkUtil.kt @@ -2,6 +2,7 @@ package de.platon42.intellij.plugins.m68k.psi.utils import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement +import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.util.PsiTreeUtil import com.intellij.util.SmartList import com.intellij.util.containers.addIfNotNull @@ -31,6 +32,31 @@ object M68kPsiWalkUtil { return comments.reversed() } + fun getBeginningOfRelatedComment(lineElement: PsiElement): PsiElement { + // go back to catch comments that are not more than one empty line away + var relStart = lineElement + var prevLine = relStart.prevSibling ?: return lineElement + var eolCount = 2 + do { + if (prevLine is PsiComment) { + relStart = prevLine + eolCount = 1 + } else if (prevLine is PsiWhiteSpace) { + if (--eolCount < 0) break + } else { + break + } + prevLine = prevLine.prevSibling ?: break + } while (true) + return relStart + } + + fun isSignificantLine(element: PsiElement) = when (element) { + is M68kStatement -> (element.assignment != null) || (element.globalLabel != null) + is M68kMacroDefinition -> true + else -> false + } + fun findStatementForElement(psiElement: PsiElement): M68kStatement? { if (psiElement is M68kStatement) return psiElement if (psiElement.parent is M68kFile) { diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index f38a04f..29e6add 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -21,6 +21,9 @@ implementationClass="de.platon42.intellij.plugins.m68k.parser.M68kParserDefinition"/> + diff --git a/src/test/java/de/platon42/intellij/plugins/m68k/folding/M68kFoldingBuilderTest.kt b/src/test/java/de/platon42/intellij/plugins/m68k/folding/M68kFoldingBuilderTest.kt new file mode 100644 index 0000000..de90023 --- /dev/null +++ b/src/test/java/de/platon42/intellij/plugins/m68k/folding/M68kFoldingBuilderTest.kt @@ -0,0 +1,19 @@ +package de.platon42.intellij.plugins.m68k.folding + +import com.intellij.testFramework.fixtures.CodeInsightTestFixture +import de.platon42.intellij.jupiter.LightCodeInsightExtension +import de.platon42.intellij.jupiter.MyFixture +import de.platon42.intellij.jupiter.TestDataPath +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@TestDataPath("src/test/resources/folding") +@ExtendWith(LightCodeInsightExtension::class) +internal class M68kFoldingBuilderTest { + + @Test + internal fun check_documentation_for_a_symbol_definition(@MyFixture myFixture: CodeInsightTestFixture) { + myFixture.testFolding(myFixture.testDataPath + "/folding.asm") + } +} \ No newline at end of file diff --git a/src/test/resources/folding/folding.asm b/src/test/resources/folding/folding.asm new file mode 100644 index 0000000..60c0f9e --- /dev/null +++ b/src/test/resources/folding/folding.asm @@ -0,0 +1,46 @@ +; this is a test + +FOO = 1 +; this is the main demo routine +demo_main: + moveq.l #0,d0 + rts + +; data area starts here +.data dc.w 10,0 + even + +; this is an unrelated comment + +; this is another folding area +; could be anything. + +intro_part1 + dc.w $47fe + illegal + rts + +; this comment is two lines away + + +intro_part2: + moveq.l #0,d1 + rts + +; standard macros +BLTWAIT MACRO +.bw\@ + btst #DMAB_BLTDONE-8,dmaconr(a5) + bne.s .bw\@ + ENDM + +********************** foobar + + +some_more_data: + dc.w $123 + dc.w $345 + dc.w $333 + dc.w $222 + +CUBE_SIZE = 100