From 8247fe0546d9f4f3a21fdeccce26339b47dad365 Mon Sep 17 00:00:00 2001 From: ix0rai Date: Mon, 28 Oct 2024 20:30:55 -0500 Subject: [PATCH 1/4] fix a couple possible crashes in package renamer --- .../enigma/gui/util/PackageRenamer.java | 6 +- .../org/quiltmc/enigma/TestPackageRename.java | 116 +++++++++++------- .../test/resources/test_mappings/a/D.mapping | 1 - .../resources/test_mappings/a/b/C.mapping | 1 - .../resources/test_mappings/a/b/c.mapping | 1 + .../resources/test_mappings/a/b/c/A.mapping | 1 - .../resources/test_mappings/a/b/c/B.mapping | 1 - .../resources/test_mappings/a/b/c/a.mapping | 1 + .../resources/test_mappings/a/b/c/b.mapping | 1 + .../test/resources/test_mappings/a/d.mapping | 1 + .../resources/test_mappings/b/c/g.mapping | 1 + .../test/resources/test_mappings/b/f.mapping | 1 + .../test_mappings/{E.mapping => e.mapping} | 2 +- .../org/quiltmc/enigma/input/packages/E.java | 4 + .../quiltmc/enigma/input/packages/a/D.java | 4 + .../quiltmc/enigma/input/packages/a/b/C.java | 4 + .../enigma/input/packages/a/b/c/A.java | 4 + .../enigma/input/packages/a/b/c/B.java | 4 + .../quiltmc/enigma/input/packages/b/F.java | 4 + .../quiltmc/enigma/input/packages/b/c/G.java | 4 + 20 files changed, 110 insertions(+), 52 deletions(-) delete mode 100644 enigma-swing/src/test/resources/test_mappings/a/D.mapping delete mode 100644 enigma-swing/src/test/resources/test_mappings/a/b/C.mapping create mode 100644 enigma-swing/src/test/resources/test_mappings/a/b/c.mapping delete mode 100644 enigma-swing/src/test/resources/test_mappings/a/b/c/A.mapping delete mode 100644 enigma-swing/src/test/resources/test_mappings/a/b/c/B.mapping create mode 100644 enigma-swing/src/test/resources/test_mappings/a/b/c/a.mapping create mode 100644 enigma-swing/src/test/resources/test_mappings/a/b/c/b.mapping create mode 100644 enigma-swing/src/test/resources/test_mappings/a/d.mapping create mode 100644 enigma-swing/src/test/resources/test_mappings/b/c/g.mapping create mode 100644 enigma-swing/src/test/resources/test_mappings/b/f.mapping rename enigma-swing/src/test/resources/test_mappings/{E.mapping => e.mapping} (52%) create mode 100644 enigma/src/test/java/org/quiltmc/enigma/input/packages/E.java create mode 100644 enigma/src/test/java/org/quiltmc/enigma/input/packages/a/D.java create mode 100644 enigma/src/test/java/org/quiltmc/enigma/input/packages/a/b/C.java create mode 100644 enigma/src/test/java/org/quiltmc/enigma/input/packages/a/b/c/A.java create mode 100644 enigma/src/test/java/org/quiltmc/enigma/input/packages/a/b/c/B.java create mode 100644 enigma/src/test/java/org/quiltmc/enigma/input/packages/b/F.java create mode 100644 enigma/src/test/java/org/quiltmc/enigma/input/packages/b/c/G.java diff --git a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/util/PackageRenamer.java b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/util/PackageRenamer.java index d807cdfc6..0e577d754 100644 --- a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/util/PackageRenamer.java +++ b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/util/PackageRenamer.java @@ -181,7 +181,7 @@ public CompletableFuture renamePackage(String path, String input) { private void handleNode(int divergenceIndex, boolean rename, String[] oldPackageNames, String[] newPackageNames, Map renameStack, TreeNode node) { if (node instanceof ClassSelectorClassNode classNode && rename) { String oldName = classNode.getDeobfEntry().getFullName(); - int finalPackageIndex = divergenceIndex - 1; + int finalPackageIndex = divergenceIndex == 0 ? 0 : divergenceIndex - 1; // skips all classes that do not match the exact package being renamed if (this.mode == Mode.MOVE) { @@ -268,9 +268,9 @@ private void handleNode(int divergenceIndex, boolean rename, String[] oldPackage } } - if (packageName.equals(newPackageNames[index])) { + if (newPackageNames.length - 1 >= index && packageName.equals(newPackageNames[index])) { this.handlePackage(index, false, oldPackageNames, newPackageNames, renameStack, packageNode); - } else if (packageName.equals(oldPackageNames[index])) { + } else if (oldPackageNames.length - 1 >= index && packageName.equals(oldPackageNames[index])) { this.handlePackage(index, true, oldPackageNames, newPackageNames, renameStack, packageNode); } } diff --git a/enigma-swing/src/test/java/org/quiltmc/enigma/TestPackageRename.java b/enigma-swing/src/test/java/org/quiltmc/enigma/TestPackageRename.java index 9329f8306..76333f8ab 100644 --- a/enigma-swing/src/test/java/org/quiltmc/enigma/TestPackageRename.java +++ b/enigma-swing/src/test/java/org/quiltmc/enigma/TestPackageRename.java @@ -1,6 +1,7 @@ package org.quiltmc.enigma; import org.quiltmc.enigma.api.EnigmaProfile; +import org.quiltmc.enigma.api.EnigmaProject; import org.quiltmc.enigma.gui.EditableType; import org.quiltmc.enigma.gui.Gui; import org.quiltmc.enigma.gui.docker.AllClassesDocker; @@ -26,83 +27,96 @@ public class TestPackageRename { public static final Path JAR = TestUtil.obfJar("complete"); public static final Path MAPPINGS = Path.of("src/test/resources/test_mappings"); - private static Translator deobfuscator; + private static EnigmaProject project; @Test void testRemoveOnePackage() throws InterruptedException { renamePackage("a/b/c", "a/c", PackageRenamer.Mode.REFACTOR); - assertMapping(TestEntryFactory.newClass("A"), TestEntryFactory.newClass("a/c/A")); - assertMapping(TestEntryFactory.newClass("B"), TestEntryFactory.newClass("a/c/B")); - assertMapping(TestEntryFactory.newClass("C"), TestEntryFactory.newClass("a/c/C")); - assertMapping(TestEntryFactory.newClass("D"), TestEntryFactory.newClass("a/D")); - assertMapping(TestEntryFactory.newClass("E"), TestEntryFactory.newClass("E")); + assertMapping("a","a/c/A"); + assertMapping("b", "a/c/B"); + assertMapping("c", "a/c/C"); + assertMapping("d", "a/D"); + assertMapping("e", "E"); } @Test void testRemoveTwoPackages() throws InterruptedException { renamePackage("a/b/c", "a", PackageRenamer.Mode.REFACTOR); - assertMapping(TestEntryFactory.newClass("A"), TestEntryFactory.newClass("a/A")); - assertMapping(TestEntryFactory.newClass("B"), TestEntryFactory.newClass("a/B")); - assertMapping(TestEntryFactory.newClass("C"), TestEntryFactory.newClass("a/C")); - assertMapping(TestEntryFactory.newClass("D"), TestEntryFactory.newClass("a/D")); - assertMapping(TestEntryFactory.newClass("E"), TestEntryFactory.newClass("E")); + assertMapping("a", "a/A"); + assertMapping("b", "a/B"); + assertMapping("c", "a/C"); + assertMapping("d", "a/D"); + assertMapping("e", "E"); } @Test void testPackageConservation() throws InterruptedException { renamePackage("a/b", "a", PackageRenamer.Mode.REFACTOR); - assertMapping(TestEntryFactory.newClass("A"), TestEntryFactory.newClass("a/c/A")); - assertMapping(TestEntryFactory.newClass("B"), TestEntryFactory.newClass("a/c/B")); - assertMapping(TestEntryFactory.newClass("C"), TestEntryFactory.newClass("a/C")); - assertMapping(TestEntryFactory.newClass("D"), TestEntryFactory.newClass("a/D")); - assertMapping(TestEntryFactory.newClass("E"), TestEntryFactory.newClass("E")); + assertMapping("a", "a/c/A"); + assertMapping("b", "a/c/B"); + assertMapping("c", "a/C"); + assertMapping("d", "a/D"); + assertMapping("e", "E"); } @Test void testAppendOnePackage() throws InterruptedException { renamePackage("a/b/c", "a/b/c/d", PackageRenamer.Mode.REFACTOR); - assertMapping(TestEntryFactory.newClass("A"), TestEntryFactory.newClass("a/b/c/d/A")); - assertMapping(TestEntryFactory.newClass("B"), TestEntryFactory.newClass("a/b/c/d/B")); - assertMapping(TestEntryFactory.newClass("C"), TestEntryFactory.newClass("a/b/C")); - assertMapping(TestEntryFactory.newClass("D"), TestEntryFactory.newClass("a/D")); - assertMapping(TestEntryFactory.newClass("E"), TestEntryFactory.newClass("E")); + assertMapping("a", "a/b/c/d/A"); + assertMapping("b", "a/b/c/d/B"); + assertMapping("c", "a/b/C"); + assertMapping("d", "a/D"); + assertMapping("e", "E"); } @Test void testSimpleRename() throws InterruptedException { renamePackage("a/b/c", "a/b/d", PackageRenamer.Mode.REFACTOR); - assertMapping(TestEntryFactory.newClass("A"), TestEntryFactory.newClass("a/b/d/A")); - assertMapping(TestEntryFactory.newClass("B"), TestEntryFactory.newClass("a/b/d/B")); - assertMapping(TestEntryFactory.newClass("C"), TestEntryFactory.newClass("a/b/C")); - assertMapping(TestEntryFactory.newClass("D"), TestEntryFactory.newClass("a/D")); - assertMapping(TestEntryFactory.newClass("E"), TestEntryFactory.newClass("E")); + assertMapping("a", "a/b/d/A"); + assertMapping("b", "a/b/d/B"); + assertMapping("c", "a/b/C"); + assertMapping("d", "a/D"); + assertMapping("e", "E"); } @Test void testFirstPackageRename() throws InterruptedException { renamePackage("a", "b", PackageRenamer.Mode.REFACTOR); - assertMapping(TestEntryFactory.newClass("A"), TestEntryFactory.newClass("b/b/c/A")); - assertMapping(TestEntryFactory.newClass("B"), TestEntryFactory.newClass("b/b/c/B")); - assertMapping(TestEntryFactory.newClass("C"), TestEntryFactory.newClass("b/b/C")); - assertMapping(TestEntryFactory.newClass("D"), TestEntryFactory.newClass("b/D")); - assertMapping(TestEntryFactory.newClass("E"), TestEntryFactory.newClass("E")); + assertMapping("a", "b/b/c/A"); + assertMapping("b", "b/b/c/B"); + assertMapping("c", "b/b/C"); + assertMapping("d", "b/D"); + assertMapping("e", "E"); } @Test void testPackageMove() throws InterruptedException { renamePackage("a/b/c", "a/c", PackageRenamer.Mode.MOVE); - assertMapping(TestEntryFactory.newClass("A"), TestEntryFactory.newClass("a/c/A")); - assertMapping(TestEntryFactory.newClass("B"), TestEntryFactory.newClass("a/c/B")); - assertMapping(TestEntryFactory.newClass("C"), TestEntryFactory.newClass("a/b/C")); - assertMapping(TestEntryFactory.newClass("D"), TestEntryFactory.newClass("a/D")); - assertMapping(TestEntryFactory.newClass("E"), TestEntryFactory.newClass("E")); + assertMapping("a", "a/c/A"); + assertMapping("b", "a/c/B"); + assertMapping("c", "a/b/C"); + assertMapping("d", "a/D"); + assertMapping("e", "E"); + } + + @Test + void testPackageMerge() throws InterruptedException { + renamePackage("b", "a", PackageRenamer.Mode.REFACTOR); + + assertMapping("a", "a/b/c/A"); + assertMapping("b", "a/b/c/B"); + assertMapping("c", "a/b/C"); + assertMapping("d", "a/D"); + assertMapping("e", "E"); + assertMapping("f", "a/F"); + assertMapping("g", "a/c/G"); } private static void renamePackage(String packageName, String newName, PackageRenamer.Mode mode) throws InterruptedException { @@ -124,21 +138,35 @@ private static ClassSelectorPopupMenu setupMenu() throws InterruptedException { gui.getController().openJar(JAR).thenRun(() -> gui.getController().openMappings(MAPPINGS).thenRun(latch::countDown)); latch.await(); - deobfuscator = gui.getController().getProject().getRemapper().getDeobfuscator(); + project = gui.getController().getProject(); return gui.getDockerManager().getDocker(AllClassesDocker.class).getPopupMenu(); } private static void assertBaseMappings() { - // assert starting mappings - assertMapping(TestEntryFactory.newClass("A"), TestEntryFactory.newClass("a/b/c/A")); - assertMapping(TestEntryFactory.newClass("B"), TestEntryFactory.newClass("a/b/c/B")); - assertMapping(TestEntryFactory.newClass("C"), TestEntryFactory.newClass("a/b/C")); - assertMapping(TestEntryFactory.newClass("D"), TestEntryFactory.newClass("a/D")); - assertMapping(TestEntryFactory.newClass("E"), TestEntryFactory.newClass("E")); + // a + assertMapping("a", "a/b/c/A"); + assertMapping("b", "a/b/c/B"); + assertMapping("c", "a/b/C"); + assertMapping("d", "a/D"); + + // lone + assertMapping("e", "E"); + + // b + assertMapping("f", "b/F"); + assertMapping("g", "b/c/G"); + } + + private static void assertMapping(String obf, String deobf) { + assertMapping(TestEntryFactory.newClass(obf), TestEntryFactory.newClass(deobf)); } private static void assertMapping(Entry obf, Entry deobf) { - TranslateResult> result = deobfuscator.extendedTranslate(obf); + if (!project.getRemapper().getMappings().contains(obf)) { + throw new RuntimeException("no mapping for " + obf.getFullName() + " !"); + } + + TranslateResult> result = project.getRemapper().getDeobfuscator().extendedTranslate(obf); assertThat(result, is(notNullValue())); assertThat(result.getValue(), is(deobf)); diff --git a/enigma-swing/src/test/resources/test_mappings/a/D.mapping b/enigma-swing/src/test/resources/test_mappings/a/D.mapping deleted file mode 100644 index 801850a35..000000000 --- a/enigma-swing/src/test/resources/test_mappings/a/D.mapping +++ /dev/null @@ -1 +0,0 @@ -CLASS D a/D diff --git a/enigma-swing/src/test/resources/test_mappings/a/b/C.mapping b/enigma-swing/src/test/resources/test_mappings/a/b/C.mapping deleted file mode 100644 index 9d5362527..000000000 --- a/enigma-swing/src/test/resources/test_mappings/a/b/C.mapping +++ /dev/null @@ -1 +0,0 @@ -CLASS C a/b/C diff --git a/enigma-swing/src/test/resources/test_mappings/a/b/c.mapping b/enigma-swing/src/test/resources/test_mappings/a/b/c.mapping new file mode 100644 index 000000000..fcc97bb90 --- /dev/null +++ b/enigma-swing/src/test/resources/test_mappings/a/b/c.mapping @@ -0,0 +1 @@ +CLASS c a/b/C diff --git a/enigma-swing/src/test/resources/test_mappings/a/b/c/A.mapping b/enigma-swing/src/test/resources/test_mappings/a/b/c/A.mapping deleted file mode 100644 index f3fd37243..000000000 --- a/enigma-swing/src/test/resources/test_mappings/a/b/c/A.mapping +++ /dev/null @@ -1 +0,0 @@ -CLASS A a/b/c/A diff --git a/enigma-swing/src/test/resources/test_mappings/a/b/c/B.mapping b/enigma-swing/src/test/resources/test_mappings/a/b/c/B.mapping deleted file mode 100644 index 610a7aae7..000000000 --- a/enigma-swing/src/test/resources/test_mappings/a/b/c/B.mapping +++ /dev/null @@ -1 +0,0 @@ -CLASS B a/b/c/B diff --git a/enigma-swing/src/test/resources/test_mappings/a/b/c/a.mapping b/enigma-swing/src/test/resources/test_mappings/a/b/c/a.mapping new file mode 100644 index 000000000..38c16a1d5 --- /dev/null +++ b/enigma-swing/src/test/resources/test_mappings/a/b/c/a.mapping @@ -0,0 +1 @@ +CLASS a a/b/c/A diff --git a/enigma-swing/src/test/resources/test_mappings/a/b/c/b.mapping b/enigma-swing/src/test/resources/test_mappings/a/b/c/b.mapping new file mode 100644 index 000000000..7ea9d2be8 --- /dev/null +++ b/enigma-swing/src/test/resources/test_mappings/a/b/c/b.mapping @@ -0,0 +1 @@ +CLASS b a/b/c/B diff --git a/enigma-swing/src/test/resources/test_mappings/a/d.mapping b/enigma-swing/src/test/resources/test_mappings/a/d.mapping new file mode 100644 index 000000000..8e70907fd --- /dev/null +++ b/enigma-swing/src/test/resources/test_mappings/a/d.mapping @@ -0,0 +1 @@ +CLASS d a/D diff --git a/enigma-swing/src/test/resources/test_mappings/b/c/g.mapping b/enigma-swing/src/test/resources/test_mappings/b/c/g.mapping new file mode 100644 index 000000000..7f3af739f --- /dev/null +++ b/enigma-swing/src/test/resources/test_mappings/b/c/g.mapping @@ -0,0 +1 @@ +CLASS g b/c/G diff --git a/enigma-swing/src/test/resources/test_mappings/b/f.mapping b/enigma-swing/src/test/resources/test_mappings/b/f.mapping new file mode 100644 index 000000000..280011eeb --- /dev/null +++ b/enigma-swing/src/test/resources/test_mappings/b/f.mapping @@ -0,0 +1 @@ +CLASS f b/F diff --git a/enigma-swing/src/test/resources/test_mappings/E.mapping b/enigma-swing/src/test/resources/test_mappings/e.mapping similarity index 52% rename from enigma-swing/src/test/resources/test_mappings/E.mapping rename to enigma-swing/src/test/resources/test_mappings/e.mapping index 268eae355..c17de533a 100644 --- a/enigma-swing/src/test/resources/test_mappings/E.mapping +++ b/enigma-swing/src/test/resources/test_mappings/e.mapping @@ -1,2 +1,2 @@ -CLASS E E +CLASS e E COMMENT a diff --git a/enigma/src/test/java/org/quiltmc/enigma/input/packages/E.java b/enigma/src/test/java/org/quiltmc/enigma/input/packages/E.java new file mode 100644 index 000000000..8da78b8d3 --- /dev/null +++ b/enigma/src/test/java/org/quiltmc/enigma/input/packages/E.java @@ -0,0 +1,4 @@ +package org.quiltmc.enigma.input.packages; + +public class E { +} diff --git a/enigma/src/test/java/org/quiltmc/enigma/input/packages/a/D.java b/enigma/src/test/java/org/quiltmc/enigma/input/packages/a/D.java new file mode 100644 index 000000000..b7883875b --- /dev/null +++ b/enigma/src/test/java/org/quiltmc/enigma/input/packages/a/D.java @@ -0,0 +1,4 @@ +package org.quiltmc.enigma.input.packages.a; + +public class D { +} diff --git a/enigma/src/test/java/org/quiltmc/enigma/input/packages/a/b/C.java b/enigma/src/test/java/org/quiltmc/enigma/input/packages/a/b/C.java new file mode 100644 index 000000000..679b34caf --- /dev/null +++ b/enigma/src/test/java/org/quiltmc/enigma/input/packages/a/b/C.java @@ -0,0 +1,4 @@ +package org.quiltmc.enigma.input.packages.a.b; + +public class C { +} diff --git a/enigma/src/test/java/org/quiltmc/enigma/input/packages/a/b/c/A.java b/enigma/src/test/java/org/quiltmc/enigma/input/packages/a/b/c/A.java new file mode 100644 index 000000000..45be7f683 --- /dev/null +++ b/enigma/src/test/java/org/quiltmc/enigma/input/packages/a/b/c/A.java @@ -0,0 +1,4 @@ +package org.quiltmc.enigma.input.packages.a.b.c; + +public class A { +} diff --git a/enigma/src/test/java/org/quiltmc/enigma/input/packages/a/b/c/B.java b/enigma/src/test/java/org/quiltmc/enigma/input/packages/a/b/c/B.java new file mode 100644 index 000000000..500030c50 --- /dev/null +++ b/enigma/src/test/java/org/quiltmc/enigma/input/packages/a/b/c/B.java @@ -0,0 +1,4 @@ +package org.quiltmc.enigma.input.packages.a.b.c; + +public class B { +} diff --git a/enigma/src/test/java/org/quiltmc/enigma/input/packages/b/F.java b/enigma/src/test/java/org/quiltmc/enigma/input/packages/b/F.java new file mode 100644 index 000000000..965cd28cd --- /dev/null +++ b/enigma/src/test/java/org/quiltmc/enigma/input/packages/b/F.java @@ -0,0 +1,4 @@ +package org.quiltmc.enigma.input.packages.b; + +public class F { +} diff --git a/enigma/src/test/java/org/quiltmc/enigma/input/packages/b/c/G.java b/enigma/src/test/java/org/quiltmc/enigma/input/packages/b/c/G.java new file mode 100644 index 000000000..89399d117 --- /dev/null +++ b/enigma/src/test/java/org/quiltmc/enigma/input/packages/b/c/G.java @@ -0,0 +1,4 @@ +package org.quiltmc.enigma.input.packages.b.c; + +public class G { +} From 6d97c85861389de9857488405752feb9e8597f44 Mon Sep 17 00:00:00 2001 From: ix0rai Date: Mon, 28 Oct 2024 20:35:13 -0500 Subject: [PATCH 2/4] checkstyle --- .../src/test/java/org/quiltmc/enigma/TestPackageRename.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/enigma-swing/src/test/java/org/quiltmc/enigma/TestPackageRename.java b/enigma-swing/src/test/java/org/quiltmc/enigma/TestPackageRename.java index 76333f8ab..ec2aad4ca 100644 --- a/enigma-swing/src/test/java/org/quiltmc/enigma/TestPackageRename.java +++ b/enigma-swing/src/test/java/org/quiltmc/enigma/TestPackageRename.java @@ -8,7 +8,6 @@ import org.quiltmc.enigma.gui.element.ClassSelectorPopupMenu; import org.quiltmc.enigma.gui.util.PackageRenamer; import org.quiltmc.enigma.api.translation.TranslateResult; -import org.quiltmc.enigma.api.translation.Translator; import org.quiltmc.enigma.api.translation.representation.entry.Entry; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIf; @@ -33,7 +32,7 @@ public class TestPackageRename { void testRemoveOnePackage() throws InterruptedException { renamePackage("a/b/c", "a/c", PackageRenamer.Mode.REFACTOR); - assertMapping("a","a/c/A"); + assertMapping("a", "a/c/A"); assertMapping("b", "a/c/B"); assertMapping("c", "a/c/C"); assertMapping("d", "a/D"); From f8bb5c8da5fd834a9259188e0423174cb067b5e2 Mon Sep 17 00:00:00 2001 From: ix0rai Date: Mon, 28 Oct 2024 21:56:34 -0500 Subject: [PATCH 3/4] add a confirmation dialogue for package renaming --- .../gui/element/ClassSelectorPopupMenu.java | 7 +- .../enigma/gui/util/PackageRenamer.java | 172 +++++++++++++----- enigma/src/main/resources/lang/en_us.json | 6 +- enigma/src/main/resources/lang/fr_fr.json | 2 +- 4 files changed, 138 insertions(+), 49 deletions(-) diff --git a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/element/ClassSelectorPopupMenu.java b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/element/ClassSelectorPopupMenu.java index a95a18188..a128b3920 100644 --- a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/element/ClassSelectorPopupMenu.java +++ b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/element/ClassSelectorPopupMenu.java @@ -99,7 +99,12 @@ private void onRenamePackage(PackageRenamer.Mode mode) { } } - String input = JOptionPane.showInputDialog(this.gui.getFrame(), I18n.translate("popup_menu.class_selector.package_rename.title"), pathString.toString()); + String title = switch (mode) { + case MOVE -> I18n.translateFormatted("popup_menu.class_selector.package_rename.move_title", pathString.toString()); + case REFACTOR -> I18n.translateFormatted("popup_menu.class_selector.package_rename.rename_title", pathString.toString()); + }; + + String input = JOptionPane.showInputDialog(this.gui.getFrame(), title, pathString.toString()); if (input != null) { this.createPackageRenamer(mode).renamePackage(pathString.toString(), input); } diff --git a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/util/PackageRenamer.java b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/util/PackageRenamer.java index 0e577d754..fa48ff2d1 100644 --- a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/util/PackageRenamer.java +++ b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/util/PackageRenamer.java @@ -12,7 +12,14 @@ import org.quiltmc.enigma.util.validation.Message; import org.quiltmc.enigma.util.validation.ValidationContext; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; import javax.swing.tree.TreeNode; +import java.awt.BorderLayout; +import java.awt.Dimension; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -143,7 +150,7 @@ public CompletableFuture renamePackage(String path, String input) { String[] oldPackageNames = path.split("/"); String[] newPackageNames = input.split("/"); - Map renameStack = new HashMap<>(); + Map renameStack = new HashMap<>(); return ProgressDialog.runOffThread(this.gui, listener -> { listener.init(1, I18n.translate("popup_menu.class_selector.package_rename.discovering")); @@ -163,10 +170,20 @@ public CompletableFuture renamePackage(String path, String input) { } } + boolean confirmed = false; int i = 0; for (var entry : renameStack.entrySet()) { + if (!confirmed) { + int continueOperation = JOptionPane.showConfirmDialog(this.gui.getFrame(), buildConfirmationPanel(renameStack)); + if (continueOperation != JOptionPane.YES_OPTION) { + return; + } else { + confirmed = true; + } + } + listener.step(i, I18n.translateFormatted("popup_menu.class_selector.package_rename.renaming_class", entry.getKey())); - entry.getValue().run(); + entry.getValue().executeRename(); i++; } @@ -178,7 +195,51 @@ public CompletableFuture renamePackage(String path, String input) { }); } - private void handleNode(int divergenceIndex, boolean rename, String[] oldPackageNames, String[] newPackageNames, Map renameStack, TreeNode node) { + private static JPanel buildConfirmationPanel(Map renameStack) { + JPanel panel = new JPanel(new BorderLayout()); + int truncationThreshold = 50; + + var sampleRenameLines = collectSampleRenames(truncationThreshold, renameStack); + JTextArea text = new JTextArea(multilineify(false, sampleRenameLines)); + text.setEditable(false); + JScrollPane sampleRenames = new JScrollPane(text); + sampleRenames.setPreferredSize(new Dimension(ScaleUtil.scale(400), ScaleUtil.scale(100))); + + String changesString = I18n.translate("popup_menu.class_selector.package_rename.changes_to_apply") + (sampleRenameLines.length == truncationThreshold ? " (" + I18n.translate("popup_menu.class_selector.package_rename.truncated") + ")" : ""); + panel.add(BorderLayout.NORTH, new JLabel(multilineify(true, I18n.translate("popup_menu.class_selector.package_rename.confirm_rename"), changesString))); + panel.add(sampleRenames, BorderLayout.CENTER); + + return panel; + } + + private static String multilineify(boolean html, String... lines) { + StringBuilder builder = new StringBuilder(html ? "" : ""); + + for (int i = 0; i < lines.length; i++) { + builder.append(lines[i]).append(i == lines.length - 1 ? "" : (html ? "
" : "\n")); + } + + return builder.append(html ? "" : "").toString(); + } + + private static String[] collectSampleRenames(int truncationThreshold, Map renameStack) { + int max = Math.min(renameStack.size(), truncationThreshold); + int index = 0; + + String[] builder = new String[max]; + for (Map.Entry entry : renameStack.entrySet()) { + builder[index] = entry.getKey() + " -> " + entry.getValue().getNewName(); + index++; + + if (index >= max) { + return builder; + } + } + + throw new RuntimeException("failed to collect sample renames!"); + } + + private void handleNode(int divergenceIndex, boolean rename, String[] oldPackageNames, String[] newPackageNames, Map renameStack, TreeNode node) { if (node instanceof ClassSelectorClassNode classNode && rename) { String oldName = classNode.getDeobfEntry().getFullName(); int finalPackageIndex = divergenceIndex == 0 ? 0 : divergenceIndex - 1; @@ -190,59 +251,72 @@ private void handleNode(int divergenceIndex, boolean rename, String[] oldPackage } } - renameStack.put(oldName, () -> { - String[] split = oldName.split("/"); - StringBuilder newPackages = new StringBuilder(); - - if (oldPackageNames.length <= newPackageNames.length) { - for (int i = finalPackageIndex; i < newPackageNames.length; i++) { - if (i >= 0) { - if (i < oldPackageNames.length && i < split.length && oldPackageNames[i].equals(split[i])) { - split[i] = newPackageNames[i]; - } else { - newPackages.append("/").append(newPackageNames[i]); + renameStack.put(oldName, new ClassRename() { + private String cachedNewName = null; + + @Override + public void executeRename() { + String newName = this.cachedNewName == null ? this.getNewName() : this.cachedNewName; + + // ignore warnings, we don't want to bother the user with every individual package created + PackageRenamer.this.gui.getController().applyChange(new ValidationContext(PackageRenamer.this.gui.getNotificationManager(), false), EntryChange.modify(classNode.getObfEntry()).withDeobfName(newName), false); + } + + @Override + public String getNewName() { + String[] split = oldName.split("/"); + StringBuilder newPackages = new StringBuilder(); + + if (oldPackageNames.length <= newPackageNames.length) { + for (int i = finalPackageIndex; i < newPackageNames.length; i++) { + if (i >= 0) { + if (i < oldPackageNames.length && i < split.length && oldPackageNames[i].equals(split[i])) { + split[i] = newPackageNames[i]; + } else { + newPackages.append("/").append(newPackageNames[i]); + } } } - } - } else { - for (int i = 0; i < oldPackageNames.length; i++) { - if (i > newPackageNames.length - 1 || !oldPackageNames[i].equals(newPackageNames[i])) { - StringBuilder string = new StringBuilder(); + } else { + for (int i = 0; i < oldPackageNames.length; i++) { + if (i > newPackageNames.length - 1 || !oldPackageNames[i].equals(newPackageNames[i])) { + StringBuilder string = new StringBuilder(); - // append preceding old package names - for (int j = 0; j <= i - 1; j++) { - appendSlash(string); - string.append(oldPackageNames[j]); - } + // append preceding old package names + for (int j = 0; j <= i - 1; j++) { + appendSlash(string); + string.append(oldPackageNames[j]); + } - // append new package names - for (int j = i; j < newPackageNames.length; j++) { - appendSlash(string); - string.append(newPackageNames[j]); - } + // append new package names + for (int j = i; j < newPackageNames.length; j++) { + appendSlash(string); + string.append(newPackageNames[j]); + } + + // append the remaining old package names + for (int j = i - 1 + oldPackageNames.length; j < split.length - 1; j++) { + appendSlash(string); + string.append(split[j]); + } - // append the remaining old package names - for (int j = i - 1 + oldPackageNames.length; j < split.length - 1; j++) { appendSlash(string); - string.append(split[j]); + string.append(classNode.getDeobfEntry().getSimpleName()); + split = string.toString().split("/"); + break; } - - appendSlash(string); - string.append(classNode.getDeobfEntry().getSimpleName()); - split = string.toString().split("/"); - break; } } - } - // append new packages to last package - if (!newPackages.toString().isBlank()) { - split[finalPackageIndex] = split[finalPackageIndex] + newPackages; - } + // append new packages to last package + if (!newPackages.toString().isBlank()) { + split[finalPackageIndex] = split[finalPackageIndex] + newPackages; + } - String newName = String.join("/", split); - // ignore warnings, we don't want to bother the user with every individual package created - this.gui.getController().applyChange(new ValidationContext(this.gui.getNotificationManager(), false), EntryChange.modify(classNode.getObfEntry()).withDeobfName(newName), false); + String newName = String.join("/", split); + this.cachedNewName = newName; + return newName; + } }); } else if (node instanceof ClassSelectorPackageNode packageNode) { String packageName = packageNode.getPackageName().substring(packageNode.getPackageName().lastIndexOf("/") + 1); @@ -282,7 +356,7 @@ private static void appendSlash(StringBuilder string) { } } - private void handlePackage(int divergenceIndex, boolean rename, String[] oldPackageNames, String[] newPackageNames, Map renameStack, TreeNode node) { + private void handlePackage(int divergenceIndex, boolean rename, String[] oldPackageNames, String[] newPackageNames, Map renameStack, TreeNode node) { if (!rename) { divergenceIndex++; } @@ -291,4 +365,10 @@ private void handlePackage(int divergenceIndex, boolean rename, String[] oldPack this.handleNode(divergenceIndex, rename, oldPackageNames, newPackageNames, renameStack, node.getChildAt(j)); } } + + private interface ClassRename { + void executeRename(); + + String getNewName(); + } } diff --git a/enigma/src/main/resources/lang/en_us.json b/enigma/src/main/resources/lang/en_us.json index f92790864..6054f6900 100644 --- a/enigma/src/main/resources/lang/en_us.json +++ b/enigma/src/main/resources/lang/en_us.json @@ -124,10 +124,14 @@ "popup_menu.class_selector.rename_class": "Rename Class", "popup_menu.class_selector.expand_all": "Expand All", "popup_menu.class_selector.collapse_all": "Collapse All", - "popup_menu.class_selector.package_rename.title": "Renaming package...", + "popup_menu.class_selector.package_rename.rename_title": "Renaming package '%s'...", + "popup_menu.class_selector.package_rename.move_title": "Moving package '%s'...", "popup_menu.class_selector.package_rename.discovering": "Discovering classes to rename...", "popup_menu.class_selector.package_rename.renaming_classes": "Renaming classes...", "popup_menu.class_selector.package_rename.renaming_class": "Renaming class: %s", + "popup_menu.class_selector.package_rename.truncated": "truncated", + "popup_menu.class_selector.package_rename.changes_to_apply": "Changes to apply:", + "popup_menu.class_selector.package_rename.confirm_rename": "Confirm rename?", "editor.decompiling": "Decompiling...", "editor.decompile_error": "An error was encountered while decompiling.", diff --git a/enigma/src/main/resources/lang/fr_fr.json b/enigma/src/main/resources/lang/fr_fr.json index b6b35aa40..76ce55cee 100644 --- a/enigma/src/main/resources/lang/fr_fr.json +++ b/enigma/src/main/resources/lang/fr_fr.json @@ -115,7 +115,7 @@ "popup_menu.class_selector.rename_class": "Renommer la classe", "popup_menu.class_selector.expand_all": "Tout développer", "popup_menu.class_selector.collapse_all": "Tout réduire", - "popup_menu.class_selector.package_rename.title": "Renommage du package...", + "popup_menu.class_selector.package_rename.rename_title": "Renommage du package '%s'...", "popup_menu.class_selector.package_rename.discovering": "Découverte des classes à renommer...", "popup_menu.class_selector.package_rename.renaming_classes": "Renommage des classes...", "popup_menu.class_selector.package_rename.renaming_class": "Renommage de la classe : %s", From 94ba4b60ee50404e5cfbf02a9788fb4b1b998f4f Mon Sep 17 00:00:00 2001 From: ix0rai Date: Mon, 28 Oct 2024 22:08:23 -0500 Subject: [PATCH 4/4] fix test --- .../src/main/java/org/quiltmc/enigma/gui/Gui.java | 11 +++++++++-- .../src/main/java/org/quiltmc/enigma/gui/Main.java | 2 +- .../org/quiltmc/enigma/gui/util/PackageRenamer.java | 2 +- .../java/org/quiltmc/enigma/TestPackageRename.java | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/Gui.java b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/Gui.java index 8cd3e755a..9a86ebdc6 100644 --- a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/Gui.java +++ b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/Gui.java @@ -103,7 +103,9 @@ public class Gui { public final JFileChooser exportJarFileChooser; public final SearchDialog searchDialog; - public Gui(EnigmaProfile profile, Set editableTypes, boolean visible) { + private final boolean testEnvironment; + + public Gui(EnigmaProfile profile, Set editableTypes, boolean testEnvironment) { this.dockerManager = new DockerManager(this); this.mainWindow = new MainWindow(this, Enigma.NAME); this.centerPanel = new JPanel(new BorderLayout()); @@ -126,6 +128,7 @@ public Gui(EnigmaProfile profile, Set editableTypes, boolean visib this.connectionStatusLabel = new JLabel(); this.notificationManager = new NotificationManager(this); this.searchDialog = new SearchDialog(this); + this.testEnvironment = testEnvironment; this.showsProgressBars = true; @@ -133,7 +136,7 @@ public Gui(EnigmaProfile profile, Set editableTypes, boolean visib LanguageUtil.addListener(this::retranslateUi); - this.mainWindow.setVisible(visible); + this.mainWindow.setVisible(!testEnvironment); } private void setupDockers() { @@ -273,6 +276,10 @@ public Set getEditableTypes() { return this.editableTypes; } + public boolean isTestEnvironment() { + return this.testEnvironment; + } + public void addCrash(Throwable t) { this.crashHistory.add(t); this.menuBar.prepareCrashHistoryMenu(); diff --git a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/Main.java b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/Main.java index 81209eb6d..dfa47f2b4 100644 --- a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/Main.java +++ b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/Main.java @@ -109,7 +109,7 @@ public static void main(String[] args) throws IOException { KeyBinds.loadConfig(); - Gui gui = new Gui(parsedProfile, editables, true); + Gui gui = new Gui(parsedProfile, editables, false); GuiController controller = gui.getController(); if (options.has("hide-progress-bars")) { diff --git a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/util/PackageRenamer.java b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/util/PackageRenamer.java index fa48ff2d1..1410f4007 100644 --- a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/util/PackageRenamer.java +++ b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/util/PackageRenamer.java @@ -173,7 +173,7 @@ public CompletableFuture renamePackage(String path, String input) { boolean confirmed = false; int i = 0; for (var entry : renameStack.entrySet()) { - if (!confirmed) { + if (!confirmed && !this.gui.isTestEnvironment()) { int continueOperation = JOptionPane.showConfirmDialog(this.gui.getFrame(), buildConfirmationPanel(renameStack)); if (continueOperation != JOptionPane.YES_OPTION) { return; diff --git a/enigma-swing/src/test/java/org/quiltmc/enigma/TestPackageRename.java b/enigma-swing/src/test/java/org/quiltmc/enigma/TestPackageRename.java index ec2aad4ca..f5091221b 100644 --- a/enigma-swing/src/test/java/org/quiltmc/enigma/TestPackageRename.java +++ b/enigma-swing/src/test/java/org/quiltmc/enigma/TestPackageRename.java @@ -130,7 +130,7 @@ private static void renamePackage(String packageName, String newName, PackageRen private static ClassSelectorPopupMenu setupMenu() throws InterruptedException { Set editables = EnumSet.allOf(EditableType.class); editables.addAll(List.of(EditableType.values())); - Gui gui = new Gui(EnigmaProfile.EMPTY, editables, false); + Gui gui = new Gui(EnigmaProfile.EMPTY, editables, true); gui.setShowsProgressBars(false); CountDownLatch latch = new CountDownLatch(1);