Skip to content

Commit 9a84cfb

Browse files
committed
Allow ctrl+clicking on source elements and make method matching more stable
1 parent 5757105 commit 9a84cfb

File tree

13 files changed

+146
-141
lines changed

13 files changed

+146
-141
lines changed

src/main/java/com/github/minecraft_ta/totalDebugCompanion/jdt/JIndexBinaryType.java

+1-5
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,7 @@ public char[][] getInterfaceNames() {
6161

6262
@Override
6363
public char[] getSourceName() {
64-
var name = this.indexedClass.getName();
65-
//TODO: Return real source name
66-
var dollarIndex = name.lastIndexOf('$');
67-
68-
return name.substring(dollarIndex == -1 ? 0 : dollarIndex + 1).toCharArray();
64+
return this.indexedClass.getSourceName().toCharArray();
6965
}
7066

7167
@Override

src/main/java/com/github/minecraft_ta/totalDebugCompanion/jdt/diagnostics/CustomJavaLinkGenerator.java

+54-22
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,28 @@
22

33
import com.github.minecraft_ta.totalDebugCompanion.CompanionApp;
44
import com.github.minecraft_ta.totalDebugCompanion.messages.codeView.DecompileOrOpenMessage;
5+
import com.github.minecraft_ta.totalDebugCompanion.ui.components.global.BottomInformationBar;
6+
import com.github.minecraft_ta.totalDebugCompanion.util.UIUtils;
57
import org.eclipse.jdt.core.IJavaElement;
68
import org.eclipse.jdt.core.JavaModelException;
9+
import org.eclipse.jdt.core.SourceRange;
710
import org.eclipse.jdt.internal.core.*;
811
import org.fife.ui.rsyntaxtextarea.LinkGenerator;
912
import org.fife.ui.rsyntaxtextarea.LinkGeneratorResult;
1013
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
14+
import org.fife.ui.rtextarea.RTextScrollPane;
1115

1216
import javax.swing.event.HyperlinkEvent;
1317
import java.util.Arrays;
1418

1519
public class CustomJavaLinkGenerator implements LinkGenerator {
1620

1721
private final String identifier;
22+
private final BottomInformationBar informationBar;
1823

19-
public CustomJavaLinkGenerator(String identifier) {
24+
public CustomJavaLinkGenerator(String identifier, BottomInformationBar informationBar) {
2025
this.identifier = identifier;
26+
this.informationBar = informationBar;
2127
}
2228

2329
@Override
@@ -35,47 +41,73 @@ public LinkGeneratorResult isLinkAtOffset(RSyntaxTextArea textArea, int offs) {
3541
return null;
3642
}
3743

38-
return new LinkResult(elements[0], offs);
44+
return new LinkResult(textArea, elements[0], offs);
3945
} catch (JavaModelException e) {
4046
e.printStackTrace();
4147
return null;
4248
}
4349
}
4450

45-
private static class LinkResult implements LinkGeneratorResult {
51+
private class LinkResult implements LinkGeneratorResult {
4652

53+
private final RSyntaxTextArea textArea;
4754
private final IJavaElement el;
4855
private final int offs;
4956

50-
public LinkResult(IJavaElement el, int offs) {
57+
public LinkResult(RSyntaxTextArea textArea, IJavaElement el, int offs) {
58+
this.textArea = textArea;
5159
this.el = el;
5260
this.offs = offs;
5361
}
5462

5563
@Override
5664
public HyperlinkEvent execute() {
57-
//TODO: Handle these differently
58-
if (el instanceof SourceMethod || el instanceof SourceField || el instanceof SourceType)
65+
if (!CompanionApp.SERVER.isClientConnected()) {
66+
informationBar.setFailureInfoText("Not connected to game client!");
5967
return null;
68+
}
6069

61-
String className;
62-
int targetMemberType = -1;
63-
String targetMemberIdentifier = "";
64-
if (el instanceof ResolvedBinaryMethod method) {
65-
className = method.getDeclaringType().getFullyQualifiedName();
66-
targetMemberType = method.getElementType();
67-
targetMemberIdentifier = method.getKey();
68-
} else if (el instanceof ResolvedBinaryField field) {
69-
className = field.getDeclaringType().getFullyQualifiedName();
70-
targetMemberType = field.getElementType();
71-
targetMemberIdentifier = field.getElementName();
72-
} else if (el instanceof ResolvedBinaryType type) {
73-
className = type.getFullyQualifiedName();
74-
} else {
75-
return null;
70+
try {
71+
if (el instanceof LocalVariable || el instanceof SourceMethod || el instanceof SourceField || el instanceof SourceType) {
72+
var sourceRange = switch (el) {
73+
case LocalVariable lv ->
74+
SourceRange.isAvailable(lv.getNameRange()) ? lv.getNameRange() : lv.getSourceRange();
75+
case SourceRefElement sr ->
76+
SourceRange.isAvailable(sr.getNameRange()) ? sr.getNameRange() : sr.getSourceRange();
77+
default -> throw new IllegalStateException();
78+
};
79+
80+
if (!SourceRange.isAvailable(sourceRange)) {
81+
System.err.println("SourceRange is not available for " + el);
82+
return null;
83+
}
84+
85+
UIUtils.centerViewportOnRange(((RTextScrollPane) textArea.getParent().getParent()), sourceRange.getOffset(), sourceRange.getOffset());
86+
return null;
87+
}
88+
89+
String className;
90+
int targetMemberType = -1;
91+
String targetMemberIdentifier = "";
92+
if (el instanceof ResolvedBinaryMethod method) {
93+
className = method.getDeclaringType().getFullyQualifiedName();
94+
targetMemberType = method.getElementType();
95+
targetMemberIdentifier = method.getKey();
96+
} else if (el instanceof ResolvedBinaryField field) {
97+
className = field.getDeclaringType().getFullyQualifiedName();
98+
targetMemberType = field.getElementType();
99+
targetMemberIdentifier = field.getElementName();
100+
} else if (el instanceof ResolvedBinaryType type) {
101+
className = type.getFullyQualifiedName();
102+
} else {
103+
return null;
104+
}
105+
106+
CompanionApp.SERVER.getMessageProcessor().enqueueMessage(new DecompileOrOpenMessage(className, targetMemberType, targetMemberIdentifier));
107+
} catch (JavaModelException e) {
108+
e.printStackTrace();
76109
}
77110

78-
CompanionApp.SERVER.getMessageProcessor().enqueueMessage(new DecompileOrOpenMessage(className, targetMemberType, targetMemberIdentifier));
79111
return null;
80112
}
81113

src/main/java/com/github/minecraft_ta/totalDebugCompanion/jdt/impls/CompilationUnitImpl.java

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ public class CompilationUnitImpl extends CompilationUnit {
1919
private final IBuffer buffer;
2020

2121
public CompilationUnitImpl(String name, String contents) {
22-
//TODO: is the name relevant?
2322
super(JDTHacks.createPackageFragment(extractPackageName(contents)), name, DefaultWorkingCopyOwner.PRIMARY);
2423
this.buffer = new BufferImpl(contents);
2524
//Force some model updates

src/main/java/com/github/minecraft_ta/totalDebugCompanion/messages/codeView/DecompileOrOpenMessage.java

+27-21
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
import java.util.List;
1818
import java.util.Optional;
1919
import java.util.OptionalInt;
20+
import java.util.regex.Pattern;
2021

2122
public class DecompileOrOpenMessage extends AbstractMessage {
2223

2324
private static final String CU_NAME = "Name";
25+
private static final Pattern TYPE_PATTERN = Pattern.compile("(T\\w+;)|(L[\\w/$]+;)");
2426

2527
private String name;
2628
private int targetType;
@@ -58,7 +60,7 @@ public static void handle(DecompileOrOpenMessage message) {
5860
if (!Files.exists(filePath) || !FileUtils.isSubPathOf(CompanionApp.getRootPath(), filePath))
5961
return;
6062

61-
int line = 0;
63+
int offset = 0;
6264
if (message.targetType != -1) {
6365
var ast = ASTCache.rawParse(CU_NAME, CodeView.readCode(filePath));
6466
var firstType = ast.types().get(0);
@@ -76,7 +78,7 @@ public static void handle(DecompileOrOpenMessage message) {
7678
return;
7779
}
7880

79-
line = ast.getLineNumber(targetMethod.get().getStartPosition());
81+
offset = targetMethod.get().getStartPosition();
8082
} else if (message.targetType == IJavaElement.FIELD) {
8183
var targetField = findTargetField(message, type);
8284

@@ -85,26 +87,21 @@ public static void handle(DecompileOrOpenMessage message) {
8587
return;
8688
}
8789

88-
line = ast.getLineNumber(targetField.getAsInt());
90+
offset = targetField.getAsInt();
8991
} else {
9092
System.err.println("Unknown target type");
9193
return;
9294
}
9395
}
9496

9597
var window = MainWindow.INSTANCE;
96-
var editorTabs = window.getEditorTabs();
97-
int finalLine = line;
98-
editorTabs.getEditors().stream()
99-
.filter(e -> e instanceof CodeView)
100-
.map(e -> (CodeView) e)
101-
.filter(e -> e.getPath().equals(filePath))
102-
.findFirst()
103-
.ifPresentOrElse(c -> {
104-
editorTabs.setSelectedIndex(editorTabs.getEditors().indexOf(c));
105-
}, () -> {
106-
editorTabs.openEditorTab(new CodeView(filePath, finalLine)).join();
107-
});
98+
var finalOffset = offset;
99+
var codeView = window.getEditorTabs().focusOrCreateIfAbsent(
100+
CodeView.class,
101+
(cv) -> cv.getPath().equals(filePath),
102+
() -> new CodeView(filePath, finalOffset)
103+
).join();
104+
codeView.centerViewportOnOffset(offset);
108105

109106
UIUtils.focusWindow(window);
110107
}
@@ -150,7 +147,7 @@ private static String fixMethodIdentifier(String key) {
150147
var builder = new StringBuilder(key);
151148

152149
// Remove exception data
153-
var exceptionIndex = builder.lastIndexOf("|");
150+
var exceptionIndex = builder.indexOf("|");
154151
if (exceptionIndex != -1)
155152
builder.delete(exceptionIndex, builder.length());
156153

@@ -167,14 +164,23 @@ private static String fixMethodIdentifier(String key) {
167164
// Remove any type parameters
168165
var genericIndex = -1;
169166
while ((genericIndex = builder.indexOf("<")) != -1) {
170-
var endIndex = builder.indexOf(">", genericIndex);
171-
if (endIndex == -1)
167+
var endIndex = genericIndex + 1;
168+
var count = 1;
169+
//Find closing '>'
170+
for (; count != 0 && endIndex < builder.length(); endIndex++) {
171+
var c = builder.charAt(endIndex);
172+
if (c == '<')
173+
count++;
174+
else if (c == '>')
175+
count--;
176+
}
177+
if (count != 0 || endIndex == -1)
172178
break;
173179

174-
builder.delete(genericIndex, endIndex + 1);
180+
builder.delete(genericIndex, endIndex);
175181
}
176182

177-
// Replace unwanted CU_NAME from JDT and any generic type with a placeholder
178-
return builder.toString().replace(CU_NAME + "~", "").replaceAll("T\\w+;", "Ljava/lang/Object;");
183+
// Replace unwanted CU_NAME from JDT and reduce any type or generic type to just java.lang.Object
184+
return TYPE_PATTERN.matcher(builder.toString().replace(CU_NAME + "~", "")).replaceAll("Ljava/lang/Object;");
179185
}
180186
}

src/main/java/com/github/minecraft_ta/totalDebugCompanion/messages/search/OpenSearchResultsMessage.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public static void handle(OpenSearchResultsMessage message) {
3333
var editorTabs = window.getEditorTabs();
3434
editorTabs.openEditorTab(new SearchResultView(
3535
message.query, message.results, message.methodSearch, message.classesCount, message.time
36-
)).join();
36+
));
3737

3838
UIUtils.focusWindow(window);
3939
}

src/main/java/com/github/minecraft_ta/totalDebugCompanion/model/CodeView.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class CodeView implements IEditorPanel {
1717
private final Path path;
1818
private final CodeViewPanel codeViewPanel;
1919

20-
public CodeView(Path path, int line) {
20+
public CodeView(Path path, int offset) {
2121
this.path = path;
2222
this.codeViewPanel = new CodeViewPanel(this);
2323

@@ -27,7 +27,7 @@ public CodeView(Path path, int line) {
2727

2828
SwingUtilities.invokeLater(() -> {
2929
codeViewPanel.setCode(code);
30-
codeViewPanel.focusLine(line);
30+
codeViewPanel.centerViewportOnOffset(offset);
3131
});
3232
} catch (Exception e) {
3333
throw new CompletionException(e);
@@ -39,13 +39,13 @@ public CodeView(Path path, int line) {
3939
}
4040

4141
/**
42-
* @param line the line to scroll to, starting at index 1
42+
* @param offset the offset to scroll to
4343
*/
44-
public void focusLine(int line) {
45-
if (line < 1)
44+
public void centerViewportOnOffset(int offset) {
45+
if (offset < 0)
4646
throw new IllegalArgumentException();
4747

48-
this.codeViewPanel.focusLine(line);
48+
this.codeViewPanel.centerViewportOnOffset(offset);
4949
}
5050

5151
@Override

src/main/java/com/github/minecraft_ta/totalDebugCompanion/model/ScriptView.java

-4
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,6 @@ public String getSourceText() {
5151
return text;
5252
}
5353

54-
public String getURI() {
55-
return this.path.toUri().toString();
56-
}
57-
5854
public Path getPath() {
5955
return path;
6056
}

src/main/java/com/github/minecraft_ta/totalDebugCompanion/ui/components/editors/AbstractCodeViewPanel.java

+13-28
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
import com.github.minecraft_ta.totalDebugCompanion.util.DocumentChangeListener;
1010
import com.github.minecraft_ta.totalDebugCompanion.util.UIUtils;
1111
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
12+
import org.fife.ui.rsyntaxtextarea.Token;
1213
import org.fife.ui.rtextarea.Gutter;
1314
import org.fife.ui.rtextarea.RTextScrollPane;
1415

1516
import javax.swing.*;
1617
import javax.swing.event.DocumentEvent;
17-
import javax.swing.text.BadLocationException;
1818
import java.awt.*;
1919
import java.awt.event.HierarchyEvent;
2020
import java.beans.PropertyChangeListener;
@@ -33,7 +33,12 @@ public class AbstractCodeViewPanel extends JPanel {
3333
}
3434
}
3535

36-
protected final RSyntaxTextArea editorPane = new RSyntaxTextArea();
36+
protected final RSyntaxTextArea editorPane = new RSyntaxTextArea() {
37+
@Override
38+
public boolean getUnderlineForToken(Token t) {
39+
return false;
40+
}
41+
};
3742
protected final RTextScrollPane editorScrollPane = new RTextScrollPane(editorPane);
3843

3944
protected final BottomInformationBar bottomInformationBar = new BottomInformationBar();
@@ -56,14 +61,17 @@ public AbstractCodeViewPanel(String identifier, String className) {
5661
this.editorPane.setBackground(UIManager.getColor("TextPane.background"));
5762
this.editorPane.setForeground(UIManager.getColor("EditorPane.foreground"));
5863
this.editorPane.setSelectionColor(UIManager.getColor("EditorPane.selectionBackground"));
59-
this.editorPane.setLinkGenerator(new CustomJavaLinkGenerator(identifier));
64+
this.editorPane.setHyperlinkForeground(Color.decode("#7cc0f7"));
65+
this.editorPane.setLinkGenerator(new CustomJavaLinkGenerator(identifier, this.bottomInformationBar));
6066
this.editorPane.addHyperlinkListener(e -> {}); //Empty listener to circumvent RSyntaxTextArea bug
6167
this.editorPane.getDocument().addDocumentListener((DocumentChangeListener) e -> {
6268
if (e.getType() == DocumentEvent.EventType.CHANGE)
6369
return;
6470

6571
ASTCache.update(identifier, className,UIUtils.getText(this.editorPane));
6672
});
73+
this.editorPane.addCaretListener(e -> this.editorPane.getCaret().setVisible(true));
74+
6775
this.editorPane.setSyntaxEditingStyle(RSyntaxTextArea.SYNTAX_STYLE_JAVA);
6876
CodeUtils.initJavaColors(this.editorPane.getSyntaxScheme());
6977
try {
@@ -90,31 +98,8 @@ public AbstractCodeViewPanel(String identifier, String className) {
9098
});
9199
}
92100

93-
public void focusLine(int line) {
94-
SwingUtilities.invokeLater(() -> {
95-
var verticalScrollBar = this.editorScrollPane.getVerticalScrollBar();
96-
verticalScrollBar.setValue((int) ((line - 1) * ((double) verticalScrollBar.getMaximum() / this.editorPane.getDocument().getDefaultRootElement().getElementCount())));
97-
});
98-
}
99-
100-
public void focusRange(int offsetStart, int offsetEnd) {
101-
try {
102-
var rect = this.editorPane.modelToView2D(offsetStart);
103-
var viewport = this.editorScrollPane.getViewport();
104-
105-
var viewSize = viewport.getViewSize();
106-
var extentSize = viewport.getExtentSize();
107-
108-
int rangeWidth = UIUtils.getFontWidth(this.editorPane, "9".repeat(offsetEnd - offsetStart));
109-
int x = (int) Math.max(0, rect.getX() - ((extentSize.width - rangeWidth) / 2f));
110-
x = Math.min(x, viewSize.width - extentSize.width);
111-
int y = (int) Math.max(0, rect.getY() - ((extentSize.height - rect.getHeight()) / 2f));
112-
y = Math.min(y, viewSize.height - extentSize.height);
113-
114-
viewport.setViewPosition(new Point(x, y));
115-
} catch (BadLocationException e) {
116-
e.printStackTrace();
117-
}
101+
public void centerViewportOnOffset(int offset) {
102+
SwingUtilities.invokeLater(() -> UIUtils.centerViewportOnRange(this.editorScrollPane, offset, offset));
118103
}
119104

120105
public void setHeaderComponent(JComponent component) {

0 commit comments

Comments
 (0)