From 87581ffe8d23aaf8ad677ffbb9de1ecfec3cfe80 Mon Sep 17 00:00:00 2001 From: Joseph Burton Date: Sat, 18 Oct 2025 16:38:40 +0100 Subject: Annotation editor support (#568) * Add gutter markers * Add more GUI APIs * Use SVG icons for gutter markers * Add a little more padding between the line numbers and the gutter markers * Add API for creating an Enigma JEditorPane * Add API to list all classes including library classes * Add API to create a LocalVariableEntryView * Expose BrdigeMethodIndex to API * Require name to be passed to LocalVariableEntryView * Make implementation of isCursorOnDeclaration more robust * Checkstyle * Replace isCursorOnDeclaration with getCursorDeclaration * Checkstyle again * Refactor EnigmaIcon as per Juuz's suggestions * Add more @NonExtendable and add EnigmaIcon docs--- .../src/main/java/cuchaz/enigma/EnigmaProject.java | 5 +++ .../enigma/analysis/index/BridgeMethodIndex.java | 16 ++++++++- .../cuchaz/enigma/analysis/index/JarIndex.java | 1 + .../cuchaz/enigma/api/DataInvalidationEvent.java | 2 ++ .../main/java/cuchaz/enigma/api/EnigmaIcon.java | 39 ++++++++++++++++++++++ .../java/cuchaz/enigma/api/service/GuiService.java | 18 ++++++++++ .../main/java/cuchaz/enigma/api/view/GuiView.java | 13 ++++++++ .../java/cuchaz/enigma/api/view/ProjectView.java | 4 +++ .../enigma/api/view/entry/ClassDefEntryView.java | 2 ++ .../enigma/api/view/entry/ClassEntryView.java | 3 ++ .../cuchaz/enigma/api/view/entry/DefEntryView.java | 3 ++ .../enigma/api/view/entry/EntryReferenceView.java | 3 ++ .../cuchaz/enigma/api/view/entry/EntryView.java | 2 ++ .../enigma/api/view/entry/FieldEntryView.java | 3 ++ .../api/view/entry/LocalVariableDefEntryView.java | 3 ++ .../api/view/entry/LocalVariableEntryView.java | 10 ++++++ .../enigma/api/view/entry/MethodEntryView.java | 3 ++ .../api/view/index/BridgeMethodIndexView.java | 15 +++++++++ .../enigma/api/view/index/EntryIndexView.java | 3 ++ .../api/view/index/InheritanceIndexView.java | 3 ++ .../cuchaz/enigma/api/view/index/JarIndexView.java | 4 +++ .../enigma/api/view/index/ReferenceIndexView.java | 3 ++ .../java/cuchaz/enigma/source/SourceIndex.java | 15 ++++++++- .../cuchaz/enigma/utils/IconLoadingService.java | 14 ++++++++ 24 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 enigma/src/main/java/cuchaz/enigma/api/EnigmaIcon.java create mode 100644 enigma/src/main/java/cuchaz/enigma/api/view/index/BridgeMethodIndexView.java create mode 100644 enigma/src/main/java/cuchaz/enigma/utils/IconLoadingService.java (limited to 'enigma') 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 @@ -409,6 +409,11 @@ public class EnigmaProject implements ProjectView { return projectClasses; } + @Override + public Collection getProjectAndLibraryClasses() { + return classProvider.getClassNames(); + } + @Override @Nullable public ClassNode getBytecode(String 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; import org.jetbrains.annotations.Nullable; +import cuchaz.enigma.api.view.entry.MethodEntryView; +import cuchaz.enigma.api.view.index.BridgeMethodIndexView; import cuchaz.enigma.translation.representation.AccessFlags; import cuchaz.enigma.translation.representation.MethodDescriptor; import cuchaz.enigma.translation.representation.TypeDescriptor; @@ -17,7 +19,7 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry; import cuchaz.enigma.translation.representation.entry.MethodDefEntry; import cuchaz.enigma.translation.representation.entry.MethodEntry; -public class BridgeMethodIndex implements JarIndexer { +public class BridgeMethodIndex implements JarIndexer, BridgeMethodIndexView { private final EntryIndex entryIndex; private final InheritanceIndex inheritanceIndex; private final ReferenceIndex referenceIndex; @@ -154,6 +156,18 @@ public class BridgeMethodIndex implements JarIndexer { return bridgeToSpecialized.get(bridge); } + @Override + @Nullable + public MethodEntryView getBridgeFromSpecialized(MethodEntryView specialized) { + return getBridgeFromSpecialized((MethodEntry) specialized); + } + + @Override + @Nullable + public MethodEntryView getSpecializedFromBridge(MethodEntryView bridge) { + return getSpecializedFromBridge((MethodEntry) bridge); + } + /** Includes "renamed specialized -> bridge" entries. */ public Map getSpecializedToBridge() { 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 { return referenceIndex; } + @Override public BridgeMethodIndex getBridgeMethodIndex() { return bridgeMethodIndex; } 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; import java.util.Collection; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; +@ApiStatus.NonExtendable public interface DataInvalidationEvent { /** * 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 @@ +package cuchaz.enigma.api; + +import java.io.IOException; +import java.io.InputStream; + +import org.jetbrains.annotations.ApiStatus; + +import cuchaz.enigma.utils.IconLoadingService; + +@ApiStatus.NonExtendable +public interface EnigmaIcon { + /** + * Loads an icon resource from the given SVG resource path. + * + * @param resource the path to the resource to be loaded + * @return The loaded icon + * @throws IOException if the resource could not be found or an error occurred while reading it + */ + static EnigmaIcon loadResource(String resource) throws IOException { + try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource)) { + if (in == null) { + throw new IOException("Could not find resource: " + resource); + } + + return load(in); + } + } + + /** + * Loads an icon in SVG format from the given input stream. + * + * @param in the input stream to load from + * @return The loaded icon + * @throws IOException if the stream throws an error + */ + static EnigmaIcon load(InputStream in) throws IOException { + return IconLoadingService.INSTANCE.loadIcon(in); + } +} 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; import javax.swing.KeyStroke; +import cuchaz.enigma.api.EnigmaIcon; import cuchaz.enigma.api.view.GuiView; +import cuchaz.enigma.api.view.entry.EntryView; public interface GuiService extends EnigmaService { EnigmaServiceType TYPE = EnigmaServiceType.create("gui"); @@ -16,6 +18,9 @@ public interface GuiService extends EnigmaService { default void addToEditorContextMenu(GuiView gui, MenuRegistrar registrar) { } + default void addGutterMarkers(GuiView gui, EntryView entry, GutterMarkerAdder gutter) { + } + interface MenuRegistrar { void addSeparator(); @@ -31,4 +36,17 @@ public interface GuiService extends EnigmaService { MenuItemBuilder setEnabledWhen(BooleanSupplier condition); MenuItemBuilder setAction(Runnable action); } + + interface GutterMarkerAdder { + GutterMarkerBuilder addMarker(EnigmaIcon icon, GutterMarkerAlignment alignment); + } + + interface GutterMarkerBuilder { + GutterMarkerBuilder setClickAction(Runnable action); + GutterMarkerBuilder setTooltip(String tooltip); + } + + enum GutterMarkerAlignment { + LEFT, RIGHT + } } 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 @@ package cuchaz.enigma.api.view; +import javax.swing.JEditorPane; import javax.swing.JFrame; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import cuchaz.enigma.api.view.entry.EntryReferenceView; +import cuchaz.enigma.api.view.entry.EntryView; +@ApiStatus.NonExtendable public interface GuiView { @Nullable ProjectView getProject(); @@ -13,5 +17,14 @@ public interface GuiView { @Nullable EntryReferenceView getCursorReference(); + @Nullable + EntryView getCursorDeclaration(); + JFrame getFrame(); + + float getScale(); + + boolean isDarkTheme(); + + JEditorPane createEditorPane(); } 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; import java.util.Collection; import java.util.List; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.ClassNode; @@ -11,6 +12,7 @@ import cuchaz.enigma.api.DataInvalidationListener; import cuchaz.enigma.api.view.entry.EntryView; import cuchaz.enigma.api.view.index.JarIndexView; +@ApiStatus.NonExtendable public interface ProjectView { T deobfuscate(T entry); @@ -25,6 +27,8 @@ public interface ProjectView { Collection getProjectClasses(); + Collection getProjectAndLibraryClasses(); + @Nullable ClassNode getBytecode(String className); 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 @@ package cuchaz.enigma.api.view.entry; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; +@ApiStatus.NonExtendable public interface ClassDefEntryView extends ClassEntryView, DefEntryView { @Nullable 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 @@ package cuchaz.enigma.api.view.entry; +import org.jetbrains.annotations.ApiStatus; + import cuchaz.enigma.translation.representation.entry.ClassEntry; +@ApiStatus.NonExtendable public interface ClassEntryView extends EntryView { ClassEntryView getParent(); 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 @@ package cuchaz.enigma.api.view.entry; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.NonExtendable public interface DefEntryView { int getAccessFlags(); } 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 @@ package cuchaz.enigma.api.view.entry; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.NonExtendable public interface EntryReferenceView { EntryView getEntry(); } 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 @@ package cuchaz.enigma.api.view.entry; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; +@ApiStatus.NonExtendable public interface EntryView { /** * 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 @@ package cuchaz.enigma.api.view.entry; +import org.jetbrains.annotations.ApiStatus; + import cuchaz.enigma.translation.representation.TypeDescriptor; import cuchaz.enigma.translation.representation.entry.ClassEntry; import cuchaz.enigma.translation.representation.entry.FieldEntry; +@ApiStatus.NonExtendable public interface FieldEntryView extends EntryView { String getDescriptor(); 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 @@ package cuchaz.enigma.api.view.entry; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.NonExtendable public interface LocalVariableDefEntryView extends LocalVariableEntryView { String getDescriptor(); } 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 @@ package cuchaz.enigma.api.view.entry; +import org.jetbrains.annotations.ApiStatus; + +import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; +import cuchaz.enigma.translation.representation.entry.MethodEntry; + +@ApiStatus.NonExtendable public interface LocalVariableEntryView extends EntryView { int getIndex(); boolean isArgument(); MethodEntryView getParent(); + + static LocalVariableEntryView create(MethodEntryView parent, int index, String name, boolean argument) { + return new LocalVariableEntry((MethodEntry) parent, index, name, argument, null); + } } 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 @@ package cuchaz.enigma.api.view.entry; +import org.jetbrains.annotations.ApiStatus; + import cuchaz.enigma.translation.representation.MethodDescriptor; import cuchaz.enigma.translation.representation.entry.ClassEntry; import cuchaz.enigma.translation.representation.entry.MethodEntry; +@ApiStatus.NonExtendable public interface MethodEntryView extends EntryView { String getDescriptor(); 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 @@ +package cuchaz.enigma.api.view.index; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import cuchaz.enigma.api.view.entry.MethodEntryView; + +@ApiStatus.NonExtendable +public interface BridgeMethodIndexView { + @Nullable + MethodEntryView getBridgeFromSpecialized(MethodEntryView specialized); + + @Nullable + MethodEntryView getSpecializedFromBridge(MethodEntryView bridge); +} 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; import java.util.Collection; +import org.jetbrains.annotations.ApiStatus; + import cuchaz.enigma.api.view.entry.ClassDefEntryView; import cuchaz.enigma.api.view.entry.ClassEntryView; import cuchaz.enigma.api.view.entry.EntryView; +@ApiStatus.NonExtendable public interface EntryIndexView { boolean hasEntry(EntryView entry); 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; import java.util.Collection; +import org.jetbrains.annotations.ApiStatus; + import cuchaz.enigma.api.view.entry.ClassEntryView; +@ApiStatus.NonExtendable public interface InheritanceIndexView { Collection getParents(ClassEntryView entry); Collection 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 @@ package cuchaz.enigma.api.view.index; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.NonExtendable public interface JarIndexView { EntryIndexView getEntryIndex(); InheritanceIndexView getInheritanceIndex(); ReferenceIndexView getReferenceIndex(); + BridgeMethodIndexView getBridgeMethodIndex(); } 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; import java.util.Collection; +import org.jetbrains.annotations.ApiStatus; + import cuchaz.enigma.api.view.entry.ClassEntryView; import cuchaz.enigma.api.view.entry.EntryReferenceView; import cuchaz.enigma.api.view.entry.FieldEntryView; import cuchaz.enigma.api.view.entry.MethodEntryView; +@ApiStatus.NonExtendable public interface ReferenceIndexView { Collection getMethodsReferencedBy(MethodEntryView entry); Collection 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; import java.util.Map; import java.util.TreeMap; +import org.jetbrains.annotations.Nullable; + import cuchaz.enigma.analysis.EntryReference; import cuchaz.enigma.translation.mapping.EntryResolver; import cuchaz.enigma.translation.mapping.ResolutionStrategy; @@ -17,11 +19,13 @@ public class SourceIndex { private List lineOffsets; private final TreeMap, Entry>> tokenToReference; private final Map, Entry>, Collection> referenceToTokens; + private final TreeMap> tokenToDeclaration; private final Map, Token> declarationToToken; public SourceIndex() { tokenToReference = new TreeMap<>(); referenceToTokens = new HashMap<>(); + tokenToDeclaration = new TreeMap<>(); declarationToToken = new HashMap<>(); } @@ -80,6 +84,11 @@ public class SourceIndex { return declarationToToken.get(entry); } + @Nullable + public Entry getDeclaration(Token token) { + return tokenToDeclaration.get(token); + } + public void addDeclaration(Token token, Entry deobfEntry) { if (token != null) { EntryReference, Entry> reference = new EntryReference<>(deobfEntry, token.text); @@ -88,6 +97,7 @@ public class SourceIndex { .add(token); referenceToTokens.computeIfAbsent(EntryReference.declaration(deobfEntry, token.text), key -> new ArrayList<>()) .add(token); + tokenToDeclaration.put(token, deobfEntry); declarationToToken.put(deobfEntry, token); } } @@ -108,6 +118,7 @@ public class SourceIndex { return tokenToReference.keySet(); } + @Nullable public Token getReferenceToken(int pos) { Token token = tokenToReference.floorKey(new Token(pos, pos, null)); @@ -153,7 +164,9 @@ public class SourceIndex { SourceIndex remapped = new SourceIndex(result.getSource()); for (Map.Entry, Token> entry : declarationToToken.entrySet()) { - remapped.declarationToToken.put(entry.getKey(), result.getRemappedToken(entry.getValue())); + Token remappedToken = result.getRemappedToken(entry.getValue()); + remapped.declarationToToken.put(entry.getKey(), remappedToken); + remapped.tokenToDeclaration.put(remappedToken, entry.getKey()); } for (Map.Entry, Entry>, Collection> 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 @@ +package cuchaz.enigma.utils; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ServiceLoader; + +import cuchaz.enigma.api.EnigmaIcon; + +public interface IconLoadingService { + IconLoadingService INSTANCE = ServiceLoader.load(IconLoadingService.class).findFirst() + .orElseThrow(() -> new IllegalStateException("Trying to load icon on headless Enigma")); + + EnigmaIcon loadIcon(InputStream in) throws IOException; +} -- cgit v1.2.3