Skip to content

Commit e9ccd0c

Browse files
committed
correct 'go to definition' for constant labels, overhaul code folding, add .mac extension
1 parent e41679b commit e9ccd0c

File tree

6 files changed

+68
-49
lines changed

6 files changed

+68
-49
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This IntelliJ plugin provides basic support for 6502 assembly language. It is su
1111
- Find usages
1212
- Refactor/rename a label and its usages
1313
- Comment/uncomment blocks of code
14-
- Code folding for scopes, procedures and macro definitions.
14+
- Code folding for scopes, procedures and macro definitions
1515

1616
## Installation
1717

build.gradle

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,12 @@ runPluginVerifier {
3838
}
3939

4040
patchPluginXml {
41-
changeNotes = """This change adds 'Go to definition' and 'Find usages' support for constants and imports. It also adds support for code folding of macro definitions, corrects a bug where code folding incorrectly treated the .proc and .scope keywords as case sensitive."""
41+
changeNotes = """This change adds 'Go to definition' and 'Find usages' support for constants and imports, and allows for labels to be auto-completed when entering text after an assembly mnemonic.
42+
43+
Code folding has also been overhauled, and now supports macro definitions, conditional blocks, and a number of other constructs. A code folding bug has also been corrected, where keywords such as .proc and .scope were incorrectly interpreted as case sensitive.
44+
45+
The 6502 Assembly file type now includes files with the ".mac" extension, which is used by ca65 macro definitions.
46+
"""
4247
sinceBuild = '211.6693'
4348
}
4449

src/main/java/org/ca65/Asm.bnf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ implements("identifierdef")="com.intellij.psi.PsiNamedElement"
1818

1919
asmFile ::= item_*
2020

21-
private item_ ::= marker? (dotexpr|imports|assign|define|macro|llabel)? COMMENT? EOL_WS
21+
private item_ ::= marker? (dotexpr|imports|define_constant_label|define_constant_numeric|macro|llabel)? COMMENT? EOL_WS
2222

2323
marker ::= (LABEL | SHORTLABEL) {
2424
mixin="org.ca65.psi.impl.AsmLabelDefinitionImpl"
@@ -34,8 +34,8 @@ dotexpr ::= DOT_KEYWORD expr
3434
macro ::= IDENTIFIER expr
3535
llabel ::= MNEMONIC expr?
3636

37-
define ::= identifierdef ( EQUALS ) expr
38-
assign ::= identifierr ( COLON_EQUALS ) expr
37+
define_constant_numeric ::= identifierdef ( EQUALS ) expr
38+
define_constant_label ::= identifierdef ( COLON_EQUALS ) expr
3939

4040
expr ::= anything*
4141

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,44 @@
11
package org.ca65;
22

33
import com.intellij.lang.ASTNode;
4-
import com.intellij.lang.folding.FoldingBuilder;
54
import com.intellij.lang.folding.FoldingBuilderEx;
65
import com.intellij.lang.folding.FoldingDescriptor;
76
import com.intellij.openapi.editor.Document;
8-
import com.intellij.openapi.editor.FoldingGroup;
97
import com.intellij.openapi.project.DumbAware;
108
import com.intellij.openapi.util.TextRange;
119
import com.intellij.psi.PsiElement;
1210
import com.intellij.psi.util.PsiTreeUtil;
1311
import org.ca65.psi.AsmDotexpr;
14-
import org.ca65.psi.AsmMarker;
15-
import org.ca65.psi.AsmTypes;
1612
import org.jetbrains.annotations.NotNull;
1713
import org.jetbrains.annotations.Nullable;
1814

19-
import java.util.ArrayList;
20-
import java.util.Deque;
21-
import java.util.LinkedList;
22-
import java.util.List;
15+
import java.util.*;
2316

2417
public class AsmFoldingBuilder extends FoldingBuilderEx implements DumbAware {
2518
@Override
2619
public FoldingDescriptor @NotNull [] buildFoldRegions(PsiElement root, @NotNull Document document, boolean quick) {
27-
// Create folding regions for start/end of procs, scopes, macros
20+
// Create folding regions for start/end of some assembler control commands
2821
AsmDotexpr[] dotexprs = PsiTreeUtil.getChildrenOfType(root.getContainingFile(), AsmDotexpr.class);
2922
List<FoldingDescriptor> descriptors = new ArrayList<>();
30-
if(dotexprs != null) {
31-
Deque<AsmDotexpr> procStartStack = new LinkedList<>();
32-
Deque<AsmDotexpr> scopeStartStack = new LinkedList<>();
33-
Deque<AsmDotexpr> macroStartStack = new LinkedList<>();
34-
for (AsmDotexpr expr : dotexprs) {
35-
String exprText = expr.getFirstChild().getText().toLowerCase();
36-
if(exprText.equals(".proc")) {
37-
procStartStack.add(expr);
38-
} else if(exprText.equals(".macro")) {
39-
macroStartStack.add(expr);
40-
} else if(exprText.equals(".scope")) {
41-
scopeStartStack.add(expr);
42-
} else if(!procStartStack.isEmpty() && exprText.equals(".endproc")) {
43-
AsmDotexpr procStart = procStartStack.removeLast();
44-
descriptors.add(new FoldingDescriptor(procStart.getNode(),
45-
new TextRange(procStart.getTextRange().getEndOffset(),
46-
expr.getTextRange().getEndOffset())));
47-
} else if(!scopeStartStack.isEmpty() && exprText.equals(".endscope")) {
48-
AsmDotexpr scopeStart = scopeStartStack.removeLast();
49-
descriptors.add(new FoldingDescriptor(scopeStart.getNode(),
50-
new TextRange(scopeStart.getTextRange().getEndOffset(),
51-
expr.getTextRange().getEndOffset())));
52-
} else if(!macroStartStack.isEmpty() && exprText.equals(".endmacro")) {
53-
AsmDotexpr macroStart = macroStartStack.removeLast();
54-
descriptors.add(new FoldingDescriptor(macroStart.getNode(),
55-
new TextRange(macroStart.getTextRange().getEndOffset(),
56-
expr.getTextRange().getEndOffset())));
57-
}
23+
if (dotexprs == null) {
24+
return new FoldingDescriptor[0];
25+
}
26+
List<FoldableStack> foldableBlockTypes = Arrays.asList(
27+
new FoldableStack(Set.of(".enum"), Set.of(".endenum")),
28+
new FoldableStack(Set.of(".if", ".ifblank", ".ifconst", ".ifdef", ".ifnblank", ".ifndef", ".ifnfref", ".ifp02", ".ifp816", ".ifpc02", ".ifpsc02", ".ifref"), Set.of(".endif")),
29+
new FoldableStack(Set.of(".macro", ".mac"), Set.of(".endmacro", ".endmac")),
30+
new FoldableStack(Set.of(".proc"), Set.of(".endproc")),
31+
new FoldableStack(Set.of(".repeat"), Set.of(".endrep", ".endrepeat")),
32+
new FoldableStack(Set.of(".scope"), Set.of(".endscope")),
33+
new FoldableStack(Set.of(".struct"), Set.of(".endstruct")),
34+
new FoldableStack(Set.of(".union"), Set.of(".endunion"))
35+
);
36+
for (AsmDotexpr expr : dotexprs) {
37+
for(FoldableStack foldableStack : foldableBlockTypes) {
38+
foldableStack.apply(expr, descriptors);
5839
}
5940
}
60-
return descriptors.toArray(new FoldingDescriptor[descriptors.size()]);
41+
return descriptors.toArray(new FoldingDescriptor[0]);
6142
}
6243

6344
@Override
@@ -70,3 +51,26 @@ public boolean isCollapsedByDefault(@NotNull ASTNode node) {
7051
return false;
7152
}
7253
}
54+
55+
class FoldableStack {
56+
private final Set<String> start;
57+
private final Set<String> end;
58+
final private Deque<AsmDotexpr> startStack = new LinkedList<>();
59+
60+
public FoldableStack(Set<String> start, Set<String> end) {
61+
this.start = start;
62+
this.end = end;
63+
}
64+
65+
public void apply(AsmDotexpr expr, List<FoldingDescriptor> descriptors) {
66+
String exprText = expr.getFirstChild().getText().toLowerCase();
67+
if(start.contains(exprText)) {
68+
startStack.add(expr);
69+
} else if (!startStack.isEmpty() && end.contains(exprText)) {
70+
AsmDotexpr scopeStart = startStack.removeLast();
71+
descriptors.add(new FoldingDescriptor(scopeStart.getNode(),
72+
new TextRange(scopeStart.getTextRange().getEndOffset(),
73+
expr.getTextRange().getEndOffset())));
74+
}
75+
}
76+
}

src/main/java/org/ca65/AsmUtil.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,21 @@ public static PsiNamedElement findDefinition(AsmFile asmFile, String identifier)
4040
}
4141
}
4242
}
43-
// Imported values. For reasons unknown, getChildrenOfType(asmFile, AsmIdentifierdef.class) is always null, but this works.
44-
AsmDefine[] defineStatements = PsiTreeUtil.getChildrenOfType(asmFile, AsmDefine.class);
45-
if (defineStatements != null) {
46-
for (AsmDefine defineStatement : defineStatements) {
47-
AsmIdentifierdef identifierDef = defineStatement.getIdentifierdef();
43+
// Numeric constants
44+
AsmDefineConstantNumeric[] numericConstantList = PsiTreeUtil.getChildrenOfType(asmFile, AsmDefineConstantNumeric.class);
45+
if (numericConstantList != null) {
46+
for (AsmDefineConstantNumeric numericConstant : numericConstantList) {
47+
AsmIdentifierdef identifierDef = numericConstant.getIdentifierdef();
48+
if (identifier.equals(AsmPsiImplUtil.getLabelName(identifierDef))) {
49+
return identifierDef;
50+
}
51+
}
52+
}
53+
// label constants
54+
AsmDefineConstantLabel[] labelConstantList = PsiTreeUtil.getChildrenOfType(asmFile, AsmDefineConstantLabel.class);
55+
if (labelConstantList != null) {
56+
for (AsmDefineConstantLabel labelConstant : labelConstantList) {
57+
AsmIdentifierdef identifierDef = labelConstant.getIdentifierdef();
4858
if (identifier.equals(AsmPsiImplUtil.getLabelName(identifierDef))) {
4959
return identifierDef;
5060
}

src/main/resources/META-INF/plugin.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
<extensions defaultExtensionNs="com.intellij">
2626
<fileType name="Assembly file" implementationClass="org.ca65.AsmFileType" fieldName="INSTANCE"
27-
language="6502 Assembly" extensions="s;asm;inc"/>
27+
language="6502 Assembly" extensions="s;asm;inc;mac"/>
2828
<lang.parserDefinition language="6502 Assembly"
2929
implementationClass="org.ca65.AsmParserDefinition"/>
3030
<lang.syntaxHighlighterFactory language="6502 Assembly"

0 commit comments

Comments
 (0)