-
Notifications
You must be signed in to change notification settings - Fork 89
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a programmatic way of getting all options, including plugin options
- Loading branch information
Showing
5 changed files
with
291 additions
and
158 deletions.
There are no files selected for viewing
9 changes: 5 additions & 4 deletions
9
plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinOptions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 5 additions & 5 deletions
10
...iable-renaming/src/main/java/org/vineflower/variablerenaming/VariableRenamingOptions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
184 changes: 184 additions & 0 deletions
184
src/org/jetbrains/java/decompiler/api/DecompilerOption.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
package org.jetbrains.java.decompiler.api; | ||
|
||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
import org.jetbrains.java.decompiler.api.plugin.Plugin; | ||
import org.jetbrains.java.decompiler.api.plugin.PluginOptions; | ||
import org.jetbrains.java.decompiler.main.Fernflower; | ||
import org.jetbrains.java.decompiler.main.decompiler.BaseDecompiler; | ||
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; | ||
import org.jetbrains.java.decompiler.main.plugins.PluginContext; | ||
|
||
import java.lang.reflect.Field; | ||
import java.util.*; | ||
|
||
/** | ||
* Represents a decompiler option. These can be passed from command line or as | ||
* a map into a {@link BaseDecompiler} or {@link Fernflower} constructor. | ||
* <p> | ||
* As plugins might not provide all information, some fields are nullable. | ||
* | ||
* @param id The unique identifier of the option. This is what is passed to the decompiler. | ||
* @param name A human-readable name for the option. | ||
* @param description A human-readable description of the option. | ||
* @param type The type of the option. | ||
* @param plugin The plugin that provides this option. If {@code null}, it comes from the core decompiler. | ||
* @param defaultValue The default value of the option. | ||
*/ | ||
public record DecompilerOption( | ||
@NotNull String id, | ||
@NotNull String name, | ||
@NotNull String description, | ||
@NotNull Type type, | ||
@Nullable String plugin, | ||
@Nullable String defaultValue | ||
) implements Comparable<DecompilerOption> { | ||
public enum Type { | ||
BOOLEAN("bool"), | ||
STRING("string"), | ||
INTEGER("int"), | ||
|
||
; | ||
|
||
private final String friendlyName; | ||
|
||
Type(String friendlyName) { | ||
this.friendlyName = friendlyName; | ||
} | ||
|
||
public String toString() { | ||
return friendlyName; | ||
} | ||
} | ||
|
||
/** | ||
* Compares this option to another option. The order is set first by the plugin, then by the id. | ||
* Core decompiler options come first. | ||
*/ | ||
@Override | ||
public int compareTo(@NotNull DecompilerOption decompilerOption) { | ||
if (!Objects.equals(decompilerOption.plugin, plugin)) { | ||
if (plugin == null) { | ||
return -1; | ||
} | ||
if (decompilerOption.plugin == null) { | ||
return 1; | ||
} | ||
return plugin.compareTo(decompilerOption.plugin); | ||
} | ||
return id.compareTo(decompilerOption.id); | ||
} | ||
|
||
public static List<DecompilerOption> getAll() { | ||
List<DecompilerOption> options = new ArrayList<>(); | ||
|
||
List<Field> fields = Arrays.stream(IFernflowerPreferences.class.getDeclaredFields()) | ||
.filter(field -> field.getType() == String.class) | ||
.toList(); | ||
|
||
Map<String, Object> defaults = IFernflowerPreferences.DEFAULTS; | ||
addOptions(fields, options, defaults, null); | ||
|
||
PluginContext ctx = new PluginContext(); | ||
ctx.findPlugins(); | ||
|
||
for (Plugin plugin : ctx.getPlugins()) { | ||
PluginOptions opt = plugin.getPluginOptions(); | ||
|
||
if (opt != null) { | ||
var opts = opt.provideOptions(); | ||
|
||
List<Field> pluginFields = Arrays.stream(opts.a.getDeclaredFields()) | ||
.filter(field -> field.getType() == String.class) | ||
.toList(); | ||
|
||
Map<String, Object> pluginDefaults = new HashMap<>(); | ||
opts.b.accept(pluginDefaults::put); | ||
|
||
addOptions(pluginFields, options, pluginDefaults, plugin); | ||
} | ||
} | ||
|
||
options.sort(DecompilerOption::compareTo); | ||
|
||
return options; | ||
} | ||
|
||
public static Map<Plugin, List<DecompilerOption>> getAllByPlugin() { | ||
Map<Plugin, List<DecompilerOption>> options = new HashMap<>(); | ||
|
||
List<Field> fields = Arrays.stream(IFernflowerPreferences.class.getDeclaredFields()) | ||
.filter(field -> field.getType() == String.class) | ||
.toList(); | ||
|
||
Map<String, Object> defaults = IFernflowerPreferences.DEFAULTS; | ||
List<DecompilerOption> coreOptions = new ArrayList<>(); | ||
addOptions(fields, coreOptions, defaults, null); | ||
coreOptions.sort(DecompilerOption::compareTo); | ||
options.put(null, coreOptions); | ||
|
||
PluginContext ctx = new PluginContext(); | ||
ctx.findPlugins(); | ||
|
||
for (Plugin plugin : ctx.getPlugins()) { | ||
PluginOptions opt = plugin.getPluginOptions(); | ||
|
||
if (opt != null) { | ||
var opts = opt.provideOptions(); | ||
|
||
List<Field> pluginFields = Arrays.stream(opts.a.getDeclaredFields()) | ||
.filter(field -> field.getType() == String.class) | ||
.toList(); | ||
|
||
Map<String, Object> pluginDefaults = new HashMap<>(); | ||
opts.b.accept(pluginDefaults::put); | ||
|
||
List<DecompilerOption> pluginOptions = new ArrayList<>(); | ||
addOptions(pluginFields, pluginOptions, pluginDefaults, plugin); | ||
|
||
pluginOptions.sort(DecompilerOption::compareTo); | ||
|
||
options.put(plugin, pluginOptions); | ||
} | ||
} | ||
|
||
return options; | ||
} | ||
|
||
private static void addOptions(List<Field> fields, List<DecompilerOption> options, Map<String, Object> defaults, Plugin plugin) { | ||
for (Field field : fields) { | ||
IFernflowerPreferences.Name name = field.getAnnotation(IFernflowerPreferences.Name.class); | ||
IFernflowerPreferences.Description description = field.getAnnotation(IFernflowerPreferences.Description.class); | ||
IFernflowerPreferences.Type type = field.getAnnotation(IFernflowerPreferences.Type.class); | ||
|
||
String paramName; | ||
try { | ||
paramName = (String) field.get(null); | ||
} catch (IllegalAccessException e) { | ||
IFernflowerPreferences.ShortName shortName = field.getAnnotation(IFernflowerPreferences.ShortName.class); | ||
if (shortName == null) { | ||
continue; | ||
} | ||
paramName = shortName.value(); | ||
} | ||
|
||
if (name == null || description == null || type == null) { | ||
continue; | ||
} | ||
|
||
String friendlyName = name.value(); | ||
String friendlyDescription = description.value(); | ||
Type friendlyType = type.value(); | ||
String defaultValue = defaults.containsKey(paramName) ? defaults.get(paramName).toString() : null; | ||
|
||
options.add(new DecompilerOption( | ||
paramName, | ||
friendlyName, | ||
friendlyDescription, | ||
friendlyType, | ||
plugin != null ? plugin.id() : null, | ||
defaultValue | ||
)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.