Skip to content

Commit

Permalink
correct 'go to definition' for constant labels, overhaul code folding…
Browse files Browse the repository at this point in the history
…, add .mac extension
  • Loading branch information
mike42 committed Jan 30, 2022
1 parent e41679b commit e9ccd0c
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 49 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This IntelliJ plugin provides basic support for 6502 assembly language. It is su
- Find usages
- Refactor/rename a label and its usages
- Comment/uncomment blocks of code
- Code folding for scopes, procedures and macro definitions.
- Code folding for scopes, procedures and macro definitions

## Installation

Expand Down
7 changes: 6 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ runPluginVerifier {
}

patchPluginXml {
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."""
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.
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.
The 6502 Assembly file type now includes files with the ".mac" extension, which is used by ca65 macro definitions.
"""
sinceBuild = '211.6693'
}

Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/ca65/Asm.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ implements("identifierdef")="com.intellij.psi.PsiNamedElement"

asmFile ::= item_*

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

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

define ::= identifierdef ( EQUALS ) expr
assign ::= identifierr ( COLON_EQUALS ) expr
define_constant_numeric ::= identifierdef ( EQUALS ) expr
define_constant_label ::= identifierdef ( COLON_EQUALS ) expr

expr ::= anything*

Expand Down
80 changes: 42 additions & 38 deletions src/main/java/org/ca65/AsmFoldingBuilder.java
Original file line number Diff line number Diff line change
@@ -1,63 +1,44 @@
package org.ca65;

import com.intellij.lang.ASTNode;
import com.intellij.lang.folding.FoldingBuilder;
import com.intellij.lang.folding.FoldingBuilderEx;
import com.intellij.lang.folding.FoldingDescriptor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.FoldingGroup;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.ca65.psi.AsmDotexpr;
import org.ca65.psi.AsmMarker;
import org.ca65.psi.AsmTypes;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.*;

public class AsmFoldingBuilder extends FoldingBuilderEx implements DumbAware {
@Override
public FoldingDescriptor @NotNull [] buildFoldRegions(PsiElement root, @NotNull Document document, boolean quick) {
// Create folding regions for start/end of procs, scopes, macros
// Create folding regions for start/end of some assembler control commands
AsmDotexpr[] dotexprs = PsiTreeUtil.getChildrenOfType(root.getContainingFile(), AsmDotexpr.class);
List<FoldingDescriptor> descriptors = new ArrayList<>();
if(dotexprs != null) {
Deque<AsmDotexpr> procStartStack = new LinkedList<>();
Deque<AsmDotexpr> scopeStartStack = new LinkedList<>();
Deque<AsmDotexpr> macroStartStack = new LinkedList<>();
for (AsmDotexpr expr : dotexprs) {
String exprText = expr.getFirstChild().getText().toLowerCase();
if(exprText.equals(".proc")) {
procStartStack.add(expr);
} else if(exprText.equals(".macro")) {
macroStartStack.add(expr);
} else if(exprText.equals(".scope")) {
scopeStartStack.add(expr);
} else if(!procStartStack.isEmpty() && exprText.equals(".endproc")) {
AsmDotexpr procStart = procStartStack.removeLast();
descriptors.add(new FoldingDescriptor(procStart.getNode(),
new TextRange(procStart.getTextRange().getEndOffset(),
expr.getTextRange().getEndOffset())));
} else if(!scopeStartStack.isEmpty() && exprText.equals(".endscope")) {
AsmDotexpr scopeStart = scopeStartStack.removeLast();
descriptors.add(new FoldingDescriptor(scopeStart.getNode(),
new TextRange(scopeStart.getTextRange().getEndOffset(),
expr.getTextRange().getEndOffset())));
} else if(!macroStartStack.isEmpty() && exprText.equals(".endmacro")) {
AsmDotexpr macroStart = macroStartStack.removeLast();
descriptors.add(new FoldingDescriptor(macroStart.getNode(),
new TextRange(macroStart.getTextRange().getEndOffset(),
expr.getTextRange().getEndOffset())));
}
if (dotexprs == null) {
return new FoldingDescriptor[0];
}
List<FoldableStack> foldableBlockTypes = Arrays.asList(
new FoldableStack(Set.of(".enum"), Set.of(".endenum")),
new FoldableStack(Set.of(".if", ".ifblank", ".ifconst", ".ifdef", ".ifnblank", ".ifndef", ".ifnfref", ".ifp02", ".ifp816", ".ifpc02", ".ifpsc02", ".ifref"), Set.of(".endif")),
new FoldableStack(Set.of(".macro", ".mac"), Set.of(".endmacro", ".endmac")),
new FoldableStack(Set.of(".proc"), Set.of(".endproc")),
new FoldableStack(Set.of(".repeat"), Set.of(".endrep", ".endrepeat")),
new FoldableStack(Set.of(".scope"), Set.of(".endscope")),
new FoldableStack(Set.of(".struct"), Set.of(".endstruct")),
new FoldableStack(Set.of(".union"), Set.of(".endunion"))
);
for (AsmDotexpr expr : dotexprs) {
for(FoldableStack foldableStack : foldableBlockTypes) {
foldableStack.apply(expr, descriptors);
}
}
return descriptors.toArray(new FoldingDescriptor[descriptors.size()]);
return descriptors.toArray(new FoldingDescriptor[0]);
}

@Override
Expand All @@ -70,3 +51,26 @@ public boolean isCollapsedByDefault(@NotNull ASTNode node) {
return false;
}
}

class FoldableStack {
private final Set<String> start;
private final Set<String> end;
final private Deque<AsmDotexpr> startStack = new LinkedList<>();

public FoldableStack(Set<String> start, Set<String> end) {
this.start = start;
this.end = end;
}

public void apply(AsmDotexpr expr, List<FoldingDescriptor> descriptors) {
String exprText = expr.getFirstChild().getText().toLowerCase();
if(start.contains(exprText)) {
startStack.add(expr);
} else if (!startStack.isEmpty() && end.contains(exprText)) {
AsmDotexpr scopeStart = startStack.removeLast();
descriptors.add(new FoldingDescriptor(scopeStart.getNode(),
new TextRange(scopeStart.getTextRange().getEndOffset(),
expr.getTextRange().getEndOffset())));
}
}
}
20 changes: 15 additions & 5 deletions src/main/java/org/ca65/AsmUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,21 @@ public static PsiNamedElement findDefinition(AsmFile asmFile, String identifier)
}
}
}
// Imported values. For reasons unknown, getChildrenOfType(asmFile, AsmIdentifierdef.class) is always null, but this works.
AsmDefine[] defineStatements = PsiTreeUtil.getChildrenOfType(asmFile, AsmDefine.class);
if (defineStatements != null) {
for (AsmDefine defineStatement : defineStatements) {
AsmIdentifierdef identifierDef = defineStatement.getIdentifierdef();
// Numeric constants
AsmDefineConstantNumeric[] numericConstantList = PsiTreeUtil.getChildrenOfType(asmFile, AsmDefineConstantNumeric.class);
if (numericConstantList != null) {
for (AsmDefineConstantNumeric numericConstant : numericConstantList) {
AsmIdentifierdef identifierDef = numericConstant.getIdentifierdef();
if (identifier.equals(AsmPsiImplUtil.getLabelName(identifierDef))) {
return identifierDef;
}
}
}
// label constants
AsmDefineConstantLabel[] labelConstantList = PsiTreeUtil.getChildrenOfType(asmFile, AsmDefineConstantLabel.class);
if (labelConstantList != null) {
for (AsmDefineConstantLabel labelConstant : labelConstantList) {
AsmIdentifierdef identifierDef = labelConstant.getIdentifierdef();
if (identifier.equals(AsmPsiImplUtil.getLabelName(identifierDef))) {
return identifierDef;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

<extensions defaultExtensionNs="com.intellij">
<fileType name="Assembly file" implementationClass="org.ca65.AsmFileType" fieldName="INSTANCE"
language="6502 Assembly" extensions="s;asm;inc"/>
language="6502 Assembly" extensions="s;asm;inc;mac"/>
<lang.parserDefinition language="6502 Assembly"
implementationClass="org.ca65.AsmParserDefinition"/>
<lang.syntaxHighlighterFactory language="6502 Assembly"
Expand Down

0 comments on commit e9ccd0c

Please sign in to comment.