Added folding support for functions and macro definitions.
This commit is contained in:
parent
f87bc7fea9
commit
cd0bcd22ff
@ -66,6 +66,7 @@ patchPluginXml {
|
||||
<li>New: Added semantic highlighting. Currently available for data and address registers and local labels.
|
||||
<li>Bugfix: addq/subq for address register stated it would affect the condition codes, which it in fact doesn't.
|
||||
<li>New: Added simple custom navigation bar.
|
||||
<li>New: Added folding support for functions and macro definitions.
|
||||
</ul>
|
||||
<p>Full changelog available at <a href="https://github.com/chrisly42/mc68000-asm-plugin#changelog">Github project site</a>.</p>
|
||||
""")
|
||||
|
@ -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<FoldingDescriptor> {
|
||||
if (root !is M68kFile) return FoldingDescriptor.EMPTY
|
||||
|
||||
val descriptors = ArrayList<FoldingDescriptor>()
|
||||
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
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
@ -21,6 +21,9 @@
|
||||
implementationClass="de.platon42.intellij.plugins.m68k.parser.M68kParserDefinition"/>
|
||||
<lang.syntaxHighlighterFactory language="MC68000"
|
||||
implementationClass="de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighterFactory"/>
|
||||
<lang.foldingBuilder
|
||||
language="MC68000"
|
||||
implementationClass="de.platon42.intellij.plugins.m68k.folding.M68kFoldingBuilder"/>
|
||||
<navbar implementation="de.platon42.intellij.plugins.m68k.navigation.M68kStructureAwareNavbar"/>
|
||||
<highlightVisitor implementation="de.platon42.intellij.plugins.m68k.syntax.M68kRainbowVisitor"/>
|
||||
<colorSettingsPage implementation="de.platon42.intellij.plugins.m68k.syntax.M68kColorSettingsPage"/>
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
46
src/test/resources/folding/folding.asm
Normal file
46
src/test/resources/folding/folding.asm
Normal file
@ -0,0 +1,46 @@
|
||||
; this is a test
|
||||
|
||||
FOO = 1
|
||||
<fold text='[[[ demo_main ]]]'>; this is the main demo routine
|
||||
demo_main:
|
||||
moveq.l #0,d0
|
||||
rts
|
||||
|
||||
; data area starts here
|
||||
.data dc.w 10,0
|
||||
even</fold>
|
||||
|
||||
; this is an unrelated comment
|
||||
|
||||
<fold text='[[[ intro_part1 ]]]'>; this is another folding area
|
||||
; could be anything.
|
||||
|
||||
intro_part1
|
||||
dc.w $47fe
|
||||
illegal
|
||||
rts</fold>
|
||||
|
||||
; this comment is two lines away
|
||||
|
||||
|
||||
<fold text='[[[ intro_part2 ]]]'>intro_part2:
|
||||
moveq.l #0,d1
|
||||
rts</fold>
|
||||
|
||||
; standard macros
|
||||
<fold text='[[[ MACRO BLTWAIT ]]]'>BLTWAIT MACRO
|
||||
.bw\@
|
||||
btst #DMAB_BLTDONE-8,dmaconr(a5)
|
||||
bne.s .bw\@
|
||||
ENDM</fold>
|
||||
|
||||
********************** foobar
|
||||
|
||||
|
||||
<fold text='[[[ some_more_data ]]]'>some_more_data:
|
||||
dc.w $123
|
||||
dc.w $345
|
||||
dc.w $333
|
||||
dc.w $222</fold>
|
||||
|
||||
CUBE_SIZE = 100
|
Loading…
Reference in New Issue
Block a user