Compare commits

...

9 Commits
v0.9 ... main

40 changed files with 1094 additions and 97 deletions

View File

@ -1,4 +1,4 @@
# MC68000 Assembly Language Plugin [![Build Status](https://app.travis-ci.com/chrisly42/mc68000-asm-plugin.svg?branch=master)](https://app.travis-ci.com/chrisly42/mc68000-asm-plugin)
# MC68000 Assembly Language Plugin
_MC68000 Assembly Language Plugin_ is plugin for Jetbrains IDEs (CLion, IntelliJ, etc.).
@ -133,6 +133,7 @@ If the current statement has no valid syntax, the instruction details of all mat
- Switching the spaces option usually needs the caches to be invalidated. Find Usages word scanner always uses default settings, as it is not configurable per
project :-/
- Unit Test coverage is not as good as it could be (ahem).
- Code flow sometimes outputs "uhm?"
- Missing but planned features:
- Macro evaluation on invocation
- Folding
@ -149,9 +150,10 @@ to highlight the same address and data registers while editing (see new `View ->
## Development notice
This plugin has been written in Kotlin 1.5 using Grammar-Kit.
This plugin has been written in Kotlin 1.9 using Grammar-Kit.
It is probably the only plugin (besides [Cajon](https://github.com/chrisly42/cajon-plugin) from the same author) that uses JUnit 5 Jupiter for unit testing so
It is probably the only plugin (besides [Cajon](https://git.platon42.de/chrisly42/cajon-plugin) from the same author) that uses JUnit 5 Jupiter for unit testing
so
far (or at least the only one I'm aware of ;) ). The IntelliJ framework actually uses the JUnit 3 TestCase for plugin testing, and it took me quite a while to
make it work with JUnit 5. Feel free to use the code (in package ```de.platon42.intellij.jupiter```) for your projects (with attribution).
@ -164,6 +166,19 @@ are appreciated. It really is keeping me motivated to continue development.
## Changelog
### V0.10 (20-Feb-24)
- Decided to release some features that have been sitting on my harddrive for almost two years, but never got released,
because I was unable to get that damn formatter working in a way that was acceptable (the API and the docs are easily one
the worst abominations I've come across).
- Maintenance. Updated all dependencies to the latest versions.
- 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.
- New: Added assembler directives to code completion (only lower-case except for other directives like IF
and MACRO, which are only suggested for upper-case).
### V0.9 (16-Aug-22)
- Maintenance. Updated all dependencies to the latest versions.
@ -249,4 +264,4 @@ are appreciated. It really is keeping me motivated to continue development.
### V0.1 (20-Jul-21)
- Initial public release.
- Initial public release.

View File

@ -1,74 +1,64 @@
plugins {
id 'java'
id 'org.jetbrains.intellij' version '1.8.0'
id 'org.jetbrains.kotlin.jvm' version '1.7.10'
id 'org.jetbrains.intellij' version '1.17.1'
id 'org.jetbrains.kotlin.jvm' version '1.9.22'
id 'jacoco'
id 'com.github.kt3k.coveralls' version '2.12.0'
}
group = 'de.platon42'
version = '0.9'
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
version = '0.10'
sourceCompatibility = 17
targetCompatibility = 17
repositories {
mavenCentral()
}
/*
To run tests in IntelliJ use these VM Options for run configuration
To run tests in IntelliJ use these VM Options for run configuration
-ea -Didea.system.path=build/idea-sandbox/system-test -Didea.config.path=build/idea-sandbox/config-test -Didea.plugins.path=build/idea-sandbox/plugins-test
*/
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
testImplementation 'org.assertj:assertj-core:3.23.1'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
testImplementation 'org.assertj:assertj-core:3.25.3'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
testImplementation "org.jetbrains.kotlin:kotlin-test"
testImplementation "org.jetbrains.kotlin:kotlin-reflect"
testImplementation 'org.junit.platform:junit-platform-launcher:1.9.0'
testImplementation 'org.junit.platform:junit-platform-launcher:1.10.2'
// testImplementation "org.jetbrains.kotlin:kotlin-test-junit"
}
compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs += "-Xjvm-default=all"
}
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
intellij {
setVersion("2022.2") // LATEST-EAP-SNAPSHOT
setVersion("2022.3") // LATEST-EAP-SNAPSHOT
setUpdateSinceUntilBuild(false)
// setPlugins(["com.intellij.java"])
}
runPluginVerifier {
ideVersions = ["IC-203.6682.168", "IC-222.3345.118", // 2020.3 - 2022.2
"CL-203.8084.11", // 2020.3
"CL-211.7628.27", // 2021.1
"CL-212.5712.21", // 2021.2
"CL-213.7172.20", // 2021.3.4
"CL-221.5080.224", // 2022.1
"CL-222.3345.126"] // 2022.2
ideVersions = ["IC-203.6682.168", "IC-233.14015.106", // 2020.3 - 2023.3
"CL-203.8084.11", "CL-233.14015.92"] // 2020.3 - 2023.3
downloadDir = System.getProperty("user.home") + "/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.idea/verifier"
}
patchPluginXml {
setChangeNotes("""
<h4>V0.9 (16-Aug-22)</h4>
<h4>V0.10 (20-Feb-24)</h4>
<ul>
<li>Decided to release some features that have been sitting on my harddrive for almost two years, but never got released,
because I was unable to get that damn formatter working in a way that was acceptable (the API and the docs are easily one
the worst abominations I've come across).
<li>Maintenance. Updated all dependencies to the latest versions.
<li>Bugfix: Fixed condition code for asr/lsr/lsl, which is has a different behaviour for V flag than asl.
<li>Bugfix: Fixed 'Unknown op size' exception when uppercase sizes were used.
<li>Bugfix: Refactoring was broken for newer IDE versions, at least for me, this now works again by unknown magic.
<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.
<li>New: Added assembler directives to code completion (only lower-case except for other directives like IF
and MACRO, which are only suggested for upper-case).
</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://git.platon42.de/chrisly42/mc68000-asm-plugin#changelog">Gitea project site</a>.</p>
""")
}
@ -84,10 +74,6 @@ test {
}
}
tasks.coveralls {
dependsOn jacocoTestReport
}
jacoco {
toolVersion = '0.8.8'
}
@ -101,4 +87,4 @@ jacocoTestReport {
publishPlugin {
setToken(intellijPublishToken)
}
}

View File

@ -1,4 +1,4 @@
kotlin.code.style=official
kotlin.incremental=true
intellijPublishToken=perm:dummy
systemProp.jdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2"
systemProp.jdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2"

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

17
plans.txt Normal file
View File

@ -0,0 +1,17 @@
Formatting:
- dc.w statements: Pressing return will automatically add dc.w in next line (plus tabs)
Showing of used registers in selection
Actions:
- Replace constant by symbol (with suggestion)
- Converting of hex values into decimal values and vice versa
- convert new style to old style
- convert old style to new style
- simplify explicit mnemonics (e.g. movea)
Marker:
- go to source register setter
- go to target register setter
- Can we add "find declaration to go for registers"

View File

@ -649,22 +649,12 @@ public class M68kParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// AsmInstruction | MacroCall
// AsmInstruction | MacroCall | PreprocessorDirective
static boolean Instruction(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "Instruction")) return false;
if (!nextTokenIs(b, "", MACRO_INVOCATION, MNEMONIC)) return false;
boolean r;
r = AsmInstruction(b, l + 1);
if (!r) r = MacroCall(b, l + 1);
return r;
}
/* ********************************************************** */
// Instruction|PreprocessorDirective
static boolean InstructionOnly(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "InstructionOnly")) return false;
boolean r;
r = Instruction(b, l + 1);
if (!r) r = PreprocessorDirective(b, l + 1);
return r;
}
@ -681,13 +671,13 @@ public class M68kParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// LabelWithInstruction | LabelOnly | InstructionOnly
// LabelWithInstruction | LabelOnly | Instruction
static boolean LabelInsts(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "LabelInsts")) return false;
boolean r;
r = LabelWithInstruction(b, l + 1);
if (!r) r = LabelOnly(b, l + 1);
if (!r) r = InstructionOnly(b, l + 1);
if (!r) r = Instruction(b, l + 1);
return r;
}
@ -698,27 +688,18 @@ public class M68kParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// Label (Instruction|PreprocessorDirective)
// Label Instruction
static boolean LabelWithInstruction(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "LabelWithInstruction")) return false;
if (!nextTokenIs(b, "", GLOBAL_LABEL_DEF, LOCAL_LABEL_DEF)) return false;
boolean r;
Marker m = enter_section_(b);
r = Label(b, l + 1);
r = r && LabelWithInstruction_1(b, l + 1);
r = r && Instruction(b, l + 1);
exit_section_(b, m, null, r);
return r;
}
// Instruction|PreprocessorDirective
private static boolean LabelWithInstruction_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "LabelWithInstruction_1")) return false;
boolean r;
r = Instruction(b, l + 1);
if (!r) r = PreprocessorDirective(b, l + 1);
return r;
}
/* ********************************************************** */
// LOCAL_LABEL_DEF COLON?
public static boolean LocalLabel(PsiBuilder b, int l) {

View File

@ -10,7 +10,7 @@ class M68kFileElementType private constructor() : ILightStubFileElementType<PsiF
@JvmField
val INSTANCE = M68kFileElementType()
const val STUB_VERSION = 7
const val STUB_VERSION = 8
const val STUB_EXTERNAL_ID_PREFIX = "MC68000."
const val EXTERNAL_ID = STUB_EXTERNAL_ID_PREFIX + "FILE"
}

View File

@ -19,7 +19,9 @@ object AssemblerDirectives {
"align", "even", "odd", "cnop", "long", "dphrase", "phrase", "qphrase",
"cargs", "comm", "comment",
"rsset", "clrfo", "clrso", "setfo", "setso"
"rsset", "clrfo", "clrso", "setfo", "setso",
"rsreset", "rs.b", "rs.w", "rs.l"
)
val plainDirectives: Set<String> = setOf(

View File

@ -0,0 +1,27 @@
package de.platon42.intellij.plugins.m68k.asm
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.M68kIcons
import de.platon42.intellij.plugins.m68k.psi.M68kTypes
class M68kDirectiveCompletionContributor : CompletionContributor() {
companion object {
val DIRECTIVES =
listOf(AssemblerDirectives.dataDirectives, AssemblerDirectives.plainDirectives, AssemblerDirectives.otherDirectives.map(String::uppercase))
.flatten()
.toSortedSet()
.map { PrioritizedLookupElement.withPriority(LookupElementBuilder.create(it).withIcon(M68kIcons.MNEMONIC), 1.5) }
}
init {
extend(CompletionType.BASIC, PlatformPatterns.psiElement(M68kTypes.MACRO_INVOCATION), object : CompletionProvider<CompletionParameters>() {
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, resultSet: CompletionResultSet) {
resultSet.addAllElements(DIRECTIVES)
}
})
}
}

View File

@ -294,7 +294,7 @@ object M68kIsa {
AllowedAdrMode(
setOf(AddressMode.IMMEDIATE_DATA), ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL, modInfo = RWM_MODIFY_OP2_OPSIZE, affectedCc = cc("C****")
),
AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), AREG_ONLY, size = OP_SIZE_WL, modInfo = RWM_MODIFY_OP2_L, affectedCc = cc("C****"))
AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), AREG_ONLY, size = OP_SIZE_WL, modInfo = RWM_MODIFY_OP2_L)
)
private val ADDX_SUBX_MODES = listOf(

View File

@ -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
}
}

View File

@ -0,0 +1,23 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Alignment
import com.intellij.formatting.Block
import com.intellij.formatting.Spacing
import com.intellij.formatting.Wrap
import com.intellij.lang.ASTNode
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
class M68kAsmAssignmentBlock(
node: ASTNode, wrap: Wrap?, alignment: Alignment?,
private val codeStyleSettings: CodeStyleSettings
) : AbstractBlock(node, wrap, alignment) {
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
return Spacing.getReadOnlySpacing()
}
override fun isLeaf() = true
override fun buildChildren() = emptyList<Block>()
}

View File

@ -0,0 +1,62 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Alignment
import com.intellij.formatting.Block
import com.intellij.formatting.Spacing
import com.intellij.formatting.Wrap
import com.intellij.lang.ASTNode
import com.intellij.psi.TokenType
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
import de.platon42.intellij.plugins.m68k.psi.M68kTypes
class M68kAsmBlock(
node: ASTNode, wrap: Wrap?, alignment: Alignment?,
val column: Int,
private val codeStyleSettings: CodeStyleSettings
) : AbstractBlock(node, wrap, alignment) {
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
if (child1 is M68kAsmBlock && child2 is M68kAsmBlock) {
val columnDiff = child2.column - child1.column
if (columnDiff > 0) {
var minSpaces = columnDiff * codeStyleSettings.indentOptions.INDENT_SIZE - child1.node.textLength
while (minSpaces < 1) {
minSpaces += codeStyleSettings.indentOptions.INDENT_SIZE
}
return Spacing.createSpacing(minSpaces, minSpaces, 0, false, 0)
}
}
return null
}
override fun isLeaf() = (node.firstChildNode == null)
override fun buildChildren(): List<Block> {
val subBlocks = ArrayList<Block>()
if (myNode.elementType == M68kTypes.ASM_OP) {
return subBlocks
}
var child = myNode.firstChildNode
var newColumn = column
while (child != null) {
if (child.elementType != TokenType.WHITE_SPACE) {
subBlocks.add(
M68kAsmBlock(
child,
null,
null,
newColumn,
codeStyleSettings
)
)
if (child.elementType == M68kTypes.ASM_OP) {
newColumn += 2
}
}
child = child.treeNext
}
return subBlocks
}
}

View File

@ -0,0 +1,7 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CustomCodeStyleSettings
class M68kAsmCodeStyleSettings(container: CodeStyleSettings) : CustomCodeStyleSettings("MC68000AsmCodeStyleSettings", container) {
}

View File

@ -0,0 +1,31 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.application.options.CodeStyleAbstractConfigurable
import com.intellij.application.options.CodeStyleAbstractPanel
import com.intellij.application.options.TabbedLanguageCodeStylePanel
import com.intellij.psi.codeStyle.CodeStyleConfigurable
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CodeStyleSettingsProvider
import com.intellij.psi.codeStyle.CustomCodeStyleSettings
import de.platon42.intellij.plugins.m68k.MC68000Language
class M68kAsmCodeStyleSettingsProvider : CodeStyleSettingsProvider() {
override fun createCustomSettings(settings: CodeStyleSettings): CustomCodeStyleSettings {
return M68kAsmCodeStyleSettings(settings)
}
override fun createConfigurable(settings: CodeStyleSettings, modelSettings: CodeStyleSettings): CodeStyleConfigurable {
return object : CodeStyleAbstractConfigurable(settings, modelSettings, configurableDisplayName) {
override fun createPanel(settings: CodeStyleSettings): CodeStyleAbstractPanel {
return M68kAsmCodeStyleMainPanel(currentSettings, settings)
}
}
}
override fun getConfigurableDisplayName() = "M68k"
private class M68kAsmCodeStyleMainPanel(currentSettings: CodeStyleSettings, settings: CodeStyleSettings) :
TabbedLanguageCodeStylePanel(MC68000Language.INSTANCE, currentSettings, settings)
}

View File

@ -0,0 +1,21 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Block
import com.intellij.formatting.Spacing
import com.intellij.lang.ASTNode
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
class M68kAsmCommentBlock(
node: ASTNode,
private val codeStyleSettings: CodeStyleSettings
) : AbstractBlock(node, null, null) {
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
return Spacing.getReadOnlySpacing()
}
override fun isLeaf() = true
override fun buildChildren() = emptyList<Block>()
}

View File

@ -0,0 +1,14 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Block
import com.intellij.lang.ASTNode
import com.intellij.psi.formatter.common.AbstractBlock
class M68kAsmEolBlock(node: ASTNode) : AbstractBlock(node, null, null) {
override fun getSpacing(child1: Block?, child2: Block) = null
override fun isLeaf() = true
override fun buildChildren() = emptyList<Block>()
}

View File

@ -0,0 +1,19 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.FormattingContext
import com.intellij.formatting.FormattingModel
import com.intellij.formatting.FormattingModelBuilder
import com.intellij.formatting.FormattingModelProvider
class M68kAsmFormattingModelBuilder : FormattingModelBuilder {
override fun createModel(formattingContext: FormattingContext): FormattingModel {
val codeStyleSettings = formattingContext.codeStyleSettings
return FormattingModelProvider.createFormattingModelForPsiFile(
formattingContext.containingFile,
M68kAsmRootBlock(formattingContext.node, codeStyleSettings),
codeStyleSettings
)
}
}

View File

@ -0,0 +1,23 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Alignment
import com.intellij.formatting.Block
import com.intellij.formatting.Spacing
import com.intellij.formatting.Wrap
import com.intellij.lang.ASTNode
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
class M68kAsmLabelBlock(
node: ASTNode, wrap: Wrap?, alignment: Alignment?,
private val codeStyleSettings: CodeStyleSettings
) : AbstractBlock(node, wrap, alignment) {
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
return Spacing.getReadOnlySpacing()
}
override fun isLeaf() = true
override fun buildChildren() = emptyList<Block>()
}

View File

@ -0,0 +1,21 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Block
import com.intellij.formatting.Spacing
import com.intellij.lang.ASTNode
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
class M68kAsmMacroDefBlock(
node: ASTNode,
private val codeStyleSettings: CodeStyleSettings
) : AbstractBlock(node, null, null) {
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
return Spacing.getReadOnlySpacing()
}
override fun isLeaf() = true
override fun buildChildren() = emptyList<Block>()
}

View File

@ -0,0 +1,70 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Block
import com.intellij.formatting.Indent
import com.intellij.formatting.Spacing
import com.intellij.lang.ASTNode
import com.intellij.psi.PsiComment
import com.intellij.psi.TokenType
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition
import de.platon42.intellij.plugins.m68k.psi.M68kStatement
import de.platon42.intellij.plugins.m68k.psi.M68kTypes
class M68kAsmRootBlock(node: ASTNode, private val codeStyleSettings: CodeStyleSettings) : AbstractBlock(node, null, null) {
override fun getIndent(): Indent? {
return Indent.getAbsoluteNoneIndent()
}
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
if (child2 is M68kAsmEolBlock) {
return Spacing.createSpacing(0, 0, 0, false, 0)
//return null
}
if (child2 is M68kAsmMacroDefBlock) {
return child2.getSpacing(child1, child2)
}
if (child2 is M68kAsmCommentBlock) {
if (child1 is M68kAsmStatementBlock) {
val indentSize = codeStyleSettings.indentOptions.INDENT_SIZE
val oddIdent = indentSize - (child1.node.textLength % indentSize)
return Spacing.createSpacing(oddIdent, Integer.MAX_VALUE, 0, false, 0)
} else {
return Spacing.getReadOnlySpacing()
}
}
if (child2.subBlocks.isNotEmpty()) {
return child2.getSpacing(child1, child2.subBlocks.first())
}
return null
}
override fun isLeaf(): Boolean {
return false
}
override fun buildChildren(): List<Block> {
val subBlocks = ArrayList<Block>()
var child = myNode.firstChildNode
while (child != null) {
if (child.elementType == M68kTypes.EOL) {
subBlocks.add(M68kAsmEolBlock(child))
} else if (child.elementType != TokenType.WHITE_SPACE) {
if (child.psi is M68kStatement) {
subBlocks.add(M68kAsmStatementBlock(child, codeStyleSettings))
} else if (child.psi is M68kMacroDefinition) {
subBlocks.add(M68kAsmMacroDefBlock(child, codeStyleSettings))
} else if (child.psi is PsiComment) {
subBlocks.add(M68kAsmCommentBlock(child, codeStyleSettings))
} else {
subBlocks.add(M68kAsmBlock(child, null, null, 0, codeStyleSettings))
}
}
child = child.treeNext
}
return subBlocks
}
}

View File

@ -0,0 +1,74 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Block
import com.intellij.formatting.Indent
import com.intellij.formatting.Spacing
import com.intellij.lang.ASTNode
import com.intellij.psi.TokenType
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
import de.platon42.intellij.plugins.m68k.psi.*
class M68kAsmStatementBlock(node: ASTNode, private val codeStyleSettings: CodeStyleSettings) :
AbstractBlock(node, null, null) {
override fun getIndent(): Indent? {
val statement = myNode.psi as M68kStatement
if (((statement.asmInstruction != null) || (statement.asmInstruction != null) || (statement.preprocessorDirective != null)
|| (statement.macroCall != null))
&& ((statement.localLabel == null) && (statement.globalLabel == null))
) {
return null
} else {
return Indent.getAbsoluteNoneIndent()
}
}
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
if (child2 is M68kAsmBlock) {
val indentSize = codeStyleSettings.indentOptions.INDENT_SIZE * child2.column
if (child1 is M68kAsmEolBlock || child1 is M68kAsmCommentBlock) {
return Spacing.createSpacing(indentSize, indentSize, 0, true, 0)
}
if (child1 is M68kAsmLabelBlock) {
val spacesLeft = indentSize - child1.node.textLength
if (spacesLeft <= 0) {
return Spacing.createSpacing(0, 0, 1, true, 0)
} else {
return Spacing.createSpacing(spacesLeft, spacesLeft, 0, true, 0)
}
}
return Spacing.createSpacing(indentSize, indentSize, 0, true, 0)
}
if (child2 is M68kAsmLabelBlock || child2 is M68kAsmAssignmentBlock) {
return Spacing.createSpacing(0, 0, 0, true, 0)
}
return null
}
override fun isLeaf() = false
override fun buildChildren(): List<Block> {
val subBlocks = ArrayList<Block>()
var child = myNode.firstChildNode
while (child != null) {
if (child.elementType != TokenType.WHITE_SPACE) {
val element = child.psi
when (element) {
is M68kAssignment -> subBlocks.add(M68kAsmAssignmentBlock(child, null, null, codeStyleSettings))
is M68kAsmInstruction, is M68kPreprocessorDirective, is M68kMacroCall ->
subBlocks.add(M68kAsmBlock(child, null, null, 2, codeStyleSettings))
is M68kGlobalLabel, is M68kLocalLabel ->
subBlocks.add(M68kAsmLabelBlock(child, null, null, codeStyleSettings))
else -> subBlocks.add(M68kAsmBlock(child, null, null, 1, codeStyleSettings))
}
}
child = child.treeNext
}
return subBlocks
}
}

View File

@ -0,0 +1,41 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider
import de.platon42.intellij.plugins.m68k.MC68000Language
class M68kLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvider() {
override fun getLanguage() = MC68000Language.INSTANCE
override fun getCodeSample(settingsType: SettingsType) = """; This is an example assembly language program
PIC_HEIGHT = 256
include "../includes/hardware/custom.i"
BLTHOGON MACRO ; macro definition
move.w #DMAF_SETCLR|DMAF_BLITHOG,dmacon(a5) ; hog!
ENDM
demo_init ; global label
tst.w d1
beq.s .skip
PUSHM d0-d7/a0-a6 ; this is a macro call
lea hello(pc),a1
lea pd_ModViewTable(a4,d1.w),a0
moveq.l #0,d0
move.w #PIC_HEIGHT-1,d7
.loop move.l d0,(a0)+ ; local label
dbra d7,.loop
POPM
.skip rts
irq: move.l a0,-(sp)
move usp,a0
move.l a0,${'$'}400.w
move.l (sp)+,a0
rte
hello: dc.b 'Hello World!',10,0
even
dc.w *-hello ; length of string
"""
}

View File

@ -136,11 +136,10 @@ SymbolDefinition ::= SYMBOLDEF {
Assignment ::= SymbolDefinition COLON? (OP_ASSIGN|EQU) expr
private LabelInsts ::= LabelWithInstruction | LabelOnly | InstructionOnly
private LabelInsts ::= LabelWithInstruction | LabelOnly | Instruction
private LabelOnly ::= Label
private LabelWithInstruction ::= Label (Instruction|PreprocessorDirective)
private InstructionOnly ::= (Instruction|PreprocessorDirective)
private LabelWithInstruction ::= Label Instruction
LocalLabel ::= LOCAL_LABEL_DEF COLON? {
name = "local label"
@ -199,7 +198,7 @@ MacroCall ::= MACRO_INVOCATION PlainOperands? {
}
AsmInstruction ::= AsmOp AsmOperands?
private Instruction ::= AsmInstruction | MacroCall
private Instruction ::= AsmInstruction | MacroCall | PreprocessorDirective
//external Instruction ::= parseMacroCallOrAsmInstruction
private AsmOperands ::= AddressingMode (SEPARATOR AddressingMode)?

View File

@ -0,0 +1,75 @@
package de.platon42.intellij.plugins.m68k.navigation
import com.intellij.ide.navigationToolbar.AbstractNavBarModelExtension
import com.intellij.ide.ui.UISettings
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.project.IndexNotReadyException
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.m68k.M68kIcons
import de.platon42.intellij.plugins.m68k.MC68000Language
import de.platon42.intellij.plugins.m68k.psi.*
import de.platon42.intellij.plugins.m68k.psi.utils.M68kPsiWalkUtil.findStatementForElement
import org.jetbrains.annotations.Nullable
import javax.swing.Icon
class M68kStructureAwareNavbar : AbstractNavBarModelExtension() {
override fun getLeafElement(dataContext: DataContext): PsiElement? {
if (UISettings.getInstance().showMembersInNavigationBar) {
val psiFile = CommonDataKeys.PSI_FILE.getData(dataContext)
val editor = CommonDataKeys.EDITOR.getData(dataContext)
if (psiFile == null || !psiFile.isValid || editor == null) return null
val psiElement = psiFile.findElementAt(editor.caretModel.offset)
if (isAcceptableLanguage(psiElement)) {
try {
var statement = findStatementForElement(psiElement!!) ?: return null
do {
if (statement.localLabel != null) return statement.localLabel
if (statement.globalLabel != null) return statement.globalLabel
statement = PsiTreeUtil.getPrevSiblingOfType(statement, M68kStatement::class.java) ?: return null
} while (true)
} catch (ignored: IndexNotReadyException) {
}
}
}
return null
}
private fun isAcceptableLanguage(psiElement: @Nullable PsiElement?) = psiElement?.language == MC68000Language.INSTANCE
override fun getPresentableText(obj: Any?): String? {
return when (obj) {
is M68kFile -> obj.name
is M68kGlobalLabel -> obj.name
is M68kLocalLabel -> obj.name
is M68kSymbolDefinition -> obj.name
is M68kMacroDefinition -> obj.macroNameDefinition.text
else -> null
}
}
override fun getParent(psiElement: PsiElement): PsiElement? {
if (!isAcceptableLanguage(psiElement)) return null
var statement = findStatementForElement(psiElement) ?: return null
if (statement.localLabel != null) {
do {
if (statement.globalLabel != null) return statement.globalLabel
statement = PsiTreeUtil.getPrevSiblingOfType(statement, M68kStatement::class.java) ?: return null
} while (true)
}
return psiElement.containingFile
}
override fun getIcon(obj: Any?): Icon? {
return when (obj) {
is M68kFile -> M68kIcons.FILE
is M68kGlobalLabel -> M68kIcons.GLOBAL_LABEL
is M68kLocalLabel -> M68kIcons.LOCAL_LABEL
is M68kSymbolDefinition -> M68kIcons.SYMBOL_DEF
is M68kMacroDefinition -> M68kIcons.MACRO_DEF
else -> null
}
}
}

View File

@ -2,10 +2,13 @@ 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
import de.platon42.intellij.plugins.m68k.psi.M68kFile
import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition
import de.platon42.intellij.plugins.m68k.psi.M68kStatement
object M68kPsiWalkUtil {
@ -28,4 +31,37 @@ 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) {
return PsiTreeUtil.getPrevSiblingOfType(psiElement, M68kStatement::class.java)
}
return PsiTreeUtil.getParentOfType(psiElement, M68kStatement::class.java);
}
}

View File

@ -32,7 +32,7 @@ class M68kLocalLabelDefCompletionContributor : CompletionContributor() {
}
referencedLocalLabels.removeAll(definedLocalLabels)
resultSet.addAllElements(
if (parameters.originalPosition?.text == ".") {
if (parameters.originalPosition?.text?.startsWith(".") == true) {
referencedLocalLabels.map { LookupElementBuilder.create(it.removePrefix(".")) }
} else {
referencedLocalLabels.map(LookupElementBuilder::create)

View File

@ -1,11 +1,13 @@
package de.platon42.intellij.plugins.m68k.syntax
import com.intellij.codeHighlighting.RainbowHighlighter
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.fileTypes.SyntaxHighlighter
import com.intellij.openapi.options.colors.AttributesDescriptor
import com.intellij.openapi.options.colors.ColorDescriptor
import com.intellij.openapi.options.colors.ColorSettingsPage
import com.intellij.openapi.options.colors.RainbowColorSettingsPage
import de.platon42.intellij.plugins.m68k.M68kIcons.FILE
import de.platon42.intellij.plugins.m68k.MC68000Language
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.AREG
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.BAD_CHARACTER
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.COLON
@ -34,7 +36,9 @@ import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.
import org.jetbrains.annotations.NonNls
import javax.swing.Icon
class M68kColorSettingsPage : ColorSettingsPage {
class M68kColorSettingsPage : RainbowColorSettingsPage {
override fun getLanguage() = MC68000Language.INSTANCE
override fun getIcon(): Icon {
return FILE
@ -49,6 +53,8 @@ class M68kColorSettingsPage : ColorSettingsPage {
return """; This is an example assembly language program
PIC_HEIGHT = 256
* Semantic highlighting is available for registers and local labels
include "../includes/hardware/custom.i"
BLTHOGON MACRO ; macro definition
@ -80,23 +86,21 @@ hello: dc.b 'Hello World!',10,0
"""
}
override fun getAdditionalHighlightingTagToDescriptorMap(): Map<String, TextAttributesKey>? {
return null
override fun getAdditionalHighlightingTagToDescriptorMap(): Map<String, TextAttributesKey> {
return RainbowHighlighter.createRainbowHLM()
}
override fun getAttributeDescriptors(): Array<AttributesDescriptor> {
return DESCRIPTORS
}
override fun isRainbowType(type: TextAttributesKey) = RAINBOW_TYPES.contains(type)
override fun getColorDescriptors(): Array<ColorDescriptor> {
return ColorDescriptor.EMPTY_ARRAY
}
override fun getAttributeDescriptors() = DESCRIPTORS
override fun getDisplayName(): String {
return "M68k Assembly"
}
override fun getColorDescriptors() = ColorDescriptor.EMPTY_ARRAY
override fun getDisplayName() = "M68k Assembly"
companion object {
private val RAINBOW_TYPES = setOf(AREG, DREG, LOCAL_LABEL)
private val DESCRIPTORS = arrayOf(
AttributesDescriptor("Global labels", GLOBAL_LABEL),
AttributesDescriptor("Local labels", LOCAL_LABEL),

View File

@ -0,0 +1,28 @@
package de.platon42.intellij.plugins.m68k.syntax
import com.intellij.codeInsight.daemon.RainbowVisitor
import com.intellij.codeInsight.daemon.impl.HighlightVisitor
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import de.platon42.intellij.plugins.m68k.psi.M68kAddressRegister
import de.platon42.intellij.plugins.m68k.psi.M68kDataRegister
import de.platon42.intellij.plugins.m68k.psi.M68kFile
import de.platon42.intellij.plugins.m68k.psi.M68kLocalLabel
class M68kRainbowVisitor : RainbowVisitor() {
override fun suitableForFile(file: PsiFile): Boolean = file is M68kFile
override fun visit(element: PsiElement) {
when (element) {
is M68kAddressRegister -> addInfo(getInfo(element.containingFile, element, element.text, M68kSyntaxHighlighter.AREG))
is M68kDataRegister -> addInfo(getInfo(element.containingFile, element, element.text, M68kSyntaxHighlighter.DREG))
// is M68kGlobalLabel -> addInfo(getInfo(element.containingFile, element, element.text, M68kSyntaxHighlighter.GLOBAL_LABEL))
is M68kLocalLabel -> addInfo(getInfo(element.containingFile, element, element.text, M68kSyntaxHighlighter.LOCAL_LABEL))
// is M68kMacroCall -> addInfo(getInfo(element.containingFile, element.firstChild, element.macroName, M68kSyntaxHighlighter.MACRO_CALL))
}
}
override fun clone(): HighlightVisitor = M68kRainbowVisitor()
}

View File

@ -1,14 +1,14 @@
<idea-plugin>
<id>de.platon42.m68k</id>
<name>MC68000 Assembly Language Support</name>
<vendor email="chrisly@platon42.de" url="https://github.com/chrisly42/mc68000-asm-plugin">Chris 'platon42' Hodges
<vendor email="chrisly@platon42.de" url="https://git.platon42.de/chrisly42/mc68000-asm-plugin">Chris 'platon42' Hodges
</vendor>
<description><![CDATA[
MC68000 Assembly Language Plugin adds language support for Motorola 68000 (M68k) assembly language files (asm).
It provides syntax highlighting and refactoring possibilities among other things.
<p>
<a href="https://github.com/chrisly42/mc68000-asm-plugin/blob/main/README.md">Full documentation here...</a>
<a href="https://git.platon42.de/chrisly42/mc68000-asm-plugin/blob/main/README.md">Full documentation here...</a>
]]></description>
<idea-version since-build="203.5981.166"/>
@ -21,8 +21,17 @@
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"/>
<!--lang.formatter language="MC68000"
implementationClass="de.platon42.intellij.plugins.m68k.formatter.M68kAsmFormattingModelBuilder"/-->
<codeStyleSettingsProvider implementation="de.platon42.intellij.plugins.m68k.formatter.M68kAsmCodeStyleSettingsProvider"/>
<langCodeStyleSettingsProvider implementation="de.platon42.intellij.plugins.m68k.formatter.M68kLanguageCodeStyleSettingsProvider"/>
<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"/>
<completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.asm.M68kMnemonicCompletionContributor"/>
<completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.asm.M68kDirectiveCompletionContributor"/>
<completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.refs.M68kGlobalLabelSymbolCompletionContributor"/>
<completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.refs.M68kLocalLabelDefCompletionContributor"/>
<completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.refs.M68kMacroCallCompletionContributor"/>
@ -78,4 +87,4 @@
<actions>
</actions>
</idea-plugin>
</idea-plugin>

View File

@ -0,0 +1,63 @@
package de.platon42.intellij.plugins.m68k.asm
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
import de.platon42.intellij.jupiter.LightCodeInsightExtension
import de.platon42.intellij.jupiter.MyFixture
import de.platon42.intellij.plugins.m68k.AbstractM68kTest
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 M68kDirectiveCompletionContributorTest : AbstractM68kTest() {
@Test
internal fun completion_shows_plain_directive(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.configureByText(
"completeme.asm", """
inc<caret>
"""
)
myFixture.completeBasic()
assertThat(myFixture.lookupElementStrings).containsExactlyInAnyOrder("include", "incbin", "incdir")
}
@Test
internal fun completion_shows_other_directive(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.configureByText(
"completeme.asm", """
IF<caret>
"""
)
myFixture.completeBasic()
assertThat(myFixture.lookupElementStrings).containsExactlyInAnyOrder(
"IF",
"IFB",
"IFC",
"IFD",
"IFEQ",
"IFGE",
"IFGT",
"IFLE",
"IFLT",
"IFMACROD",
"IFMACROND",
"IFNB",
"IFNC",
"IFND",
"IFNE",
"ENDIF"
)
}
@Test
internal fun completion_shows_data_directives(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.configureByText(
"completeme.asm", """
dc<caret>
"""
)
myFixture.completeBasic()
assertThat(myFixture.lookupElementStrings).containsExactlyInAnyOrder("dc", "dc.b", "dc.w", "dc.l", "dcb", "dcb.b", "dcb.w", "dcb.l", "data_c")
}
}

View File

@ -30,7 +30,7 @@ label: <caret>
"""
)
myFixture.completeBasic()
assertThat(myFixture.lookupElementStrings).hasSameElementsAs(M68kIsa.mnemonics)
assertThat(myFixture.lookupElementStrings).containsAnyElementsOf(M68kIsa.mnemonics)
}
@Test
@ -41,6 +41,6 @@ label: <caret>
"""
)
myFixture.completeBasic()
assertThat(myFixture.lookupElementStrings).hasSameElementsAs(M68kIsa.mnemonics)
assertThat(myFixture.lookupElementStrings).containsAnyElementsOf(M68kIsa.mnemonics)
}
}

View File

@ -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")
}
}

View File

@ -0,0 +1,52 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.application.options.CodeStyle
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
import com.intellij.util.containers.ContainerUtil
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.Disabled
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
@TestDataPath("src/test/resources/formatting")
@ExtendWith(LightCodeInsightExtension::class)
internal class M68kAsmFormatterTest {
@Test
@Disabled
internal fun check_if_formatting_works_as_expected(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.configureByFile("basic_before.asm")
val settings = CodeStyle.getLanguageSettings(myFixture.file)
settings.indentOptions?.INDENT_SIZE = 6
settings.indentOptions?.CONTINUATION_INDENT_SIZE = 9
WriteCommandAction.runWriteCommandAction(myFixture.project)
{
CodeStyleManager.getInstance(myFixture.project).reformatText(
myFixture.file,
ContainerUtil.newArrayList(myFixture.file.textRange)
)
}
myFixture.checkResultByFile("basic_after.asm")
}
@Test
internal fun check_formatting_for_mnemonics(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.configureByFile("mnemonics_before.asm")
val settings = CodeStyle.getLanguageSettings(myFixture.file)
settings.indentOptions?.INDENT_SIZE = 8
WriteCommandAction.runWriteCommandAction(myFixture.project)
{
CodeStyleManager.getInstance(myFixture.project).reformatText(
myFixture.file,
ContainerUtil.newArrayList(myFixture.file.textRange)
)
}
myFixture.checkResultByFile("mnemonics_after.asm")
}
}

View File

@ -27,6 +27,6 @@ noppy MACRO
"""
)
myFixture.completeBasic()
assertThat(myFixture.lookupElementStrings).containsExactlyInAnyOrder("nop", "not", "noppy")
assertThat(myFixture.lookupElementStrings).containsExactlyInAnyOrder("nop", "not", "noppy", "cnop")
}
}

View 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

View File

@ -0,0 +1,51 @@
; this is a test
FOO = 1
; this is the main demo routine
demo_main:
moveq.l #0,d0 ; end of line comment
rts ; some more comments
; data area starts here
.data dc.w 10,0
even
this_is_a_very_long_label: moveq.l #0,d0 ; and an end of line comment, too
; this is another folding area
; could be anything.
intro_part1
; What is this doing here?
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
MACRO BLTHOGOFF
moveq.l #0,d0
ENDM
********************** foobar
some_more_data:
dc.w $123
dc.w $345
dc.w $333
dc.w $222
CUBE_SIZE = 100

View File

@ -0,0 +1,51 @@
; this is a test
FOO = 1
; this is the main demo routine
demo_main:
moveq.l #0,d0 ; end of line comment
rts ; some more comments
; data area starts here
.data dc.w 10,0
even
this_is_a_very_long_label: moveq.l #0,d0 ; and an end of line comment, too
; this is another folding area
; could be anything.
intro_part1
; What is this doing here?
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
MACRO BLTHOGOFF
moveq.l #0,d0
ENDM
********************** foobar
some_more_data:
dc.w $123
dc.w $345
dc.w $333
dc.w $222
CUBE_SIZE = 100

View File

@ -0,0 +1,32 @@
FOO = 1234
BAR = 1235
COUNTER SET COUNTER+1
FISH MACRO
.fish\@ rts
ENDM
MACRO SOUP
moveq.l #0,d0
ENDM
; with space
; standalone comment
moveq.l #10,d1 ; end of line comment
FISH
add.l #10,d1
SOUP
subq.b #2,d2 ; end of line comment
bra.s .foo
nop
.foo move.l d2,d1
rts
.verylonglabel:
stop #$2000
.narf
moveq.l #2,d0
globallabel:
moveq.l #0,d0

View File

@ -0,0 +1,31 @@
FOO = 1234
BAR = 1235
COUNTER SET COUNTER+1
FISH MACRO
.fish\@ rts
ENDM
MACRO SOUP
moveq.l #0,d0
ENDM
; with space
; standalone comment
moveq.l #10,d1; end of line comment
FISH
add.l #10,d1
SOUP
subq.b #2,d2 ; end of line comment
bra.s .foo
nop
.foo move.l d2,d1
rts
.verylonglabel: stop #$2000
.narf
moveq.l #2,d0
globallabel: moveq.l #0,d0