diff options
33 files changed, 604 insertions, 11 deletions
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java index 12877fe..3a0597e 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java | |||
| @@ -350,6 +350,12 @@ public class Gui { | |||
| 350 | return activeEditor == null ? null : activeEditor.getCursorReference(); | 350 | return activeEditor == null ? null : activeEditor.getCursorReference(); |
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | @Nullable | ||
| 354 | public Entry<?> getCursorDeclaration() { | ||
| 355 | EditorPanel activeEditor = this.editorTabbedPane.getActiveEditor(); | ||
| 356 | return activeEditor == null ? null : activeEditor.getCursorDeclaration(); | ||
| 357 | } | ||
| 358 | |||
| 353 | public void startDocChange(EditorPanel editor) { | 359 | public void startDocChange(EditorPanel editor) { |
| 354 | EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); | 360 | EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); |
| 355 | 361 | ||
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java index a2b3bd9..2c27376 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java | |||
| @@ -27,6 +27,7 @@ import java.util.concurrent.ExecutionException; | |||
| 27 | import java.util.stream.Collectors; | 27 | import java.util.stream.Collectors; |
| 28 | import java.util.stream.Stream; | 28 | import java.util.stream.Stream; |
| 29 | 29 | ||
| 30 | import javax.swing.JEditorPane; | ||
| 30 | import javax.swing.JFrame; | 31 | import javax.swing.JFrame; |
| 31 | import javax.swing.JOptionPane; | 32 | import javax.swing.JOptionPane; |
| 32 | import javax.swing.SwingUtilities; | 33 | import javax.swing.SwingUtilities; |
| @@ -52,12 +53,15 @@ import cuchaz.enigma.api.service.ObfuscationTestService; | |||
| 52 | import cuchaz.enigma.api.service.ProjectService; | 53 | import cuchaz.enigma.api.service.ProjectService; |
| 53 | import cuchaz.enigma.api.view.GuiView; | 54 | import cuchaz.enigma.api.view.GuiView; |
| 54 | import cuchaz.enigma.api.view.entry.EntryReferenceView; | 55 | import cuchaz.enigma.api.view.entry.EntryReferenceView; |
| 56 | import cuchaz.enigma.api.view.entry.EntryView; | ||
| 55 | import cuchaz.enigma.classhandle.ClassHandle; | 57 | import cuchaz.enigma.classhandle.ClassHandle; |
| 56 | import cuchaz.enigma.classhandle.ClassHandleProvider; | 58 | import cuchaz.enigma.classhandle.ClassHandleProvider; |
| 59 | import cuchaz.enigma.gui.config.LookAndFeel; | ||
| 57 | import cuchaz.enigma.gui.config.NetConfig; | 60 | import cuchaz.enigma.gui.config.NetConfig; |
| 58 | import cuchaz.enigma.gui.config.UiConfig; | 61 | import cuchaz.enigma.gui.config.UiConfig; |
| 59 | import cuchaz.enigma.gui.dialog.ProgressDialog; | 62 | import cuchaz.enigma.gui.dialog.ProgressDialog; |
| 60 | import cuchaz.enigma.gui.newabstraction.EntryValidation; | 63 | import cuchaz.enigma.gui.newabstraction.EntryValidation; |
| 64 | import cuchaz.enigma.gui.panels.EditorPanel; | ||
| 61 | import cuchaz.enigma.gui.stats.StatsGenerator; | 65 | import cuchaz.enigma.gui.stats.StatsGenerator; |
| 62 | import cuchaz.enigma.gui.stats.StatsMember; | 66 | import cuchaz.enigma.gui.stats.StatsMember; |
| 63 | import cuchaz.enigma.gui.util.History; | 67 | import cuchaz.enigma.gui.util.History; |
| @@ -130,6 +134,23 @@ public class GuiController implements ClientPacketHandler, GuiView, DataInvalida | |||
| 130 | return gui.getFrame(); | 134 | return gui.getFrame(); |
| 131 | } | 135 | } |
| 132 | 136 | ||
| 137 | @Override | ||
| 138 | public float getScale() { | ||
| 139 | return UiConfig.getActiveScaleFactor(); | ||
| 140 | } | ||
| 141 | |||
| 142 | @Override | ||
| 143 | public boolean isDarkTheme() { | ||
| 144 | return LookAndFeel.isDarkLaf(); | ||
| 145 | } | ||
| 146 | |||
| 147 | @Override | ||
| 148 | public JEditorPane createEditorPane() { | ||
| 149 | JEditorPane editor = new JEditorPane(); | ||
| 150 | EditorPanel.customizeEditor(editor); | ||
| 151 | return editor; | ||
| 152 | } | ||
| 153 | |||
| 133 | public boolean isDirty() { | 154 | public boolean isDirty() { |
| 134 | return project != null && project.getMapper().isDirty(); | 155 | return project != null && project.getMapper().isDirty(); |
| 135 | } | 156 | } |
| @@ -349,6 +370,12 @@ public class GuiController implements ClientPacketHandler, GuiView, DataInvalida | |||
| 349 | return gui.getCursorReference(); | 370 | return gui.getCursorReference(); |
| 350 | } | 371 | } |
| 351 | 372 | ||
| 373 | @Override | ||
| 374 | @Nullable | ||
| 375 | public EntryView getCursorDeclaration() { | ||
| 376 | return gui.getCursorDeclaration(); | ||
| 377 | } | ||
| 378 | |||
| 352 | /** | 379 | /** |
| 353 | * Navigates to the declaration with respect to navigation history. | 380 | * Navigates to the declaration with respect to navigation history. |
| 354 | * | 381 | * |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/LookAndFeel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/LookAndFeel.java index 2088aac..2ac5d74 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/LookAndFeel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/LookAndFeel.java | |||
| @@ -22,6 +22,7 @@ public enum LookAndFeel { | |||
| 22 | // the "JVM default" look and feel, get it at the beginning and store it so we can set it later | 22 | // the "JVM default" look and feel, get it at the beginning and store it so we can set it later |
| 23 | private static final javax.swing.LookAndFeel NONE_LAF = UIManager.getLookAndFeel(); | 23 | private static final javax.swing.LookAndFeel NONE_LAF = UIManager.getLookAndFeel(); |
| 24 | private final boolean needsScaling; | 24 | private final boolean needsScaling; |
| 25 | private static Boolean isDarkLaf = null; | ||
| 25 | 26 | ||
| 26 | LookAndFeel(boolean needsScaling) { | 27 | LookAndFeel(boolean needsScaling) { |
| 27 | this.needsScaling = needsScaling; | 28 | this.needsScaling = needsScaling; |
| @@ -52,6 +53,10 @@ public enum LookAndFeel { | |||
| 52 | } | 53 | } |
| 53 | 54 | ||
| 54 | public static boolean isDarkLaf() { | 55 | public static boolean isDarkLaf() { |
| 56 | if (isDarkLaf != null) { | ||
| 57 | return isDarkLaf; | ||
| 58 | } | ||
| 59 | |||
| 55 | // a bit of a hack because swing doesn't give any API for that, and we need colors that aren't defined in look and feel | 60 | // a bit of a hack because swing doesn't give any API for that, and we need colors that aren't defined in look and feel |
| 56 | JPanel panel = new JPanel(); | 61 | JPanel panel = new JPanel(); |
| 57 | panel.setSize(new Dimension(10, 10)); | 62 | panel.setSize(new Dimension(10, 10)); |
| @@ -64,6 +69,6 @@ public enum LookAndFeel { | |||
| 64 | 69 | ||
| 65 | // convert the color we got to grayscale | 70 | // convert the color we got to grayscale |
| 66 | int b = (int) (0.3 * c.getRed() + 0.59 * c.getGreen() + 0.11 * c.getBlue()); | 71 | int b = (int) (0.3 * c.getRed() + 0.59 * c.getGreen() + 0.11 * c.getBlue()); |
| 67 | return b < 85; | 72 | return isDarkLaf = b < 85; |
| 68 | } | 73 | } |
| 69 | } | 74 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/GutterIcon.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/GutterIcon.java new file mode 100644 index 0000000..946591a --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/GutterIcon.java | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | package cuchaz.enigma.gui.elements; | ||
| 2 | |||
| 3 | import java.awt.Cursor; | ||
| 4 | import java.awt.event.ComponentAdapter; | ||
| 5 | import java.awt.event.ComponentEvent; | ||
| 6 | |||
| 7 | import javax.swing.JButton; | ||
| 8 | |||
| 9 | import cuchaz.enigma.api.service.GuiService; | ||
| 10 | import cuchaz.enigma.gui.util.EnigmaIconImpl; | ||
| 11 | import cuchaz.enigma.gui.util.ScaleUtil; | ||
| 12 | |||
| 13 | public class GutterIcon extends JButton implements GuiService.GutterMarkerBuilder { | ||
| 14 | private Runnable clickAction = () -> { }; | ||
| 15 | |||
| 16 | public GutterIcon(EnigmaIconImpl icon) { | ||
| 17 | super(icon.icon()); | ||
| 18 | setContentAreaFilled(false); | ||
| 19 | setCursor(Cursor.getDefaultCursor()); | ||
| 20 | addActionListener(e -> clickAction.run()); | ||
| 21 | |||
| 22 | addComponentListener(new ComponentAdapter() { | ||
| 23 | @Override | ||
| 24 | public void componentResized(ComponentEvent e) { | ||
| 25 | setIcon(icon.icon().derive(ScaleUtil.invert(getWidth()), ScaleUtil.invert(getHeight()))); | ||
| 26 | } | ||
| 27 | }); | ||
| 28 | } | ||
| 29 | |||
| 30 | @Override | ||
| 31 | public GuiService.GutterMarkerBuilder setClickAction(Runnable action) { | ||
| 32 | this.clickAction = action; | ||
| 33 | setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); | ||
| 34 | return this; | ||
| 35 | } | ||
| 36 | |||
| 37 | @Override | ||
| 38 | public GuiService.GutterMarkerBuilder setTooltip(String tooltip) { | ||
| 39 | setToolTipText(tooltip); | ||
| 40 | return this; | ||
| 41 | } | ||
| 42 | } | ||
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java index 6b341ee..92d1bd7 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java | |||
| @@ -15,6 +15,7 @@ import java.awt.event.MouseAdapter; | |||
| 15 | import java.awt.event.MouseEvent; | 15 | import java.awt.event.MouseEvent; |
| 16 | import java.util.ArrayList; | 16 | import java.util.ArrayList; |
| 17 | import java.util.Collection; | 17 | import java.util.Collection; |
| 18 | import java.util.Comparator; | ||
| 18 | import java.util.List; | 19 | import java.util.List; |
| 19 | import java.util.Map; | 20 | import java.util.Map; |
| 20 | 21 | ||
| @@ -35,10 +36,12 @@ import javax.swing.text.Highlighter.HighlightPainter; | |||
| 35 | 36 | ||
| 36 | import de.sciss.syntaxpane.DefaultSyntaxKit; | 37 | import de.sciss.syntaxpane.DefaultSyntaxKit; |
| 37 | import de.sciss.syntaxpane.SyntaxDocument; | 38 | import de.sciss.syntaxpane.SyntaxDocument; |
| 39 | import de.sciss.syntaxpane.actions.ActionUtils; | ||
| 38 | import org.jetbrains.annotations.Nullable; | 40 | import org.jetbrains.annotations.Nullable; |
| 39 | 41 | ||
| 40 | import cuchaz.enigma.EnigmaProject; | 42 | import cuchaz.enigma.EnigmaProject; |
| 41 | import cuchaz.enigma.analysis.EntryReference; | 43 | import cuchaz.enigma.analysis.EntryReference; |
| 44 | import cuchaz.enigma.api.service.GuiService; | ||
| 42 | import cuchaz.enigma.classhandle.ClassHandle; | 45 | import cuchaz.enigma.classhandle.ClassHandle; |
| 43 | import cuchaz.enigma.classhandle.ClassHandleError; | 46 | import cuchaz.enigma.classhandle.ClassHandleError; |
| 44 | import cuchaz.enigma.events.ClassHandleListener; | 47 | import cuchaz.enigma.events.ClassHandleListener; |
| @@ -50,14 +53,17 @@ import cuchaz.enigma.gui.config.LookAndFeel; | |||
| 50 | import cuchaz.enigma.gui.config.Themes; | 53 | import cuchaz.enigma.gui.config.Themes; |
| 51 | import cuchaz.enigma.gui.config.UiConfig; | 54 | import cuchaz.enigma.gui.config.UiConfig; |
| 52 | import cuchaz.enigma.gui.elements.EditorPopupMenu; | 55 | import cuchaz.enigma.gui.elements.EditorPopupMenu; |
| 56 | import cuchaz.enigma.gui.elements.GutterIcon; | ||
| 53 | import cuchaz.enigma.gui.events.EditorActionListener; | 57 | import cuchaz.enigma.gui.events.EditorActionListener; |
| 54 | import cuchaz.enigma.gui.events.ThemeChangeListener; | 58 | import cuchaz.enigma.gui.events.ThemeChangeListener; |
| 55 | import cuchaz.enigma.gui.highlight.BoxHighlightPainter; | 59 | import cuchaz.enigma.gui.highlight.BoxHighlightPainter; |
| 56 | import cuchaz.enigma.gui.highlight.SelectionHighlightPainter; | 60 | import cuchaz.enigma.gui.highlight.SelectionHighlightPainter; |
| 61 | import cuchaz.enigma.gui.util.EnigmaIconImpl; | ||
| 57 | import cuchaz.enigma.gui.util.GridBagConstraintsBuilder; | 62 | import cuchaz.enigma.gui.util.GridBagConstraintsBuilder; |
| 58 | import cuchaz.enigma.gui.util.ScaleUtil; | 63 | import cuchaz.enigma.gui.util.ScaleUtil; |
| 59 | import cuchaz.enigma.source.DecompiledClassSource; | 64 | import cuchaz.enigma.source.DecompiledClassSource; |
| 60 | import cuchaz.enigma.source.RenamableTokenType; | 65 | import cuchaz.enigma.source.RenamableTokenType; |
| 66 | import cuchaz.enigma.source.SourceIndex; | ||
| 61 | import cuchaz.enigma.source.Token; | 67 | import cuchaz.enigma.source.Token; |
| 62 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 68 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 63 | import cuchaz.enigma.translation.mapping.EntryResolver; | 69 | import cuchaz.enigma.translation.mapping.EntryResolver; |
| @@ -65,12 +71,14 @@ import cuchaz.enigma.translation.mapping.ResolutionStrategy; | |||
| 65 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 71 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 66 | import cuchaz.enigma.translation.representation.entry.Entry; | 72 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 67 | import cuchaz.enigma.utils.I18n; | 73 | import cuchaz.enigma.utils.I18n; |
| 74 | import cuchaz.enigma.utils.Pair; | ||
| 68 | import cuchaz.enigma.utils.Result; | 75 | import cuchaz.enigma.utils.Result; |
| 69 | 76 | ||
| 70 | public class EditorPanel { | 77 | public class EditorPanel { |
| 71 | private final JPanel ui = new JPanel(); | 78 | private final JPanel ui = new JPanel(); |
| 72 | private final JEditorPane editor = new JEditorPane(); | 79 | private final JEditorPane editor = new JEditorPane(); |
| 73 | private final JScrollPane editorScrollPane = new JScrollPane(this.editor); | 80 | private final JScrollPane editorScrollPane = new JScrollPane(this.editor); |
| 81 | private final GutterPanel gutterPanel; | ||
| 74 | private final EditorPopupMenu popupMenu; | 82 | private final EditorPopupMenu popupMenu; |
| 75 | 83 | ||
| 76 | // progress UI | 84 | // progress UI |
| @@ -109,20 +117,16 @@ public class EditorPanel { | |||
| 109 | this.gui = gui; | 117 | this.gui = gui; |
| 110 | this.controller = gui.getController(); | 118 | this.controller = gui.getController(); |
| 111 | 119 | ||
| 112 | this.editor.setEditable(false); | 120 | customizeEditor(this.editor); |
| 113 | this.editor.setSelectionColor(new Color(31, 46, 90)); | ||
| 114 | this.editor.setCaret(new BrowserCaret()); | ||
| 115 | this.editor.addCaretListener(event -> onCaretMove(event.getDot(), this.mouseIsPressed)); | 121 | this.editor.addCaretListener(event -> onCaretMove(event.getDot(), this.mouseIsPressed)); |
| 116 | this.editor.setCaretColor(UiConfig.getCaretColor()); | ||
| 117 | this.editor.setContentType("text/enigma-sources"); | ||
| 118 | this.editor.setBackground(UiConfig.getEditorBackgroundColor()); | ||
| 119 | DefaultSyntaxKit kit = (DefaultSyntaxKit) this.editor.getEditorKit(); | ||
| 120 | kit.toggleComponent(this.editor, "de.sciss.syntaxpane.components.TokenMarker"); | ||
| 121 | 122 | ||
| 122 | // set unit increment to height of one line, the amount scrolled per | 123 | // set unit increment to height of one line, the amount scrolled per |
| 123 | // mouse wheel rotation is then controlled by OS settings | 124 | // mouse wheel rotation is then controlled by OS settings |
| 124 | this.editorScrollPane.getVerticalScrollBar().setUnitIncrement(this.editor.getFontMetrics(this.editor.getFont()).getHeight()); | 125 | this.editorScrollPane.getVerticalScrollBar().setUnitIncrement(this.editor.getFontMetrics(this.editor.getFont()).getHeight()); |
| 125 | 126 | ||
| 127 | this.gutterPanel = new GutterPanel(this.editor, (JComponent) this.editorScrollPane.getRowHeader().getView()); | ||
| 128 | this.editorScrollPane.setRowHeaderView(this.gutterPanel); | ||
| 129 | |||
| 126 | // init editor popup menu | 130 | // init editor popup menu |
| 127 | this.popupMenu = new EditorPopupMenu(this, gui); | 131 | this.popupMenu = new EditorPopupMenu(this, gui); |
| 128 | this.editor.setComponentPopupMenu(this.popupMenu.getUi()); | 132 | this.editor.setComponentPopupMenu(this.popupMenu.getUi()); |
| @@ -255,6 +259,17 @@ public class EditorPanel { | |||
| 255 | this.ui.putClientProperty(EditorPanel.class, this); | 259 | this.ui.putClientProperty(EditorPanel.class, this); |
| 256 | } | 260 | } |
| 257 | 261 | ||
| 262 | public static void customizeEditor(JEditorPane editor) { | ||
| 263 | editor.setEditable(false); | ||
| 264 | editor.setSelectionColor(new Color(31, 46, 90)); | ||
| 265 | editor.setCaret(new BrowserCaret()); | ||
| 266 | editor.setCaretColor(UiConfig.getCaretColor()); | ||
| 267 | editor.setContentType("text/enigma-sources"); | ||
| 268 | editor.setBackground(UiConfig.getEditorBackgroundColor()); | ||
| 269 | DefaultSyntaxKit kit = (DefaultSyntaxKit) editor.getEditorKit(); | ||
| 270 | kit.toggleComponent(editor, "de.sciss.syntaxpane.components.TokenMarker"); | ||
| 271 | } | ||
| 272 | |||
| 258 | @Nullable | 273 | @Nullable |
| 259 | public static EditorPanel byUi(Component ui) { | 274 | public static EditorPanel byUi(Component ui) { |
| 260 | if (ui instanceof JComponent) { | 275 | if (ui instanceof JComponent) { |
| @@ -512,6 +527,7 @@ public class EditorPanel { | |||
| 512 | this.editor.setCaretPosition(newCaretPos); | 527 | this.editor.setCaretPosition(newCaretPos); |
| 513 | } | 528 | } |
| 514 | 529 | ||
| 530 | addGutterMarkers(source.getIndex()); | ||
| 515 | setHighlightedTokens(source.getHighlightedTokens()); | 531 | setHighlightedTokens(source.getHighlightedTokens()); |
| 516 | setCursorReference(getReference(getToken(this.editor.getCaretPosition()))); | 532 | setCursorReference(getReference(getToken(this.editor.getCaretPosition()))); |
| 517 | } finally { | 533 | } finally { |
| @@ -524,6 +540,44 @@ public class EditorPanel { | |||
| 524 | } | 540 | } |
| 525 | } | 541 | } |
| 526 | 542 | ||
| 543 | private void addGutterMarkers(SourceIndex sourceIndex) { | ||
| 544 | List<GuiService> services = this.gui.getController().enigma.getServices().get(GuiService.TYPE); | ||
| 545 | |||
| 546 | if (services.isEmpty()) { | ||
| 547 | return; | ||
| 548 | } | ||
| 549 | |||
| 550 | this.gutterPanel.clearMarkers(); | ||
| 551 | |||
| 552 | List<Pair<Entry<?>, Token>> declarationTokens = new ArrayList<>(); | ||
| 553 | |||
| 554 | for (Entry<?> declaration : sourceIndex.declarations()) { | ||
| 555 | declarationTokens.add(new Pair<>(declaration, sourceIndex.getDeclarationToken(declaration))); | ||
| 556 | } | ||
| 557 | |||
| 558 | declarationTokens.sort(Comparator.comparing(pair -> pair.b)); | ||
| 559 | |||
| 560 | for (Pair<Entry<?>, Token> declaration : declarationTokens) { | ||
| 561 | int lineNumber; | ||
| 562 | |||
| 563 | try { | ||
| 564 | lineNumber = ActionUtils.getLineNumber(this.editor, declaration.b.start); | ||
| 565 | } catch (BadLocationException e) { | ||
| 566 | continue; | ||
| 567 | } | ||
| 568 | |||
| 569 | for (GuiService service : services) { | ||
| 570 | service.addGutterMarkers(this.gui.getController(), declaration.a, (icon, alignment) -> { | ||
| 571 | GutterIcon button = new GutterIcon((EnigmaIconImpl) icon); | ||
| 572 | this.gutterPanel.addMarker(lineNumber, alignment, button); | ||
| 573 | return button; | ||
| 574 | }); | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | this.editor.revalidate(); | ||
| 579 | } | ||
| 580 | |||
| 527 | public void setHighlightedTokens(Map<RenamableTokenType, ? extends Collection<Token>> tokens) { | 581 | public void setHighlightedTokens(Map<RenamableTokenType, ? extends Collection<Token>> tokens) { |
| 528 | // remove any old highlighters | 582 | // remove any old highlighters |
| 529 | this.editor.getHighlighter().removeAllHighlights(); | 583 | this.editor.getHighlighter().removeAllHighlights(); |
| @@ -565,10 +619,23 @@ public class EditorPanel { | |||
| 565 | } | 619 | } |
| 566 | } | 620 | } |
| 567 | 621 | ||
| 622 | @Nullable | ||
| 568 | public EntryReference<Entry<?>, Entry<?>> getCursorReference() { | 623 | public EntryReference<Entry<?>, Entry<?>> getCursorReference() { |
| 569 | return this.cursorReference; | 624 | return this.cursorReference; |
| 570 | } | 625 | } |
| 571 | 626 | ||
| 627 | @Nullable | ||
| 628 | public Entry<?> getCursorDeclaration() { | ||
| 629 | int pos = this.editor.getCaretPosition(); | ||
| 630 | Token token = getToken(pos); | ||
| 631 | |||
| 632 | if (token == null) { | ||
| 633 | return null; | ||
| 634 | } | ||
| 635 | |||
| 636 | return this.source.getIndex().getDeclaration(token); | ||
| 637 | } | ||
| 638 | |||
| 572 | public void showReference(EntryReference<Entry<?>, Entry<?>> reference) { | 639 | public void showReference(EntryReference<Entry<?>, Entry<?>> reference) { |
| 573 | if (this.mode == DisplayMode.SUCCESS) { | 640 | if (this.mode == DisplayMode.SUCCESS) { |
| 574 | showReference0(reference); | 641 | showReference0(reference); |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/GutterPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/GutterPanel.java new file mode 100644 index 0000000..28636a1 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/GutterPanel.java | |||
| @@ -0,0 +1,238 @@ | |||
| 1 | package cuchaz.enigma.gui.panels; | ||
| 2 | |||
| 3 | import java.awt.Color; | ||
| 4 | import java.awt.Component; | ||
| 5 | import java.awt.Container; | ||
| 6 | import java.awt.Dimension; | ||
| 7 | import java.awt.FlowLayout; | ||
| 8 | import java.awt.FontMetrics; | ||
| 9 | import java.awt.Graphics; | ||
| 10 | import java.awt.Insets; | ||
| 11 | import java.awt.LayoutManager2; | ||
| 12 | import java.beans.PropertyChangeEvent; | ||
| 13 | import java.beans.PropertyChangeListener; | ||
| 14 | import java.util.HashMap; | ||
| 15 | import java.util.Map; | ||
| 16 | |||
| 17 | import javax.swing.BorderFactory; | ||
| 18 | import javax.swing.JComponent; | ||
| 19 | import javax.swing.JEditorPane; | ||
| 20 | import javax.swing.JPanel; | ||
| 21 | import javax.swing.SwingUtilities; | ||
| 22 | import javax.swing.event.CaretEvent; | ||
| 23 | import javax.swing.event.CaretListener; | ||
| 24 | import javax.swing.event.DocumentEvent; | ||
| 25 | import javax.swing.event.DocumentListener; | ||
| 26 | import javax.swing.text.BadLocationException; | ||
| 27 | |||
| 28 | import de.sciss.syntaxpane.actions.ActionUtils; | ||
| 29 | |||
| 30 | import cuchaz.enigma.api.service.GuiService; | ||
| 31 | import cuchaz.enigma.gui.config.UiConfig; | ||
| 32 | |||
| 33 | public class GutterPanel extends JPanel { | ||
| 34 | private final JPanel markerPanel; | ||
| 35 | |||
| 36 | public GutterPanel(JEditorPane editor, JComponent lineNumbers) { | ||
| 37 | markerPanel = new MarkerPanel(editor); | ||
| 38 | |||
| 39 | setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); | ||
| 40 | add(lineNumbers); | ||
| 41 | add(markerPanel); | ||
| 42 | |||
| 43 | setBackground(UiConfig.getLineNumbersBackgroundColor()); | ||
| 44 | setForeground(UiConfig.getLineNumbersForegroundColor()); | ||
| 45 | markerPanel.setBackground(UiConfig.getLineNumbersBackgroundColor()); | ||
| 46 | markerPanel.setForeground(UiConfig.getLineNumbersForegroundColor()); | ||
| 47 | setBorder(lineNumbers.getBorder()); | ||
| 48 | lineNumbers.setBorder(null); | ||
| 49 | } | ||
| 50 | |||
| 51 | public void clearMarkers() { | ||
| 52 | markerPanel.removeAll(); | ||
| 53 | } | ||
| 54 | |||
| 55 | public void addMarker(int line, GuiService.GutterMarkerAlignment alignment, Component marker) { | ||
| 56 | markerPanel.add(marker, new MarkerLayout.Constraint(line, alignment)); | ||
| 57 | } | ||
| 58 | |||
| 59 | private static class MarkerPanel extends JPanel implements CaretListener, DocumentListener, PropertyChangeListener { | ||
| 60 | private final JEditorPane editor; | ||
| 61 | private final Color currentLineColor = UiConfig.getLineNumbersSelectedColor(); | ||
| 62 | |||
| 63 | private MarkerPanel(JEditorPane editor) { | ||
| 64 | this.editor = editor; | ||
| 65 | setLayout(new MarkerLayout()); | ||
| 66 | |||
| 67 | Insets editorInsets = editor.getInsets(); | ||
| 68 | |||
| 69 | if (editorInsets.top != 0 || editorInsets.bottom != 0) { | ||
| 70 | setBorder(BorderFactory.createEmptyBorder(editorInsets.top, 0, editorInsets.bottom, 0)); | ||
| 71 | } | ||
| 72 | |||
| 73 | setFont(editor.getFont()); | ||
| 74 | |||
| 75 | editor.addCaretListener(this); | ||
| 76 | editor.getDocument().addDocumentListener(this); | ||
| 77 | editor.addPropertyChangeListener(this); | ||
| 78 | } | ||
| 79 | |||
| 80 | @Override | ||
| 81 | protected void paintComponent(Graphics g) { | ||
| 82 | super.paintComponent(g); | ||
| 83 | |||
| 84 | int currentLine; | ||
| 85 | |||
| 86 | try { | ||
| 87 | currentLine = ActionUtils.getLineNumber(editor, editor.getCaretPosition()); | ||
| 88 | } catch (BadLocationException ex) { | ||
| 89 | return; // no valid caret -> nothing to draw | ||
| 90 | } | ||
| 91 | |||
| 92 | FontMetrics fm = getFontMetrics(getFont()); | ||
| 93 | int lh = fm.getHeight(); | ||
| 94 | Insets insets = getInsets(); | ||
| 95 | |||
| 96 | int y = currentLine * lh; | ||
| 97 | |||
| 98 | g.setColor(currentLineColor); | ||
| 99 | g.fillRect(0, y, getWidth(), lh); | ||
| 100 | } | ||
| 101 | |||
| 102 | @Override | ||
| 103 | public void propertyChange(PropertyChangeEvent evt) { | ||
| 104 | if (evt.getPropertyName().equals("document")) { | ||
| 105 | repaint(); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | @Override | ||
| 110 | public void caretUpdate(CaretEvent e) { | ||
| 111 | repaint(); | ||
| 112 | } | ||
| 113 | |||
| 114 | @Override | ||
| 115 | public void insertUpdate(DocumentEvent e) { | ||
| 116 | documentChanged(); | ||
| 117 | } | ||
| 118 | |||
| 119 | @Override | ||
| 120 | public void removeUpdate(DocumentEvent e) { | ||
| 121 | documentChanged(); | ||
| 122 | } | ||
| 123 | |||
| 124 | @Override | ||
| 125 | public void changedUpdate(DocumentEvent e) { | ||
| 126 | documentChanged(); | ||
| 127 | } | ||
| 128 | |||
| 129 | private void documentChanged() { | ||
| 130 | SwingUtilities.invokeLater(this::repaint); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | private static class MarkerLayout implements LayoutManager2 { | ||
| 135 | private static final int GAP = 2; | ||
| 136 | private static final int HUGE_HEIGHT = 0x100000; // taken from LineNumbersRuler | ||
| 137 | |||
| 138 | private final Map<Component, Constraint> constraints = new HashMap<>(); | ||
| 139 | |||
| 140 | @Override | ||
| 141 | public void addLayoutComponent(Component comp, Object constraints) { | ||
| 142 | this.constraints.put(comp, (Constraint) constraints); | ||
| 143 | } | ||
| 144 | |||
| 145 | @Override | ||
| 146 | public Dimension maximumLayoutSize(Container target) { | ||
| 147 | return preferredLayoutSize(target); | ||
| 148 | } | ||
| 149 | |||
| 150 | @Override | ||
| 151 | public float getLayoutAlignmentX(Container target) { | ||
| 152 | return 0.5f; | ||
| 153 | } | ||
| 154 | |||
| 155 | @Override | ||
| 156 | public float getLayoutAlignmentY(Container target) { | ||
| 157 | return 0.5f; | ||
| 158 | } | ||
| 159 | |||
| 160 | @Override | ||
| 161 | public void invalidateLayout(Container target) { | ||
| 162 | } | ||
| 163 | |||
| 164 | @Override | ||
| 165 | public void addLayoutComponent(String name, Component comp) { | ||
| 166 | } | ||
| 167 | |||
| 168 | @Override | ||
| 169 | public void removeLayoutComponent(Component comp) { | ||
| 170 | constraints.remove(comp); | ||
| 171 | } | ||
| 172 | |||
| 173 | @Override | ||
| 174 | public Dimension preferredLayoutSize(Container parent) { | ||
| 175 | synchronized (parent.getTreeLock()) { | ||
| 176 | Insets insets = parent.getInsets(); | ||
| 177 | |||
| 178 | if (constraints.isEmpty()) { | ||
| 179 | return new Dimension(insets.left + insets.right, HUGE_HEIGHT); | ||
| 180 | } | ||
| 181 | |||
| 182 | Map<Integer, Integer> leftCount = new HashMap<>(); | ||
| 183 | Map<Integer, Integer> rightCount = new HashMap<>(); | ||
| 184 | |||
| 185 | for (Constraint constraint : constraints.values()) { | ||
| 186 | switch (constraint.alignment) { | ||
| 187 | case LEFT -> leftCount.merge(constraint.line, 1, Integer::sum); | ||
| 188 | case RIGHT -> rightCount.merge(constraint.line, 1, Integer::sum); | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | int maxLeft = leftCount.values().stream().mapToInt(Integer::intValue).max().orElse(0); | ||
| 193 | int maxRight = rightCount.values().stream().mapToInt(Integer::intValue).max().orElse(0); | ||
| 194 | |||
| 195 | int lineHeight = parent.getFontMetrics(parent.getFont()).getHeight(); | ||
| 196 | return new Dimension( | ||
| 197 | GAP + insets.left + insets.right + (maxLeft + maxRight) * lineHeight, | ||
| 198 | HUGE_HEIGHT | ||
| 199 | ); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | @Override | ||
| 204 | public Dimension minimumLayoutSize(Container parent) { | ||
| 205 | return preferredLayoutSize(parent); | ||
| 206 | } | ||
| 207 | |||
| 208 | @Override | ||
| 209 | public void layoutContainer(Container parent) { | ||
| 210 | synchronized (parent.getTreeLock()) { | ||
| 211 | Map<Integer, Integer> leftCount = new HashMap<>(); | ||
| 212 | Map<Integer, Integer> rightCount = new HashMap<>(); | ||
| 213 | |||
| 214 | int lineHeight = parent.getFontMetrics(parent.getFont()).getHeight(); | ||
| 215 | |||
| 216 | int numComponents = parent.getComponentCount(); | ||
| 217 | |||
| 218 | for (int i = 0; i < numComponents; i++) { | ||
| 219 | Component comp = parent.getComponent(i); | ||
| 220 | Constraint constraint = constraints.get(comp); | ||
| 221 | |||
| 222 | if (constraint == null) { | ||
| 223 | continue; | ||
| 224 | } | ||
| 225 | |||
| 226 | int left = switch (constraint.alignment) { | ||
| 227 | case LEFT -> GAP + (leftCount.merge(constraint.line, 1, Integer::sum) - 1) * lineHeight + GAP / 2; | ||
| 228 | case RIGHT -> parent.getWidth() - rightCount.merge(constraint.line, 1, Integer::sum) * lineHeight + GAP / 2; | ||
| 229 | }; | ||
| 230 | comp.setBounds(left, constraint.line * lineHeight + GAP / 2, lineHeight - GAP, lineHeight - GAP); | ||
| 231 | } | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | private record Constraint(int line, GuiService.GutterMarkerAlignment alignment) { | ||
| 236 | } | ||
| 237 | } | ||
| 238 | } | ||
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/EnigmaIconImpl.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/EnigmaIconImpl.java new file mode 100644 index 0000000..8e07df3 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/EnigmaIconImpl.java | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | package cuchaz.enigma.gui.util; | ||
| 2 | |||
| 3 | import com.formdev.flatlaf.extras.FlatSVGIcon; | ||
| 4 | |||
| 5 | import cuchaz.enigma.api.EnigmaIcon; | ||
| 6 | |||
| 7 | public record EnigmaIconImpl(FlatSVGIcon icon) implements EnigmaIcon { | ||
| 8 | } | ||
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/IconLoadingServiceImpl.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/IconLoadingServiceImpl.java new file mode 100644 index 0000000..e948f5a --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/IconLoadingServiceImpl.java | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | package cuchaz.enigma.gui.util; | ||
| 2 | |||
| 3 | import java.io.IOException; | ||
| 4 | import java.io.InputStream; | ||
| 5 | |||
| 6 | import com.formdev.flatlaf.extras.FlatSVGIcon; | ||
| 7 | |||
| 8 | import cuchaz.enigma.api.EnigmaIcon; | ||
| 9 | import cuchaz.enigma.utils.IconLoadingService; | ||
| 10 | |||
| 11 | public class IconLoadingServiceImpl implements IconLoadingService { | ||
| 12 | @Override | ||
| 13 | public EnigmaIcon loadIcon(InputStream in) throws IOException { | ||
| 14 | return new EnigmaIconImpl(new FlatSVGIcon(in)); | ||
| 15 | } | ||
| 16 | } | ||
diff --git a/enigma-swing/src/main/resources/META-INF/services/cuchaz.enigma.utils.IconLoadingService b/enigma-swing/src/main/resources/META-INF/services/cuchaz.enigma.utils.IconLoadingService new file mode 100644 index 0000000..649dfd0 --- /dev/null +++ b/enigma-swing/src/main/resources/META-INF/services/cuchaz.enigma.utils.IconLoadingService | |||
| @@ -0,0 +1 @@ | |||
| cuchaz.enigma.gui.util.IconLoadingServiceImpl | |||
diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java index 348e640..5242385 100644 --- a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java +++ b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java | |||
| @@ -410,6 +410,11 @@ public class EnigmaProject implements ProjectView { | |||
| 410 | } | 410 | } |
| 411 | 411 | ||
| 412 | @Override | 412 | @Override |
| 413 | public Collection<String> getProjectAndLibraryClasses() { | ||
| 414 | return classProvider.getClassNames(); | ||
| 415 | } | ||
| 416 | |||
| 417 | @Override | ||
| 413 | @Nullable | 418 | @Nullable |
| 414 | public ClassNode getBytecode(String className) { | 419 | public ClassNode getBytecode(String className) { |
| 415 | return classProvider.get(className); | 420 | return classProvider.get(className); |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java index adb48ba..b852b5f 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java | |||
| @@ -10,6 +10,8 @@ import java.util.concurrent.ConcurrentMap; | |||
| 10 | 10 | ||
| 11 | import org.jetbrains.annotations.Nullable; | 11 | import org.jetbrains.annotations.Nullable; |
| 12 | 12 | ||
| 13 | import cuchaz.enigma.api.view.entry.MethodEntryView; | ||
| 14 | import cuchaz.enigma.api.view.index.BridgeMethodIndexView; | ||
| 13 | import cuchaz.enigma.translation.representation.AccessFlags; | 15 | import cuchaz.enigma.translation.representation.AccessFlags; |
| 14 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 16 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 15 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 17 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| @@ -17,7 +19,7 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry; | |||
| 17 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | 19 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 18 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 20 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 19 | 21 | ||
| 20 | public class BridgeMethodIndex implements JarIndexer { | 22 | public class BridgeMethodIndex implements JarIndexer, BridgeMethodIndexView { |
| 21 | private final EntryIndex entryIndex; | 23 | private final EntryIndex entryIndex; |
| 22 | private final InheritanceIndex inheritanceIndex; | 24 | private final InheritanceIndex inheritanceIndex; |
| 23 | private final ReferenceIndex referenceIndex; | 25 | private final ReferenceIndex referenceIndex; |
| @@ -154,6 +156,18 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 154 | return bridgeToSpecialized.get(bridge); | 156 | return bridgeToSpecialized.get(bridge); |
| 155 | } | 157 | } |
| 156 | 158 | ||
| 159 | @Override | ||
| 160 | @Nullable | ||
| 161 | public MethodEntryView getBridgeFromSpecialized(MethodEntryView specialized) { | ||
| 162 | return getBridgeFromSpecialized((MethodEntry) specialized); | ||
| 163 | } | ||
| 164 | |||
| 165 | @Override | ||
| 166 | @Nullable | ||
| 167 | public MethodEntryView getSpecializedFromBridge(MethodEntryView bridge) { | ||
| 168 | return getSpecializedFromBridge((MethodEntry) bridge); | ||
| 169 | } | ||
| 170 | |||
| 157 | /** Includes "renamed specialized -> bridge" entries. */ | 171 | /** Includes "renamed specialized -> bridge" entries. */ |
| 158 | public Map<MethodEntry, MethodEntry> getSpecializedToBridge() { | 172 | public Map<MethodEntry, MethodEntry> getSpecializedToBridge() { |
| 159 | return Collections.unmodifiableMap(specializedToBridge); | 173 | return Collections.unmodifiableMap(specializedToBridge); |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java index 5c5e2c3..242d750 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java | |||
| @@ -204,6 +204,7 @@ public class JarIndex implements JarIndexer, JarIndexView { | |||
| 204 | return referenceIndex; | 204 | return referenceIndex; |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | @Override | ||
| 207 | public BridgeMethodIndex getBridgeMethodIndex() { | 208 | public BridgeMethodIndex getBridgeMethodIndex() { |
| 208 | return bridgeMethodIndex; | 209 | return bridgeMethodIndex; |
| 209 | } | 210 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/DataInvalidationEvent.java b/enigma/src/main/java/cuchaz/enigma/api/DataInvalidationEvent.java index 812ad39..9396eff 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/DataInvalidationEvent.java +++ b/enigma/src/main/java/cuchaz/enigma/api/DataInvalidationEvent.java | |||
| @@ -2,8 +2,10 @@ package cuchaz.enigma.api; | |||
| 2 | 2 | ||
| 3 | import java.util.Collection; | 3 | import java.util.Collection; |
| 4 | 4 | ||
| 5 | import org.jetbrains.annotations.ApiStatus; | ||
| 5 | import org.jetbrains.annotations.Nullable; | 6 | import org.jetbrains.annotations.Nullable; |
| 6 | 7 | ||
| 8 | @ApiStatus.NonExtendable | ||
| 7 | public interface DataInvalidationEvent { | 9 | public interface DataInvalidationEvent { |
| 8 | /** | 10 | /** |
| 9 | * The classes for which the invalidation applies, or {@code null} if the invalidation applies to all classes. | 11 | * The classes for which the invalidation applies, or {@code null} if the invalidation applies to all classes. |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/EnigmaIcon.java b/enigma/src/main/java/cuchaz/enigma/api/EnigmaIcon.java new file mode 100644 index 0000000..4a4bd0e --- /dev/null +++ b/enigma/src/main/java/cuchaz/enigma/api/EnigmaIcon.java | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | package cuchaz.enigma.api; | ||
| 2 | |||
| 3 | import java.io.IOException; | ||
| 4 | import java.io.InputStream; | ||
| 5 | |||
| 6 | import org.jetbrains.annotations.ApiStatus; | ||
| 7 | |||
| 8 | import cuchaz.enigma.utils.IconLoadingService; | ||
| 9 | |||
| 10 | @ApiStatus.NonExtendable | ||
| 11 | public interface EnigmaIcon { | ||
| 12 | /** | ||
| 13 | * Loads an icon resource from the given SVG resource path. | ||
| 14 | * | ||
| 15 | * @param resource the path to the resource to be loaded | ||
| 16 | * @return The loaded icon | ||
| 17 | * @throws IOException if the resource could not be found or an error occurred while reading it | ||
| 18 | */ | ||
| 19 | static EnigmaIcon loadResource(String resource) throws IOException { | ||
| 20 | try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource)) { | ||
| 21 | if (in == null) { | ||
| 22 | throw new IOException("Could not find resource: " + resource); | ||
| 23 | } | ||
| 24 | |||
| 25 | return load(in); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | /** | ||
| 30 | * Loads an icon in SVG format from the given input stream. | ||
| 31 | * | ||
| 32 | * @param in the input stream to load from | ||
| 33 | * @return The loaded icon | ||
| 34 | * @throws IOException if the stream throws an error | ||
| 35 | */ | ||
| 36 | static EnigmaIcon load(InputStream in) throws IOException { | ||
| 37 | return IconLoadingService.INSTANCE.loadIcon(in); | ||
| 38 | } | ||
| 39 | } | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/api/service/GuiService.java b/enigma/src/main/java/cuchaz/enigma/api/service/GuiService.java index b00b94d..53b566f 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/service/GuiService.java +++ b/enigma/src/main/java/cuchaz/enigma/api/service/GuiService.java | |||
| @@ -5,7 +5,9 @@ import java.util.function.Supplier; | |||
| 5 | 5 | ||
| 6 | import javax.swing.KeyStroke; | 6 | import javax.swing.KeyStroke; |
| 7 | 7 | ||
| 8 | import cuchaz.enigma.api.EnigmaIcon; | ||
| 8 | import cuchaz.enigma.api.view.GuiView; | 9 | import cuchaz.enigma.api.view.GuiView; |
| 10 | import cuchaz.enigma.api.view.entry.EntryView; | ||
| 9 | 11 | ||
| 10 | public interface GuiService extends EnigmaService { | 12 | public interface GuiService extends EnigmaService { |
| 11 | EnigmaServiceType<GuiService> TYPE = EnigmaServiceType.create("gui"); | 13 | EnigmaServiceType<GuiService> TYPE = EnigmaServiceType.create("gui"); |
| @@ -16,6 +18,9 @@ public interface GuiService extends EnigmaService { | |||
| 16 | default void addToEditorContextMenu(GuiView gui, MenuRegistrar registrar) { | 18 | default void addToEditorContextMenu(GuiView gui, MenuRegistrar registrar) { |
| 17 | } | 19 | } |
| 18 | 20 | ||
| 21 | default void addGutterMarkers(GuiView gui, EntryView entry, GutterMarkerAdder gutter) { | ||
| 22 | } | ||
| 23 | |||
| 19 | interface MenuRegistrar { | 24 | interface MenuRegistrar { |
| 20 | void addSeparator(); | 25 | void addSeparator(); |
| 21 | 26 | ||
| @@ -31,4 +36,17 @@ public interface GuiService extends EnigmaService { | |||
| 31 | MenuItemBuilder setEnabledWhen(BooleanSupplier condition); | 36 | MenuItemBuilder setEnabledWhen(BooleanSupplier condition); |
| 32 | MenuItemBuilder setAction(Runnable action); | 37 | MenuItemBuilder setAction(Runnable action); |
| 33 | } | 38 | } |
| 39 | |||
| 40 | interface GutterMarkerAdder { | ||
| 41 | GutterMarkerBuilder addMarker(EnigmaIcon icon, GutterMarkerAlignment alignment); | ||
| 42 | } | ||
| 43 | |||
| 44 | interface GutterMarkerBuilder { | ||
| 45 | GutterMarkerBuilder setClickAction(Runnable action); | ||
| 46 | GutterMarkerBuilder setTooltip(String tooltip); | ||
| 47 | } | ||
| 48 | |||
| 49 | enum GutterMarkerAlignment { | ||
| 50 | LEFT, RIGHT | ||
| 51 | } | ||
| 34 | } | 52 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/GuiView.java b/enigma/src/main/java/cuchaz/enigma/api/view/GuiView.java index 519a8ce..1d91573 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/GuiView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/GuiView.java | |||
| @@ -1,11 +1,15 @@ | |||
| 1 | package cuchaz.enigma.api.view; | 1 | package cuchaz.enigma.api.view; |
| 2 | 2 | ||
| 3 | import javax.swing.JEditorPane; | ||
| 3 | import javax.swing.JFrame; | 4 | import javax.swing.JFrame; |
| 4 | 5 | ||
| 6 | import org.jetbrains.annotations.ApiStatus; | ||
| 5 | import org.jetbrains.annotations.Nullable; | 7 | import org.jetbrains.annotations.Nullable; |
| 6 | 8 | ||
| 7 | import cuchaz.enigma.api.view.entry.EntryReferenceView; | 9 | import cuchaz.enigma.api.view.entry.EntryReferenceView; |
| 10 | import cuchaz.enigma.api.view.entry.EntryView; | ||
| 8 | 11 | ||
| 12 | @ApiStatus.NonExtendable | ||
| 9 | public interface GuiView { | 13 | public interface GuiView { |
| 10 | @Nullable | 14 | @Nullable |
| 11 | ProjectView getProject(); | 15 | ProjectView getProject(); |
| @@ -13,5 +17,14 @@ public interface GuiView { | |||
| 13 | @Nullable | 17 | @Nullable |
| 14 | EntryReferenceView getCursorReference(); | 18 | EntryReferenceView getCursorReference(); |
| 15 | 19 | ||
| 20 | @Nullable | ||
| 21 | EntryView getCursorDeclaration(); | ||
| 22 | |||
| 16 | JFrame getFrame(); | 23 | JFrame getFrame(); |
| 24 | |||
| 25 | float getScale(); | ||
| 26 | |||
| 27 | boolean isDarkTheme(); | ||
| 28 | |||
| 29 | JEditorPane createEditorPane(); | ||
| 17 | } | 30 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/ProjectView.java b/enigma/src/main/java/cuchaz/enigma/api/view/ProjectView.java index b72e1c3..c8cb384 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/ProjectView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/ProjectView.java | |||
| @@ -3,6 +3,7 @@ package cuchaz.enigma.api.view; | |||
| 3 | import java.util.Collection; | 3 | import java.util.Collection; |
| 4 | import java.util.List; | 4 | import java.util.List; |
| 5 | 5 | ||
| 6 | import org.jetbrains.annotations.ApiStatus; | ||
| 6 | import org.jetbrains.annotations.Nullable; | 7 | import org.jetbrains.annotations.Nullable; |
| 7 | import org.objectweb.asm.tree.ClassNode; | 8 | import org.objectweb.asm.tree.ClassNode; |
| 8 | 9 | ||
| @@ -11,6 +12,7 @@ import cuchaz.enigma.api.DataInvalidationListener; | |||
| 11 | import cuchaz.enigma.api.view.entry.EntryView; | 12 | import cuchaz.enigma.api.view.entry.EntryView; |
| 12 | import cuchaz.enigma.api.view.index.JarIndexView; | 13 | import cuchaz.enigma.api.view.index.JarIndexView; |
| 13 | 14 | ||
| 15 | @ApiStatus.NonExtendable | ||
| 14 | public interface ProjectView { | 16 | public interface ProjectView { |
| 15 | <T extends EntryView> T deobfuscate(T entry); | 17 | <T extends EntryView> T deobfuscate(T entry); |
| 16 | 18 | ||
| @@ -25,6 +27,8 @@ public interface ProjectView { | |||
| 25 | 27 | ||
| 26 | Collection<String> getProjectClasses(); | 28 | Collection<String> getProjectClasses(); |
| 27 | 29 | ||
| 30 | Collection<String> getProjectAndLibraryClasses(); | ||
| 31 | |||
| 28 | @Nullable | 32 | @Nullable |
| 29 | ClassNode getBytecode(String className); | 33 | ClassNode getBytecode(String className); |
| 30 | 34 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/entry/ClassDefEntryView.java b/enigma/src/main/java/cuchaz/enigma/api/view/entry/ClassDefEntryView.java index 7cb1829..1fb6a7f 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/entry/ClassDefEntryView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/entry/ClassDefEntryView.java | |||
| @@ -1,7 +1,9 @@ | |||
| 1 | package cuchaz.enigma.api.view.entry; | 1 | package cuchaz.enigma.api.view.entry; |
| 2 | 2 | ||
| 3 | import org.jetbrains.annotations.ApiStatus; | ||
| 3 | import org.jetbrains.annotations.Nullable; | 4 | import org.jetbrains.annotations.Nullable; |
| 4 | 5 | ||
| 6 | @ApiStatus.NonExtendable | ||
| 5 | public interface ClassDefEntryView extends ClassEntryView, DefEntryView { | 7 | public interface ClassDefEntryView extends ClassEntryView, DefEntryView { |
| 6 | @Nullable | 8 | @Nullable |
| 7 | ClassEntryView getSuperClass(); | 9 | ClassEntryView getSuperClass(); |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/entry/ClassEntryView.java b/enigma/src/main/java/cuchaz/enigma/api/view/entry/ClassEntryView.java index 085188b..330920b 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/entry/ClassEntryView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/entry/ClassEntryView.java | |||
| @@ -1,7 +1,10 @@ | |||
| 1 | package cuchaz.enigma.api.view.entry; | 1 | package cuchaz.enigma.api.view.entry; |
| 2 | 2 | ||
| 3 | import org.jetbrains.annotations.ApiStatus; | ||
| 4 | |||
| 3 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 5 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 4 | 6 | ||
| 7 | @ApiStatus.NonExtendable | ||
| 5 | public interface ClassEntryView extends EntryView { | 8 | public interface ClassEntryView extends EntryView { |
| 6 | ClassEntryView getParent(); | 9 | ClassEntryView getParent(); |
| 7 | 10 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/entry/DefEntryView.java b/enigma/src/main/java/cuchaz/enigma/api/view/entry/DefEntryView.java index bf246fb..a52e685 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/entry/DefEntryView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/entry/DefEntryView.java | |||
| @@ -1,5 +1,8 @@ | |||
| 1 | package cuchaz.enigma.api.view.entry; | 1 | package cuchaz.enigma.api.view.entry; |
| 2 | 2 | ||
| 3 | import org.jetbrains.annotations.ApiStatus; | ||
| 4 | |||
| 5 | @ApiStatus.NonExtendable | ||
| 3 | public interface DefEntryView { | 6 | public interface DefEntryView { |
| 4 | int getAccessFlags(); | 7 | int getAccessFlags(); |
| 5 | } | 8 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/entry/EntryReferenceView.java b/enigma/src/main/java/cuchaz/enigma/api/view/entry/EntryReferenceView.java index d49aa1e..6ca87ab 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/entry/EntryReferenceView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/entry/EntryReferenceView.java | |||
| @@ -1,5 +1,8 @@ | |||
| 1 | package cuchaz.enigma.api.view.entry; | 1 | package cuchaz.enigma.api.view.entry; |
| 2 | 2 | ||
| 3 | import org.jetbrains.annotations.ApiStatus; | ||
| 4 | |||
| 5 | @ApiStatus.NonExtendable | ||
| 3 | public interface EntryReferenceView { | 6 | public interface EntryReferenceView { |
| 4 | EntryView getEntry(); | 7 | EntryView getEntry(); |
| 5 | } | 8 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/entry/EntryView.java b/enigma/src/main/java/cuchaz/enigma/api/view/entry/EntryView.java index 2dad562..963c1e7 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/entry/EntryView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/entry/EntryView.java | |||
| @@ -1,7 +1,9 @@ | |||
| 1 | package cuchaz.enigma.api.view.entry; | 1 | package cuchaz.enigma.api.view.entry; |
| 2 | 2 | ||
| 3 | import org.jetbrains.annotations.ApiStatus; | ||
| 3 | import org.jetbrains.annotations.Nullable; | 4 | import org.jetbrains.annotations.Nullable; |
| 4 | 5 | ||
| 6 | @ApiStatus.NonExtendable | ||
| 5 | public interface EntryView { | 7 | public interface EntryView { |
| 6 | /** | 8 | /** |
| 7 | * Returns the default name of this entry. | 9 | * Returns the default name of this entry. |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/entry/FieldEntryView.java b/enigma/src/main/java/cuchaz/enigma/api/view/entry/FieldEntryView.java index ae44458..bf22814 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/entry/FieldEntryView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/entry/FieldEntryView.java | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | package cuchaz.enigma.api.view.entry; | 1 | package cuchaz.enigma.api.view.entry; |
| 2 | 2 | ||
| 3 | import org.jetbrains.annotations.ApiStatus; | ||
| 4 | |||
| 3 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 5 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 4 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 6 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 5 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 7 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 6 | 8 | ||
| 9 | @ApiStatus.NonExtendable | ||
| 7 | public interface FieldEntryView extends EntryView { | 10 | public interface FieldEntryView extends EntryView { |
| 8 | String getDescriptor(); | 11 | String getDescriptor(); |
| 9 | 12 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/entry/LocalVariableDefEntryView.java b/enigma/src/main/java/cuchaz/enigma/api/view/entry/LocalVariableDefEntryView.java index d091560..32e0af3 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/entry/LocalVariableDefEntryView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/entry/LocalVariableDefEntryView.java | |||
| @@ -1,5 +1,8 @@ | |||
| 1 | package cuchaz.enigma.api.view.entry; | 1 | package cuchaz.enigma.api.view.entry; |
| 2 | 2 | ||
| 3 | import org.jetbrains.annotations.ApiStatus; | ||
| 4 | |||
| 5 | @ApiStatus.NonExtendable | ||
| 3 | public interface LocalVariableDefEntryView extends LocalVariableEntryView { | 6 | public interface LocalVariableDefEntryView extends LocalVariableEntryView { |
| 4 | String getDescriptor(); | 7 | String getDescriptor(); |
| 5 | } | 8 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/entry/LocalVariableEntryView.java b/enigma/src/main/java/cuchaz/enigma/api/view/entry/LocalVariableEntryView.java index 391bc0f..b4728b5 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/entry/LocalVariableEntryView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/entry/LocalVariableEntryView.java | |||
| @@ -1,9 +1,19 @@ | |||
| 1 | package cuchaz.enigma.api.view.entry; | 1 | package cuchaz.enigma.api.view.entry; |
| 2 | 2 | ||
| 3 | import org.jetbrains.annotations.ApiStatus; | ||
| 4 | |||
| 5 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 6 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 7 | |||
| 8 | @ApiStatus.NonExtendable | ||
| 3 | public interface LocalVariableEntryView extends EntryView { | 9 | public interface LocalVariableEntryView extends EntryView { |
| 4 | int getIndex(); | 10 | int getIndex(); |
| 5 | 11 | ||
| 6 | boolean isArgument(); | 12 | boolean isArgument(); |
| 7 | 13 | ||
| 8 | MethodEntryView getParent(); | 14 | MethodEntryView getParent(); |
| 15 | |||
| 16 | static LocalVariableEntryView create(MethodEntryView parent, int index, String name, boolean argument) { | ||
| 17 | return new LocalVariableEntry((MethodEntry) parent, index, name, argument, null); | ||
| 18 | } | ||
| 9 | } | 19 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/entry/MethodEntryView.java b/enigma/src/main/java/cuchaz/enigma/api/view/entry/MethodEntryView.java index 7d7fcd2..3020afa 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/entry/MethodEntryView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/entry/MethodEntryView.java | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | package cuchaz.enigma.api.view.entry; | 1 | package cuchaz.enigma.api.view.entry; |
| 2 | 2 | ||
| 3 | import org.jetbrains.annotations.ApiStatus; | ||
| 4 | |||
| 3 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 5 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 4 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 6 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 5 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 7 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 6 | 8 | ||
| 9 | @ApiStatus.NonExtendable | ||
| 7 | public interface MethodEntryView extends EntryView { | 10 | public interface MethodEntryView extends EntryView { |
| 8 | String getDescriptor(); | 11 | String getDescriptor(); |
| 9 | 12 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/index/BridgeMethodIndexView.java b/enigma/src/main/java/cuchaz/enigma/api/view/index/BridgeMethodIndexView.java new file mode 100644 index 0000000..c07be88 --- /dev/null +++ b/enigma/src/main/java/cuchaz/enigma/api/view/index/BridgeMethodIndexView.java | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | package cuchaz.enigma.api.view.index; | ||
| 2 | |||
| 3 | import org.jetbrains.annotations.ApiStatus; | ||
| 4 | import org.jetbrains.annotations.Nullable; | ||
| 5 | |||
| 6 | import cuchaz.enigma.api.view.entry.MethodEntryView; | ||
| 7 | |||
| 8 | @ApiStatus.NonExtendable | ||
| 9 | public interface BridgeMethodIndexView { | ||
| 10 | @Nullable | ||
| 11 | MethodEntryView getBridgeFromSpecialized(MethodEntryView specialized); | ||
| 12 | |||
| 13 | @Nullable | ||
| 14 | MethodEntryView getSpecializedFromBridge(MethodEntryView bridge); | ||
| 15 | } | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/index/EntryIndexView.java b/enigma/src/main/java/cuchaz/enigma/api/view/index/EntryIndexView.java index 56bf70e..9b4fbaf 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/index/EntryIndexView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/index/EntryIndexView.java | |||
| @@ -2,10 +2,13 @@ package cuchaz.enigma.api.view.index; | |||
| 2 | 2 | ||
| 3 | import java.util.Collection; | 3 | import java.util.Collection; |
| 4 | 4 | ||
| 5 | import org.jetbrains.annotations.ApiStatus; | ||
| 6 | |||
| 5 | import cuchaz.enigma.api.view.entry.ClassDefEntryView; | 7 | import cuchaz.enigma.api.view.entry.ClassDefEntryView; |
| 6 | import cuchaz.enigma.api.view.entry.ClassEntryView; | 8 | import cuchaz.enigma.api.view.entry.ClassEntryView; |
| 7 | import cuchaz.enigma.api.view.entry.EntryView; | 9 | import cuchaz.enigma.api.view.entry.EntryView; |
| 8 | 10 | ||
| 11 | @ApiStatus.NonExtendable | ||
| 9 | public interface EntryIndexView { | 12 | public interface EntryIndexView { |
| 10 | boolean hasEntry(EntryView entry); | 13 | boolean hasEntry(EntryView entry); |
| 11 | int getAccess(EntryView entry); | 14 | int getAccess(EntryView entry); |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/index/InheritanceIndexView.java b/enigma/src/main/java/cuchaz/enigma/api/view/index/InheritanceIndexView.java index a016d11..a156155 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/index/InheritanceIndexView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/index/InheritanceIndexView.java | |||
| @@ -2,8 +2,11 @@ package cuchaz.enigma.api.view.index; | |||
| 2 | 2 | ||
| 3 | import java.util.Collection; | 3 | import java.util.Collection; |
| 4 | 4 | ||
| 5 | import org.jetbrains.annotations.ApiStatus; | ||
| 6 | |||
| 5 | import cuchaz.enigma.api.view.entry.ClassEntryView; | 7 | import cuchaz.enigma.api.view.entry.ClassEntryView; |
| 6 | 8 | ||
| 9 | @ApiStatus.NonExtendable | ||
| 7 | public interface InheritanceIndexView { | 10 | public interface InheritanceIndexView { |
| 8 | Collection<? extends ClassEntryView> getParents(ClassEntryView entry); | 11 | Collection<? extends ClassEntryView> getParents(ClassEntryView entry); |
| 9 | Collection<? extends ClassEntryView> getChildren(ClassEntryView entry); | 12 | Collection<? extends ClassEntryView> getChildren(ClassEntryView entry); |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/index/JarIndexView.java b/enigma/src/main/java/cuchaz/enigma/api/view/index/JarIndexView.java index 069b115..b723267 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/index/JarIndexView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/index/JarIndexView.java | |||
| @@ -1,7 +1,11 @@ | |||
| 1 | package cuchaz.enigma.api.view.index; | 1 | package cuchaz.enigma.api.view.index; |
| 2 | 2 | ||
| 3 | import org.jetbrains.annotations.ApiStatus; | ||
| 4 | |||
| 5 | @ApiStatus.NonExtendable | ||
| 3 | public interface JarIndexView { | 6 | public interface JarIndexView { |
| 4 | EntryIndexView getEntryIndex(); | 7 | EntryIndexView getEntryIndex(); |
| 5 | InheritanceIndexView getInheritanceIndex(); | 8 | InheritanceIndexView getInheritanceIndex(); |
| 6 | ReferenceIndexView getReferenceIndex(); | 9 | ReferenceIndexView getReferenceIndex(); |
| 10 | BridgeMethodIndexView getBridgeMethodIndex(); | ||
| 7 | } | 11 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/view/index/ReferenceIndexView.java b/enigma/src/main/java/cuchaz/enigma/api/view/index/ReferenceIndexView.java index 00ab84e..7c0653f 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/view/index/ReferenceIndexView.java +++ b/enigma/src/main/java/cuchaz/enigma/api/view/index/ReferenceIndexView.java | |||
| @@ -2,11 +2,14 @@ package cuchaz.enigma.api.view.index; | |||
| 2 | 2 | ||
| 3 | import java.util.Collection; | 3 | import java.util.Collection; |
| 4 | 4 | ||
| 5 | import org.jetbrains.annotations.ApiStatus; | ||
| 6 | |||
| 5 | import cuchaz.enigma.api.view.entry.ClassEntryView; | 7 | import cuchaz.enigma.api.view.entry.ClassEntryView; |
| 6 | import cuchaz.enigma.api.view.entry.EntryReferenceView; | 8 | import cuchaz.enigma.api.view.entry.EntryReferenceView; |
| 7 | import cuchaz.enigma.api.view.entry.FieldEntryView; | 9 | import cuchaz.enigma.api.view.entry.FieldEntryView; |
| 8 | import cuchaz.enigma.api.view.entry.MethodEntryView; | 10 | import cuchaz.enigma.api.view.entry.MethodEntryView; |
| 9 | 11 | ||
| 12 | @ApiStatus.NonExtendable | ||
| 10 | public interface ReferenceIndexView { | 13 | public interface ReferenceIndexView { |
| 11 | Collection<? extends MethodEntryView> getMethodsReferencedBy(MethodEntryView entry); | 14 | Collection<? extends MethodEntryView> getMethodsReferencedBy(MethodEntryView entry); |
| 12 | Collection<? extends EntryReferenceView> getReferencesToClass(ClassEntryView entry); | 15 | Collection<? extends EntryReferenceView> getReferencesToClass(ClassEntryView entry); |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java b/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java index fec20e2..51636e3 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java +++ b/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java | |||
| @@ -7,6 +7,8 @@ import java.util.List; | |||
| 7 | import java.util.Map; | 7 | import java.util.Map; |
| 8 | import java.util.TreeMap; | 8 | import java.util.TreeMap; |
| 9 | 9 | ||
| 10 | import org.jetbrains.annotations.Nullable; | ||
| 11 | |||
| 10 | import cuchaz.enigma.analysis.EntryReference; | 12 | import cuchaz.enigma.analysis.EntryReference; |
| 11 | import cuchaz.enigma.translation.mapping.EntryResolver; | 13 | import cuchaz.enigma.translation.mapping.EntryResolver; |
| 12 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; | 14 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; |
| @@ -17,11 +19,13 @@ public class SourceIndex { | |||
| 17 | private List<Integer> lineOffsets; | 19 | private List<Integer> lineOffsets; |
| 18 | private final TreeMap<Token, EntryReference<Entry<?>, Entry<?>>> tokenToReference; | 20 | private final TreeMap<Token, EntryReference<Entry<?>, Entry<?>>> tokenToReference; |
| 19 | private final Map<EntryReference<Entry<?>, Entry<?>>, Collection<Token>> referenceToTokens; | 21 | private final Map<EntryReference<Entry<?>, Entry<?>>, Collection<Token>> referenceToTokens; |
| 22 | private final TreeMap<Token, Entry<?>> tokenToDeclaration; | ||
| 20 | private final Map<Entry<?>, Token> declarationToToken; | 23 | private final Map<Entry<?>, Token> declarationToToken; |
| 21 | 24 | ||
| 22 | public SourceIndex() { | 25 | public SourceIndex() { |
| 23 | tokenToReference = new TreeMap<>(); | 26 | tokenToReference = new TreeMap<>(); |
| 24 | referenceToTokens = new HashMap<>(); | 27 | referenceToTokens = new HashMap<>(); |
| 28 | tokenToDeclaration = new TreeMap<>(); | ||
| 25 | declarationToToken = new HashMap<>(); | 29 | declarationToToken = new HashMap<>(); |
| 26 | } | 30 | } |
| 27 | 31 | ||
| @@ -80,6 +84,11 @@ public class SourceIndex { | |||
| 80 | return declarationToToken.get(entry); | 84 | return declarationToToken.get(entry); |
| 81 | } | 85 | } |
| 82 | 86 | ||
| 87 | @Nullable | ||
| 88 | public Entry<?> getDeclaration(Token token) { | ||
| 89 | return tokenToDeclaration.get(token); | ||
| 90 | } | ||
| 91 | |||
| 83 | public void addDeclaration(Token token, Entry<?> deobfEntry) { | 92 | public void addDeclaration(Token token, Entry<?> deobfEntry) { |
| 84 | if (token != null) { | 93 | if (token != null) { |
| 85 | EntryReference<Entry<?>, Entry<?>> reference = new EntryReference<>(deobfEntry, token.text); | 94 | EntryReference<Entry<?>, Entry<?>> reference = new EntryReference<>(deobfEntry, token.text); |
| @@ -88,6 +97,7 @@ public class SourceIndex { | |||
| 88 | .add(token); | 97 | .add(token); |
| 89 | referenceToTokens.computeIfAbsent(EntryReference.declaration(deobfEntry, token.text), key -> new ArrayList<>()) | 98 | referenceToTokens.computeIfAbsent(EntryReference.declaration(deobfEntry, token.text), key -> new ArrayList<>()) |
| 90 | .add(token); | 99 | .add(token); |
| 100 | tokenToDeclaration.put(token, deobfEntry); | ||
| 91 | declarationToToken.put(deobfEntry, token); | 101 | declarationToToken.put(deobfEntry, token); |
| 92 | } | 102 | } |
| 93 | } | 103 | } |
| @@ -108,6 +118,7 @@ public class SourceIndex { | |||
| 108 | return tokenToReference.keySet(); | 118 | return tokenToReference.keySet(); |
| 109 | } | 119 | } |
| 110 | 120 | ||
| 121 | @Nullable | ||
| 111 | public Token getReferenceToken(int pos) { | 122 | public Token getReferenceToken(int pos) { |
| 112 | Token token = tokenToReference.floorKey(new Token(pos, pos, null)); | 123 | Token token = tokenToReference.floorKey(new Token(pos, pos, null)); |
| 113 | 124 | ||
| @@ -153,7 +164,9 @@ public class SourceIndex { | |||
| 153 | SourceIndex remapped = new SourceIndex(result.getSource()); | 164 | SourceIndex remapped = new SourceIndex(result.getSource()); |
| 154 | 165 | ||
| 155 | for (Map.Entry<Entry<?>, Token> entry : declarationToToken.entrySet()) { | 166 | for (Map.Entry<Entry<?>, Token> entry : declarationToToken.entrySet()) { |
| 156 | remapped.declarationToToken.put(entry.getKey(), result.getRemappedToken(entry.getValue())); | 167 | Token remappedToken = result.getRemappedToken(entry.getValue()); |
| 168 | remapped.declarationToToken.put(entry.getKey(), remappedToken); | ||
| 169 | remapped.tokenToDeclaration.put(remappedToken, entry.getKey()); | ||
| 157 | } | 170 | } |
| 158 | 171 | ||
| 159 | for (Map.Entry<EntryReference<Entry<?>, Entry<?>>, Collection<Token>> entry : referenceToTokens.entrySet()) { | 172 | for (Map.Entry<EntryReference<Entry<?>, Entry<?>>, Collection<Token>> entry : referenceToTokens.entrySet()) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/IconLoadingService.java b/enigma/src/main/java/cuchaz/enigma/utils/IconLoadingService.java new file mode 100644 index 0000000..0e66fba --- /dev/null +++ b/enigma/src/main/java/cuchaz/enigma/utils/IconLoadingService.java | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | package cuchaz.enigma.utils; | ||
| 2 | |||
| 3 | import java.io.IOException; | ||
| 4 | import java.io.InputStream; | ||
| 5 | import java.util.ServiceLoader; | ||
| 6 | |||
| 7 | import cuchaz.enigma.api.EnigmaIcon; | ||
| 8 | |||
| 9 | public interface IconLoadingService { | ||
| 10 | IconLoadingService INSTANCE = ServiceLoader.load(IconLoadingService.class).findFirst() | ||
| 11 | .orElseThrow(() -> new IllegalStateException("Trying to load icon on headless Enigma")); | ||
| 12 | |||
| 13 | EnigmaIcon loadIcon(InputStream in) throws IOException; | ||
| 14 | } | ||