summaryrefslogtreecommitdiff
path: root/enigma
diff options
context:
space:
mode:
authorGravatar 2xsaiko2020-07-21 15:18:12 +0200
committerGravatar GitHub2020-07-21 15:18:12 +0200
commite43c7a80ea1cc6c8a264bee6f521e38f71da4dfc (patch)
treeca2a38ba6e60bf29c2dd0c2d9a305778b0241231 /enigma
parentBump version (diff)
downloadenigma-fork-e43c7a80ea1cc6c8a264bee6f521e38f71da4dfc.tar.gz
enigma-fork-e43c7a80ea1cc6c8a264bee6f521e38f71da4dfc.tar.xz
enigma-fork-e43c7a80ea1cc6c8a264bee6f521e38f71da4dfc.zip
Fix losing current cursor position when renaming entries (#297)
* Fix losing current cursor position when renaming entries * Set nextReference to null after applying it * Extract token map into wrapper type
Diffstat (limited to 'enigma')
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java7
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java41
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/Token.java7
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/TokenStore.java71
4 files changed, 102 insertions, 24 deletions
diff --git a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java
index bc38e61..2272207 100644
--- a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java
@@ -11,10 +11,9 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
11 11
12import javax.annotation.Nullable; 12import javax.annotation.Nullable;
13 13
14import cuchaz.enigma.EnigmaProject;
14import cuchaz.enigma.classprovider.CachingClassProvider; 15import cuchaz.enigma.classprovider.CachingClassProvider;
15import cuchaz.enigma.classprovider.ObfuscationFixClassProvider; 16import cuchaz.enigma.classprovider.ObfuscationFixClassProvider;
16
17import cuchaz.enigma.EnigmaProject;
18import cuchaz.enigma.events.ClassHandleListener; 17import cuchaz.enigma.events.ClassHandleListener;
19import cuchaz.enigma.events.ClassHandleListener.InvalidationType; 18import cuchaz.enigma.events.ClassHandleListener.InvalidationType;
20import cuchaz.enigma.source.*; 19import cuchaz.enigma.source.*;
@@ -277,8 +276,8 @@ public final class ClassHandleProvider {
277 if (res == null || mappedVersion.get() != v) return; 276 if (res == null || mappedVersion.get() != v) return;
278 res = res.andThen(source -> { 277 res = res.andThen(source -> {
279 try { 278 try {
280 source.remapSource(p.project, p.project.getMapper().getDeobfuscator()); 279 DecompiledClassSource remappedSource = source.remapSource(p.project, p.project.getMapper().getDeobfuscator());
281 return Result.ok(source); 280 return Result.ok(remappedSource);
282 } catch (Throwable e) { 281 } catch (Throwable e) {
283 return Result.err(ClassHandleError.remap(e)); 282 return Result.err(ClassHandleError.remap(e));
284 } 283 }
diff --git a/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java b/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java
index e4a7115..9ac611f 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java
@@ -22,30 +22,35 @@ public class DecompiledClassSource {
22 private final ClassEntry classEntry; 22 private final ClassEntry classEntry;
23 23
24 private final SourceIndex obfuscatedIndex; 24 private final SourceIndex obfuscatedIndex;
25 private SourceIndex remappedIndex; 25 private final SourceIndex remappedIndex;
26 26
27 private final Map<RenamableTokenType, Collection<Token>> highlightedTokens = new EnumMap<>(RenamableTokenType.class); 27 private final TokenStore highlightedTokens;
28 28
29 public DecompiledClassSource(ClassEntry classEntry, SourceIndex index) { 29 private DecompiledClassSource(ClassEntry classEntry, SourceIndex obfuscatedIndex, SourceIndex remappedIndex, TokenStore highlightedTokens) {
30 this.classEntry = classEntry; 30 this.classEntry = classEntry;
31 this.obfuscatedIndex = index; 31 this.obfuscatedIndex = obfuscatedIndex;
32 this.remappedIndex = index; 32 this.remappedIndex = remappedIndex;
33 this.highlightedTokens = highlightedTokens;
34 }
35
36 public DecompiledClassSource(ClassEntry classEntry, SourceIndex index) {
37 this(classEntry, index, index, TokenStore.empty());
33 } 38 }
34 39
35 public static DecompiledClassSource text(ClassEntry classEntry, String text) { 40 public static DecompiledClassSource text(ClassEntry classEntry, String text) {
36 return new DecompiledClassSource(classEntry, new SourceIndex(text)); 41 return new DecompiledClassSource(classEntry, new SourceIndex(text));
37 } 42 }
38 43
39 public void remapSource(EnigmaProject project, Translator translator) { 44 public DecompiledClassSource remapSource(EnigmaProject project, Translator translator) {
40 highlightedTokens.clear();
41
42 SourceRemapper remapper = new SourceRemapper(obfuscatedIndex.getSource(), obfuscatedIndex.referenceTokens()); 45 SourceRemapper remapper = new SourceRemapper(obfuscatedIndex.getSource(), obfuscatedIndex.referenceTokens());
43 46
44 SourceRemapper.Result remapResult = remapper.remap((token, movedToken) -> remapToken(project, token, movedToken, translator)); 47 TokenStore tokenStore = TokenStore.create(this.obfuscatedIndex);
45 remappedIndex = obfuscatedIndex.remapTo(remapResult); 48 SourceRemapper.Result remapResult = remapper.remap((token, movedToken) -> remapToken(tokenStore, project, token, movedToken, translator));
49 SourceIndex remappedIndex = obfuscatedIndex.remapTo(remapResult);
50 return new DecompiledClassSource(this.classEntry, this.obfuscatedIndex, remappedIndex, tokenStore);
46 } 51 }
47 52
48 private String remapToken(EnigmaProject project, Token token, Token movedToken, Translator translator) { 53 private String remapToken(TokenStore target, EnigmaProject project, Token token, Token movedToken, Translator translator) {
49 EntryReference<Entry<?>, Entry<?>> reference = obfuscatedIndex.getReference(token); 54 EntryReference<Entry<?>, Entry<?>> reference = obfuscatedIndex.getReference(token);
50 55
51 Entry<?> entry = reference.getNameableEntry(); 56 Entry<?> entry = reference.getNameableEntry();
@@ -53,16 +58,16 @@ public class DecompiledClassSource {
53 58
54 if (project.isRenamable(reference)) { 59 if (project.isRenamable(reference)) {
55 if (!translatedEntry.isObfuscated()) { 60 if (!translatedEntry.isObfuscated()) {
56 highlightToken(movedToken, translatedEntry.getType()); 61 target.add(translatedEntry.getType(), movedToken);
57 return translatedEntry.getValue().getSourceRemapName(); 62 return translatedEntry.getValue().getSourceRemapName();
58 } else { 63 } else {
59 Optional<String> proposedName = proposeName(project, entry); 64 Optional<String> proposedName = proposeName(project, entry);
60 if (proposedName.isPresent()) { 65 if (proposedName.isPresent()) {
61 highlightToken(movedToken, RenamableTokenType.PROPOSED); 66 target.add(RenamableTokenType.PROPOSED, movedToken);
62 return proposedName.get(); 67 return proposedName.get();
63 } 68 }
64 69
65 highlightToken(movedToken, RenamableTokenType.OBFUSCATED); 70 target.add(RenamableTokenType.OBFUSCATED, movedToken);
66 } 71 }
67 } 72 }
68 73
@@ -113,12 +118,12 @@ public class DecompiledClassSource {
113 return remappedIndex; 118 return remappedIndex;
114 } 119 }
115 120
116 public Map<RenamableTokenType, Collection<Token>> getHighlightedTokens() { 121 public TokenStore getTokenStore() {
117 return highlightedTokens; 122 return this.highlightedTokens;
118 } 123 }
119 124
120 private void highlightToken(Token token, RenamableTokenType highlightType) { 125 public Map<RenamableTokenType, ? extends Collection<Token>> getHighlightedTokens() {
121 highlightedTokens.computeIfAbsent(highlightType, t -> new ArrayList<>()).add(token); 126 return this.highlightedTokens.getByType();
122 } 127 }
123 128
124 public int getObfuscatedOffset(int deobfOffset) { 129 public int getObfuscatedOffset(int deobfOffset) {
diff --git a/enigma/src/main/java/cuchaz/enigma/source/Token.java b/enigma/src/main/java/cuchaz/enigma/source/Token.java
index fad733f..7d729ab 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/Token.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/Token.java
@@ -23,9 +23,12 @@ public class Token implements Comparable<Token> {
23 this.text = text; 23 this.text = text;
24 } 24 }
25 25
26 public int length() {
27 return this.end - this.start;
28 }
29
26 public int getRenameOffset(String to) { 30 public int getRenameOffset(String to) {
27 int length = this.end - this.start; 31 return to.length() - this.length();
28 return to.length() - length;
29 } 32 }
30 33
31 public void rename(StringBuffer source, String to) { 34 public void rename(StringBuffer source, String to) {
diff --git a/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java b/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java
new file mode 100644
index 0000000..f32d918
--- /dev/null
+++ b/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java
@@ -0,0 +1,71 @@
1package cuchaz.enigma.source;
2
3import java.util.*;
4
5public final class TokenStore {
6
7 private static final TokenStore EMPTY = new TokenStore(Collections.emptyNavigableSet(), Collections.emptyMap(), null);
8
9 private final NavigableSet<Token> tokens;
10 private final Map<RenamableTokenType, NavigableSet<Token>> byType;
11 private final String obfSource;
12
13 private TokenStore(NavigableSet<Token> tokens, Map<RenamableTokenType, NavigableSet<Token>> byType, String obfSource) {
14 this.tokens = tokens;
15 this.byType = byType;
16 this.obfSource = obfSource;
17 }
18
19 public static TokenStore create(SourceIndex obfuscatedIndex) {
20 EnumMap<RenamableTokenType, NavigableSet<Token>> map = new EnumMap<>(RenamableTokenType.class);
21 for (RenamableTokenType value : RenamableTokenType.values()) {
22 map.put(value, new TreeSet<>(Comparator.comparing(t -> t.start)));
23 }
24 return new TokenStore(new TreeSet<>(Comparator.comparing(t -> t.start)), Collections.unmodifiableMap(map), obfuscatedIndex.getSource());
25 }
26
27 public static TokenStore empty() {
28 return TokenStore.EMPTY;
29 }
30
31 public void add(RenamableTokenType type, Token token) {
32 this.tokens.add(token);
33 this.byType.get(type).add(token);
34 }
35
36 public boolean isCompatible(TokenStore other) {
37 return this.obfSource != null && other.obfSource != null &&
38 this.obfSource.equals(other.obfSource) &&
39 this.tokens.size() == other.tokens.size();
40 }
41
42 public int mapPosition(TokenStore to, int position) {
43 if (!this.isCompatible(to)) return 0;
44
45 int newPos = position;
46 Iterator<Token> thisIter = this.tokens.iterator();
47 Iterator<Token> toIter = to.tokens.iterator();
48 while (thisIter.hasNext()) {
49 Token token = thisIter.next();
50 Token newToken = toIter.next();
51
52 if (position < token.start) break;
53
54 // if we're inside the token and the text changed,
55 // snap the cursor to the beginning
56 if (!token.text.equals(newToken.text) && position < token.end) {
57 newPos = newToken.start;
58 break;
59 }
60
61 newPos += newToken.length() - token.length();
62 }
63
64 return newPos;
65 }
66
67 public Map<RenamableTokenType, NavigableSet<Token>> getByType() {
68 return byType;
69 }
70
71}