Skip to content

Commit 763e10f

Browse files
committed
Make the interactive labels work
1 parent 9772f80 commit 763e10f

File tree

4 files changed

+131
-34
lines changed

4 files changed

+131
-34
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
package the.bytecode.club.jda.gui.fileviewer;
22

3+
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
34
import org.fife.ui.rsyntaxtextarea.folding.CurlyFoldParser;
5+
import org.fife.ui.rsyntaxtextarea.folding.Fold;
6+
7+
import java.util.List;
48

59
public class BytecodeFoldParser extends CurlyFoldParser {
10+
/**
11+
* {@inheritDoc}
12+
*/
13+
@Override
14+
public List<Fold> getFolds(RSyntaxTextArea textArea) {
15+
return super.getFolds(textArea);
16+
}
617
}
Lines changed: 111 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,136 @@
11
package the.bytecode.club.jda.gui.fileviewer;
22

33
import org.fife.ui.rsyntaxtextarea.*;
4+
import org.fife.ui.rsyntaxtextarea.folding.Fold;
5+
import org.fife.ui.rsyntaxtextarea.folding.FoldManager;
46

57
import javax.swing.event.HyperlinkEvent;
68
import java.net.MalformedURLException;
79
import java.net.URL;
10+
import java.util.ArrayList;
11+
import java.util.HashMap;
12+
import java.util.List;
13+
import java.util.Map;
814

915
public class BytecodeSyntaxArea extends RSyntaxTextArea {
16+
public Map<Fold, List<Token>> tokenIndex;
17+
public boolean foldsBuilt;
18+
1019
public BytecodeSyntaxArea() {
1120
setSyntaxEditingStyle(BytecodeTokenizer.SYNTAX_STYLE_BYTECODE);
1221

1322
setLinkScanningMask(0);
1423
setLinkGenerator(new BytecodeLinkGenerator());
15-
addHyperlinkListener(e -> {
16-
URL url = e.getURL();
17-
String data = url.getFile();
18-
switch (url.getProtocol()) {
19-
case "label":
20-
System.out.println(data);
21-
setCaretPosition(0);
22-
break;
23-
}
24+
addHyperlinkListener(this::processClick);
25+
26+
foldsBuilt = false;
27+
getFoldManager().addPropertyChangeListener(evt -> {
28+
if (evt.getPropertyName().equals(FoldManager.PROPERTY_FOLDS_UPDATED)
29+
&& evt.getNewValue() != null)
30+
parseLabels();
2431
});
2532
}
2633

27-
private static class BytecodeLinkGenerator implements LinkGenerator {
34+
private void processClick(HyperlinkEvent e) {
35+
URL url = e.getURL();
36+
String data = url.getFile();
37+
switch (url.getProtocol()) {
38+
case "setcaret":
39+
setCaretPosition(Integer.parseInt(data));
40+
break;
41+
}
42+
}
43+
44+
private void parseLabels() {
45+
tokenIndex = new HashMap<>();
46+
FoldManager foldManager = getFoldManager();
47+
if (foldManager.getFoldCount() != 1) {
48+
System.err.println("Fold count isn't 1, rather " + foldManager.getFoldCount());
49+
return;
50+
}
51+
parseLabels(null, foldManager.getFold(0));
52+
foldsBuilt = true;
53+
}
54+
55+
private void parseLabels(Fold parent, Fold f) {
56+
for (Token t = getTokenListForLine(f.getStartLine()); t != null; t = t.getNextToken()) {
57+
if (t.getType() == BytecodeTokenizer.TOKENTYPE_LABEL) {
58+
List<Token> methodTokens = tokenIndex.computeIfAbsent(parent, k -> new ArrayList<>());
59+
methodTokens.add(new TokenImpl(t));
60+
if (methodTokens.size() != Integer.parseInt(t.getLexeme().substring(1)))
61+
throw new IllegalArgumentException("Invalid token numbering: " + methodTokens.size() + "vs" + Integer.parseInt(t.getLexeme().substring(1)));
62+
break;
63+
}
64+
}
65+
for (int i = 0; i < f.getChildCount(); i++) {
66+
parseLabels(f, f.getChild(i));
67+
}
68+
}
69+
70+
private Fold getMethodFold(Token t) {
71+
FoldManager foldManager = getFoldManager();
72+
Fold rootFold = foldManager.getFold(0);
73+
Fold curFold = foldManager.getDeepestFoldContaining(t.getOffset());
74+
while (curFold != null) {
75+
Fold parentFold = curFold.getParent();
76+
if (parentFold == rootFold)
77+
return curFold;
78+
curFold = parentFold;
79+
}
80+
throw new IllegalArgumentException("Token is not parented in top-level (class def) fold");
81+
}
82+
83+
private Token findLabelDefinition(Token label) {
84+
if (label.getType() != BytecodeTokenizer.TOKENTYPE_LABEL)
85+
throw new IllegalArgumentException("Token is not a label");
86+
Fold parentFold = getMethodFold(label);
87+
for (Token t : tokenIndex.get(parentFold)) {
88+
if (t.getLexeme().equals(label.getLexeme()))
89+
return t;
90+
}
91+
return null;
92+
}
93+
94+
private class BytecodeLinkGenerator implements LinkGenerator {
2895
@Override
2996
public LinkGeneratorResult isLinkAtOffset(RSyntaxTextArea textArea, int offs) {
3097
Token t = textArea.modelToToken(offs);
31-
if (t.getType() == TokenTypes.PREPROCESSOR) {
32-
return new LinkGeneratorResult() {
33-
@Override
34-
public HyperlinkEvent execute() {
35-
try {
36-
URL url = new URL(null, "label:" + t.getLexeme(), new JDAURLHandler());
37-
return new HyperlinkEvent(textArea, HyperlinkEvent.EventType.ACTIVATED, url);
38-
} catch (MalformedURLException e) {
39-
e.printStackTrace();
40-
return null;
41-
}
42-
}
43-
44-
@Override
45-
public int getSourceOffset() {
46-
return offs;
47-
}
48-
};
98+
if (foldsBuilt && t.getType() == BytecodeTokenizer.TOKENTYPE_LABEL) {
99+
Token labelDef = findLabelDefinition(t);
100+
if (labelDef == null)
101+
return null;
102+
int caretTarget = labelDef.getOffset();
103+
return new SetCaretLinkResult(caretTarget, textArea, offs);
49104
}
50105
return null;
51106
}
52107
}
108+
109+
private class SetCaretLinkResult implements LinkGeneratorResult {
110+
private final int caretTarget;
111+
private final RSyntaxTextArea textArea;
112+
private final int offs;
113+
114+
public SetCaretLinkResult(int caretTarget, RSyntaxTextArea textArea, int offs) {
115+
this.caretTarget = caretTarget;
116+
this.textArea = textArea;
117+
this.offs = offs;
118+
}
119+
120+
@Override
121+
public HyperlinkEvent execute() {
122+
try {
123+
URL url = new URL(null, "setcaret:" + caretTarget, new JDAURLHandler());
124+
return new HyperlinkEvent(textArea, HyperlinkEvent.EventType.ACTIVATED, url);
125+
} catch (MalformedURLException e) {
126+
e.printStackTrace();
127+
return null;
128+
}
129+
}
130+
131+
@Override
132+
public int getSourceOffset() {
133+
return offs;
134+
}
135+
}
53136
}

src/main/java/the/bytecode/club/jda/gui/fileviewer/BytecodeTokenizer.flex

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import org.fife.ui.rsyntaxtextarea.*;
5555

5656
%{
5757
public static final String SYNTAX_STYLE_BYTECODE = "text/bytecode";
58+
public static final int TOKENTYPE_LABEL = TokenTypes.PREPROCESSOR;
5859

5960
/**
6061
* Constructor. This must be here because JFlex does not generate a
@@ -231,7 +232,7 @@ AnyCharacterButDoubleQuoteOrBackSlash = ([^\\\"\n])
231232
EscapedSourceCharacter = ("u"{HexDigit}{HexDigit}{HexDigit}{HexDigit})
232233
Escape = ("\\"(([btnfr\"'\\])|([0123]{OctalDigit}?{OctalDigit}?)|({OctalDigit}{OctalDigit}?)|{EscapedSourceCharacter}))
233234
NonSeparator = ([^\t\f\r\n\ \(\)\{\}\[\]\;\,\.\=\>\<\!\~\?\:\+\-\*\/\&\|\^\%\"\']|"#"|"\\")
234-
Label = (L({Digit}+))
235+
Label = (L{Digit}+)
235236
IdentifierStart = ({LetterOrUnderscore}|"$")
236237
IdentifierPart = ({IdentifierStart}|{Digit}|("\\"{EscapedSourceCharacter}))
237238

@@ -529,8 +530,9 @@ URL = (((https?|f(tp|ile))"://"|"www.")({URLCharacters}{URLEndCharacter})?)
529530

530531
{LineTerminator} { addNullToken(); return firstToken; }
531532

533+
532534
/* Labels. */
533-
{Label} { addToken(Token.PREPROCESSOR); }
535+
{Label} { addToken(TOKENTYPE_LABEL); }
534536

535537
{Identifier} { addToken(Token.IDENTIFIER); }
536538

@@ -614,7 +616,7 @@ URL = (((https?|f(tp|ile))"://"|"www.")({URLCharacters}{URLEndCharacter})?)
614616

615617
<EOL_COMMENT> {
616618
[^Lhwf\n]+ {}
617-
{Label} { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.COMMENT_EOL); addToken(temp,zzMarkedPos-1, Token.PREPROCESSOR); start = zzMarkedPos; }
619+
{Label} { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.COMMENT_EOL); addToken(temp,zzMarkedPos-1, TOKENTYPE_LABEL); start = zzMarkedPos; }
618620
{URL} { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.COMMENT_EOL); addHyperlinkToken(temp,zzMarkedPos-1, Token.COMMENT_EOL); start = zzMarkedPos; }
619621
[Lhwf] {}
620622
\n { addToken(start,zzStartRead-1, Token.COMMENT_EOL); addNullToken(); return firstToken; }

src/main/java/the/bytecode/club/jda/gui/fileviewer/BytecodeTokenizer.java

Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)