Merge pull request #13277 from abextm/jshell
devtools: add shell window
This commit is contained in:
34
pom.xml
34
pom.xml
@@ -119,6 +119,7 @@
|
||||
<module>cache-updater</module>
|
||||
<module>runelite-api</module>
|
||||
<module>runelite-client</module>
|
||||
<module>runelite-jshell</module>
|
||||
<module>runelite-script-assembler-plugin</module>
|
||||
<module>http-api</module>
|
||||
<module>http-service</module>
|
||||
@@ -142,6 +143,11 @@
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-parent</artifactId>
|
||||
@@ -149,37 +155,25 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice-bom</artifactId>
|
||||
<version>4.1.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>java9</id>
|
||||
<activation>
|
||||
<jdk>[1.9,)</jdk>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<release>${java.release}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
<release>${java.release}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -36,8 +36,6 @@
|
||||
<name>RuneLite Client</name>
|
||||
|
||||
<properties>
|
||||
<guice.version>4.1.0</guice.version>
|
||||
|
||||
<jarsigner.skip>true</jarsigner.skip>
|
||||
<pmd.skip>true</pmd.skip>
|
||||
</properties>
|
||||
@@ -85,7 +83,6 @@
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>${guice.version}</version>
|
||||
<classifier>no_aop</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -215,7 +212,6 @@
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -223,6 +219,12 @@
|
||||
<artifactId>runelite-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.runelite</groupId>
|
||||
<artifactId>jshell</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.runelite</groupId>
|
||||
<artifactId>client-patch</artifactId>
|
||||
@@ -267,13 +269,11 @@
|
||||
<dependency>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
<artifactId>guice-testlib</artifactId>
|
||||
<version>${guice.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
<artifactId>guice-grapher</artifactId>
|
||||
<version>${guice.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -318,7 +318,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
|
||||
@@ -51,26 +51,20 @@ import net.runelite.client.util.ReflectUtil;
|
||||
@ThreadSafe
|
||||
public class EventBus
|
||||
{
|
||||
@FunctionalInterface
|
||||
public interface SubscriberMethod
|
||||
{
|
||||
void invoke(Object event);
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class Subscriber
|
||||
public static class Subscriber
|
||||
{
|
||||
private final Object object;
|
||||
private final Method method;
|
||||
private final float priority;
|
||||
@EqualsAndHashCode.Exclude
|
||||
private final SubscriberMethod lamda;
|
||||
private final Consumer<Object> lambda;
|
||||
|
||||
void invoke(final Object arg) throws Exception
|
||||
{
|
||||
if (lamda != null)
|
||||
if (lambda != null)
|
||||
{
|
||||
lamda.invoke(arg);
|
||||
lambda.accept(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -80,7 +74,9 @@ public class EventBus
|
||||
}
|
||||
|
||||
private final Consumer<Throwable> exceptionHandler;
|
||||
private ImmutableMultimap<Class, Subscriber> subscribers = ImmutableMultimap.of();
|
||||
|
||||
@Nonnull
|
||||
private ImmutableMultimap<Class<?>, Subscriber> subscribers = ImmutableMultimap.of();
|
||||
|
||||
/**
|
||||
* Instantiates EventBus with default exception handler
|
||||
@@ -99,13 +95,8 @@ public class EventBus
|
||||
*/
|
||||
public synchronized void register(@Nonnull final Object object)
|
||||
{
|
||||
final ImmutableMultimap.Builder<Class, Subscriber> builder = ImmutableMultimap.builder();
|
||||
|
||||
if (subscribers != null)
|
||||
{
|
||||
builder.putAll(subscribers);
|
||||
}
|
||||
|
||||
final ImmutableMultimap.Builder<Class<?>, Subscriber> builder = ImmutableMultimap.builder();
|
||||
builder.putAll(subscribers);
|
||||
builder.orderValuesBy(Comparator.comparing(Subscriber::getPriority).reversed()
|
||||
.thenComparing(s -> s.object.getClass().getName()));
|
||||
|
||||
@@ -141,7 +132,7 @@ public class EventBus
|
||||
Preconditions.checkArgument(method.getName().equals(preferredName), "Subscribed method " + method + " should be named " + preferredName);
|
||||
|
||||
method.setAccessible(true);
|
||||
SubscriberMethod lambda = null;
|
||||
Consumer<Object> lambda = null;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -150,14 +141,14 @@ public class EventBus
|
||||
final MethodHandle target = caller.findVirtual(clazz, method.getName(), subscription);
|
||||
final CallSite site = LambdaMetafactory.metafactory(
|
||||
caller,
|
||||
"invoke",
|
||||
MethodType.methodType(SubscriberMethod.class, clazz),
|
||||
"accept",
|
||||
MethodType.methodType(Consumer.class, clazz),
|
||||
subscription.changeParameterType(0, Object.class),
|
||||
target,
|
||||
subscription);
|
||||
|
||||
final MethodHandle factory = site.getTarget();
|
||||
lambda = (SubscriberMethod) factory.bindTo(object).invokeExact();
|
||||
lambda = (Consumer<Object>) factory.bindTo(object).invokeExact();
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
@@ -173,6 +164,21 @@ public class EventBus
|
||||
subscribers = builder.build();
|
||||
}
|
||||
|
||||
public synchronized <T> Subscriber register(Class<T> clazz, Consumer<T> subFn, float priority)
|
||||
{
|
||||
final ImmutableMultimap.Builder<Class<?>, Subscriber> builder = ImmutableMultimap.builder();
|
||||
builder.putAll(subscribers);
|
||||
builder.orderValuesBy(Comparator.comparing(Subscriber::getPriority).reversed()
|
||||
.thenComparing(s -> s.object.getClass().getName()));
|
||||
|
||||
Subscriber sub = new Subscriber(subFn, null, priority, (Consumer<Object>) subFn);
|
||||
builder.put(clazz, sub);
|
||||
|
||||
subscribers = builder.build();
|
||||
|
||||
return sub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters all subscribed methods from provided subscriber object.
|
||||
*
|
||||
@@ -180,12 +186,7 @@ public class EventBus
|
||||
*/
|
||||
public synchronized void unregister(@Nonnull final Object object)
|
||||
{
|
||||
if (subscribers == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final Multimap<Class, Subscriber> map = HashMultimap.create();
|
||||
final Multimap<Class<?>, Subscriber> map = HashMultimap.create();
|
||||
map.putAll(subscribers);
|
||||
|
||||
for (Class<?> clazz = object.getClass(); clazz != null; clazz = clazz.getSuperclass())
|
||||
@@ -207,6 +208,21 @@ public class EventBus
|
||||
subscribers = ImmutableMultimap.copyOf(map);
|
||||
}
|
||||
|
||||
public synchronized void unregister(Subscriber sub)
|
||||
{
|
||||
if (sub == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final Multimap<Class<?>, Subscriber> map = HashMultimap.create();
|
||||
map.putAll(subscribers);
|
||||
|
||||
map.values().remove(sub);
|
||||
|
||||
subscribers = ImmutableMultimap.copyOf(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts provided event to all registered subscribers. Subscriber calls are invoked immediately,
|
||||
* ordered by priority then their declaring class' name.
|
||||
|
||||
@@ -28,7 +28,7 @@ import java.awt.Color;
|
||||
import javax.swing.JButton;
|
||||
import lombok.Getter;
|
||||
|
||||
class DevToolsButton extends JButton
|
||||
public class DevToolsButton extends JButton
|
||||
{
|
||||
@Getter
|
||||
private boolean active;
|
||||
@@ -53,4 +53,20 @@ class DevToolsButton extends JButton
|
||||
setBackground(null);
|
||||
}
|
||||
}
|
||||
|
||||
void addFrame(DevToolsFrame frame)
|
||||
{
|
||||
frame.setDevToolsButton(this);
|
||||
addActionListener(ev ->
|
||||
{
|
||||
if (isActive())
|
||||
{
|
||||
frame.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.open();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Abex
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.devtools;
|
||||
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import javax.swing.JFrame;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Setter;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
|
||||
public class DevToolsFrame extends JFrame
|
||||
{
|
||||
@Setter(AccessLevel.PACKAGE)
|
||||
protected DevToolsButton devToolsButton;
|
||||
|
||||
public DevToolsFrame()
|
||||
{
|
||||
setIconImage(ClientUI.ICON);
|
||||
|
||||
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||
addWindowListener(new WindowAdapter()
|
||||
{
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e)
|
||||
{
|
||||
close();
|
||||
devToolsButton.setActive(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void open()
|
||||
{
|
||||
setVisible(true);
|
||||
toFront();
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.devtools;
|
||||
|
||||
import com.google.inject.ProvisionException;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.TrayIcon;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
@@ -32,6 +33,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JPanel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.MenuAction;
|
||||
@@ -44,6 +46,7 @@ import net.runelite.client.ui.overlay.infobox.Counter;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
|
||||
@Slf4j
|
||||
class DevToolsPanel extends PluginPanel
|
||||
{
|
||||
private final Client client;
|
||||
@@ -129,30 +132,10 @@ class DevToolsPanel extends PluginPanel
|
||||
});
|
||||
|
||||
container.add(plugin.getWidgetInspector());
|
||||
plugin.getWidgetInspector().addActionListener((ev) ->
|
||||
{
|
||||
if (plugin.getWidgetInspector().isActive())
|
||||
{
|
||||
widgetInspector.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
widgetInspector.open();
|
||||
}
|
||||
});
|
||||
plugin.getWidgetInspector().addFrame(widgetInspector);
|
||||
|
||||
container.add(plugin.getVarInspector());
|
||||
plugin.getVarInspector().addActionListener((ev) ->
|
||||
{
|
||||
if (plugin.getVarInspector().isActive())
|
||||
{
|
||||
varInspector.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
varInspector.open();
|
||||
}
|
||||
});
|
||||
plugin.getVarInspector().addFrame(varInspector);
|
||||
|
||||
container.add(plugin.getSoundEffects());
|
||||
|
||||
@@ -164,17 +147,7 @@ class DevToolsPanel extends PluginPanel
|
||||
container.add(notificationBtn);
|
||||
|
||||
container.add(plugin.getScriptInspector());
|
||||
plugin.getScriptInspector().addActionListener((ev) ->
|
||||
{
|
||||
if (plugin.getScriptInspector().isActive())
|
||||
{
|
||||
scriptInspector.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
scriptInspector.open();
|
||||
}
|
||||
});
|
||||
plugin.getScriptInspector().addFrame(scriptInspector);
|
||||
|
||||
final JButton newInfoboxBtn = new JButton("Infobox");
|
||||
newInfoboxBtn.addActionListener(e ->
|
||||
@@ -198,22 +171,27 @@ class DevToolsPanel extends PluginPanel
|
||||
container.add(clearInfoboxBtn);
|
||||
|
||||
container.add(plugin.getInventoryInspector());
|
||||
plugin.getInventoryInspector().addActionListener((ev) ->
|
||||
{
|
||||
if (plugin.getInventoryInspector().isActive())
|
||||
{
|
||||
inventoryInspector.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
inventoryInspector.open();
|
||||
}
|
||||
});
|
||||
plugin.getInventoryInspector().addFrame(inventoryInspector);
|
||||
|
||||
final JButton disconnectBtn = new JButton("Disconnect");
|
||||
disconnectBtn.addActionListener(e -> clientThread.invoke(() -> client.setGameState(GameState.CONNECTION_LOST)));
|
||||
container.add(disconnectBtn);
|
||||
|
||||
try
|
||||
{
|
||||
ShellFrame sf = plugin.getInjector().getInstance(ShellFrame.class);
|
||||
container.add(plugin.getShell());
|
||||
plugin.getShell().addFrame(sf);
|
||||
}
|
||||
catch (LinkageError | ProvisionException e)
|
||||
{
|
||||
log.debug("Shell is not supported", e);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.info("Shell couldn't be loaded", e);
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +143,7 @@ public class DevToolsPlugin extends Plugin
|
||||
private DevToolsButton soundEffects;
|
||||
private DevToolsButton scriptInspector;
|
||||
private DevToolsButton inventoryInspector;
|
||||
private DevToolsButton shell;
|
||||
private NavigationButton navButton;
|
||||
|
||||
@Provides
|
||||
@@ -187,6 +188,7 @@ public class DevToolsPlugin extends Plugin
|
||||
soundEffects = new DevToolsButton("Sound Effects");
|
||||
scriptInspector = new DevToolsButton("Script Inspector");
|
||||
inventoryInspector = new DevToolsButton("Inventory Inspector");
|
||||
shell = new DevToolsButton("Shell");
|
||||
|
||||
overlayManager.add(overlay);
|
||||
overlayManager.add(locationOverlay);
|
||||
|
||||
@@ -28,8 +28,6 @@ import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.AdjustmentEvent;
|
||||
import java.awt.event.AdjustmentListener;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -39,7 +37,6 @@ import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.JScrollPane;
|
||||
@@ -65,7 +62,7 @@ import net.runelite.client.ui.ColorScheme;
|
||||
|
||||
@Slf4j
|
||||
@Singleton
|
||||
class InventoryInspector extends JFrame
|
||||
class InventoryInspector extends DevToolsFrame
|
||||
{
|
||||
private static final int MAX_LOG_ENTRIES = 25;
|
||||
|
||||
@@ -80,7 +77,7 @@ class InventoryInspector extends JFrame
|
||||
private final InventoryDeltaPanel deltaPanel;
|
||||
|
||||
@Inject
|
||||
InventoryInspector(Client client, EventBus eventBus, DevToolsPlugin plugin, ItemManager itemManager, ClientThread clientThread)
|
||||
InventoryInspector(Client client, EventBus eventBus, ItemManager itemManager, ClientThread clientThread)
|
||||
{
|
||||
this.client = client;
|
||||
this.eventBus = eventBus;
|
||||
@@ -92,18 +89,6 @@ class InventoryInspector extends JFrame
|
||||
setTitle("RuneLite Inventory Inspector");
|
||||
setIconImage(ClientUI.ICON);
|
||||
|
||||
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||
// Reset highlight on close
|
||||
addWindowListener(new WindowAdapter()
|
||||
{
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e)
|
||||
{
|
||||
close();
|
||||
plugin.getInventoryInspector().setActive(false);
|
||||
}
|
||||
});
|
||||
|
||||
tree.setBorder(new EmptyBorder(2, 2, 2, 2));
|
||||
tree.setRootVisible(false);
|
||||
tree.setShowsRootHandles(true);
|
||||
@@ -175,19 +160,19 @@ class InventoryInspector extends JFrame
|
||||
pack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open()
|
||||
{
|
||||
eventBus.register(this);
|
||||
setVisible(true);
|
||||
toFront();
|
||||
repaint();
|
||||
super.open();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
eventBus.unregister(this);
|
||||
clearTracker();
|
||||
setVisible(false);
|
||||
super.close();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
|
||||
@@ -31,8 +31,6 @@ import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.event.AdjustmentEvent;
|
||||
import java.awt.event.AdjustmentListener;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
@@ -42,7 +40,6 @@ import javax.swing.BorderFactory;
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFormattedTextField;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
@@ -68,14 +65,13 @@ import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.DynamicGridLayout;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.util.Text;
|
||||
|
||||
@Slf4j
|
||||
public class ScriptInspector extends JFrame
|
||||
public class ScriptInspector extends DevToolsFrame
|
||||
{
|
||||
// These scripts are the only ones that fire every client tick regardless of location.
|
||||
private final static String DEFAULT_BLACKLIST = "3174,1004";
|
||||
@@ -139,28 +135,16 @@ public class ScriptInspector extends JFrame
|
||||
}
|
||||
|
||||
@Inject
|
||||
ScriptInspector(Client client, EventBus eventBus, DevToolsPlugin plugin, ConfigManager configManager)
|
||||
ScriptInspector(Client client, EventBus eventBus, ConfigManager configManager)
|
||||
{
|
||||
this.eventBus = eventBus;
|
||||
this.client = client;
|
||||
this.configManager = configManager;
|
||||
|
||||
setTitle("RuneLite Script Inspector");
|
||||
setIconImage(ClientUI.ICON);
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||
addWindowListener(new WindowAdapter()
|
||||
{
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e)
|
||||
{
|
||||
close();
|
||||
plugin.getScriptInspector().setActive(false);
|
||||
}
|
||||
});
|
||||
|
||||
tracker.setLayout(new DynamicGridLayout(0, 1, 0, 3));
|
||||
|
||||
final JPanel leftSide = new JPanel();
|
||||
@@ -344,14 +328,14 @@ public class ScriptInspector extends JFrame
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open()
|
||||
{
|
||||
eventBus.register(this);
|
||||
setVisible(true);
|
||||
toFront();
|
||||
repaint();
|
||||
super.open();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
configManager.setConfiguration("devtools", "highlights",
|
||||
@@ -360,7 +344,7 @@ public class ScriptInspector extends JFrame
|
||||
Text.toCSV(Lists.transform(new ArrayList<>(blacklist), String::valueOf)));
|
||||
currentNode = null;
|
||||
eventBus.unregister(this);
|
||||
setVisible(false);
|
||||
super.close();
|
||||
}
|
||||
|
||||
private void addScriptLog(ScriptTreeNode treeNode)
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Abex
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.devtools;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.jshell.ShellPanel;
|
||||
|
||||
@Singleton
|
||||
class ShellFrame extends DevToolsFrame
|
||||
{
|
||||
private final ShellPanel shellPanel;
|
||||
|
||||
@Inject
|
||||
ShellFrame(ClientThread clientThread, ScheduledExecutorService executor)
|
||||
{
|
||||
this.shellPanel = new ShellPanel(executor)
|
||||
{
|
||||
@Override
|
||||
protected void invokeOnClientThread(Runnable r)
|
||||
{
|
||||
clientThread.invoke(r);
|
||||
}
|
||||
};
|
||||
setContentPane(shellPanel);
|
||||
|
||||
setTitle("RuneLite Shell");
|
||||
|
||||
pack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open()
|
||||
{
|
||||
shellPanel.switchContext(RuneLite.getInjector());
|
||||
super.open();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
super.close();
|
||||
shellPanel.freeContext();
|
||||
}
|
||||
}
|
||||
@@ -32,15 +32,12 @@ import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.event.AdjustmentEvent;
|
||||
import java.awt.event.AdjustmentListener;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollBar;
|
||||
@@ -62,13 +59,12 @@ import net.runelite.api.events.VarbitChanged;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.DynamicGridLayout;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
|
||||
@Slf4j
|
||||
class VarInspector extends JFrame
|
||||
class VarInspector extends DevToolsFrame
|
||||
{
|
||||
@Getter
|
||||
private enum VarType
|
||||
@@ -106,28 +102,16 @@ class VarInspector extends JFrame
|
||||
private Map<Integer, Object> varcs = null;
|
||||
|
||||
@Inject
|
||||
VarInspector(Client client, ClientThread clientThread, EventBus eventBus, DevToolsPlugin plugin)
|
||||
VarInspector(Client client, ClientThread clientThread, EventBus eventBus)
|
||||
{
|
||||
this.client = client;
|
||||
this.clientThread = clientThread;
|
||||
this.eventBus = eventBus;
|
||||
|
||||
setTitle("RuneLite Var Inspector");
|
||||
setIconImage(ClientUI.ICON);
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||
addWindowListener(new WindowAdapter()
|
||||
{
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e)
|
||||
{
|
||||
close();
|
||||
plugin.getVarInspector().setActive(false);
|
||||
}
|
||||
});
|
||||
|
||||
tracker.setLayout(new DynamicGridLayout(0, 1, 0, 3));
|
||||
|
||||
final JPanel trackerWrapper = new JPanel();
|
||||
@@ -332,6 +316,7 @@ class VarInspector extends JFrame
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open()
|
||||
{
|
||||
if (oldVarps == null)
|
||||
@@ -361,16 +346,15 @@ class VarInspector extends JFrame
|
||||
});
|
||||
|
||||
eventBus.register(this);
|
||||
setVisible(true);
|
||||
toFront();
|
||||
repaint();
|
||||
super.open();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
super.close();
|
||||
tracker.removeAll();
|
||||
eventBus.unregister(this);
|
||||
setVisible(false);
|
||||
varcs = null;
|
||||
varbits = null;
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@ import com.google.inject.Singleton;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
@@ -43,7 +41,6 @@ import java.util.Stack;
|
||||
import java.util.stream.Stream;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSplitPane;
|
||||
@@ -73,13 +70,12 @@ import net.runelite.api.widgets.WidgetType;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
import net.runelite.client.ui.overlay.OverlayManager;
|
||||
import net.runelite.client.util.ColorUtil;
|
||||
|
||||
@Slf4j
|
||||
@Singleton
|
||||
class WidgetInspector extends JFrame
|
||||
class WidgetInspector extends DevToolsFrame
|
||||
{
|
||||
private static final Map<Integer, WidgetInfo> widgetIdMap = new HashMap<>();
|
||||
|
||||
@@ -123,7 +119,6 @@ class WidgetInspector extends JFrame
|
||||
ClientThread clientThread,
|
||||
WidgetInfoTableModel infoTableModel,
|
||||
DevToolsConfig config,
|
||||
DevToolsPlugin plugin,
|
||||
EventBus eventBus,
|
||||
Provider<WidgetInspectorOverlay> overlay,
|
||||
OverlayManager overlayManager)
|
||||
@@ -138,18 +133,6 @@ class WidgetInspector extends JFrame
|
||||
eventBus.register(this);
|
||||
|
||||
setTitle("RuneLite Widget Inspector");
|
||||
setIconImage(ClientUI.ICON);
|
||||
|
||||
// Reset highlight on close
|
||||
addWindowListener(new WindowAdapter()
|
||||
{
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e)
|
||||
{
|
||||
close();
|
||||
plugin.getWidgetInspector().setActive(false);
|
||||
}
|
||||
});
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
@@ -402,21 +385,21 @@ class WidgetInspector extends JFrame
|
||||
return widgetIdMap.get(packedId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open()
|
||||
{
|
||||
setVisible(true);
|
||||
toFront();
|
||||
repaint();
|
||||
super.open();
|
||||
overlayManager.add(this.overlay.get());
|
||||
clientThread.invokeLater(this::addPickerWidget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
overlayManager.remove(this.overlay.get());
|
||||
clientThread.invokeLater(this::removePickerWidget);
|
||||
setSelectedWidget(null, -1, false);
|
||||
setVisible(false);
|
||||
super.close();
|
||||
}
|
||||
|
||||
private void removePickerWidget()
|
||||
|
||||
83
runelite-jshell/pom.xml
Normal file
83
runelite-jshell/pom.xml
Normal file
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.runelite</groupId>
|
||||
<artifactId>runelite-parent</artifactId>
|
||||
<version>1.7.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>jshell</artifactId>
|
||||
<name>RuneLite JShell</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<classifier>no_aop</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fifesoft</groupId>
|
||||
<artifactId>rsyntaxtextarea</artifactId>
|
||||
<version>3.1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fifesoft</groupId>
|
||||
<artifactId>autocomplete</artifactId>
|
||||
<version>3.1.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>11</source>
|
||||
<target>11</target>
|
||||
<release>11</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Abex
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.jshell;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import jdk.jshell.JShell;
|
||||
import jdk.jshell.SourceCodeAnalysis;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.fife.ui.autocomplete.BasicCompletion;
|
||||
import org.fife.ui.autocomplete.Completion;
|
||||
import org.fife.ui.autocomplete.CompletionProviderBase;
|
||||
import org.fife.ui.autocomplete.ParameterizedCompletion;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class JShellAutocompleteProvider extends CompletionProviderBase
|
||||
{
|
||||
private final JShell shell;
|
||||
private String anchorText;
|
||||
private List<Completion> completions;
|
||||
|
||||
@Override
|
||||
protected List<Completion> getCompletionsImpl(JTextComponent comp)
|
||||
{
|
||||
return completions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlreadyEnteredText(JTextComponent comp)
|
||||
{
|
||||
complete(comp);
|
||||
return anchorText;
|
||||
}
|
||||
|
||||
private void complete(JTextComponent comp)
|
||||
{
|
||||
completions = Collections.emptyList();
|
||||
|
||||
String src = comp.getText();
|
||||
int cursor = comp.getCaretPosition();
|
||||
|
||||
for (int offset = 0; offset < src.length() && cursor >= offset; )
|
||||
{
|
||||
var snipSrc = src.substring(offset);
|
||||
int thisOffset = offset;
|
||||
var ci = shell.sourceCodeAnalysis().analyzeCompletion(snipSrc);
|
||||
offset = src.length() - ci.remaining().length();
|
||||
boolean mayHaveMore = ci.completeness() == SourceCodeAnalysis.Completeness.COMPLETE_WITH_SEMI
|
||||
|| ci.completeness() == SourceCodeAnalysis.Completeness.COMPLETE;
|
||||
|
||||
if (cursor <= offset || !mayHaveMore)
|
||||
{
|
||||
var anchor = new int[1];
|
||||
|
||||
completions = shell.sourceCodeAnalysis()
|
||||
.completionSuggestions(snipSrc, cursor - thisOffset, anchor)
|
||||
.stream()
|
||||
.filter(v -> !v.continuation().startsWith("$"))
|
||||
.map(s ->
|
||||
{
|
||||
return new BasicCompletion(this, s.continuation());
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
anchorText = snipSrc.substring(anchor[0], cursor - thisOffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (completions.isEmpty())
|
||||
{
|
||||
anchorText = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Completion> getCompletionsAt(JTextComponent comp, Point p)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoActivateOkay(JTextComponent comp)
|
||||
{
|
||||
// try not to start autocomplete when it has no useful context
|
||||
String text = comp.getText();
|
||||
for (int i = comp.getCaretPosition(); i >= 0; i--)
|
||||
{
|
||||
char c = text.charAt(i);
|
||||
if (Character.isJavaIdentifierPart(c) || c == '.' || c == '(')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (Character.isWhitespace(c))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ParameterizedCompletion> getParameterizedCompletions(JTextComponent tc)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Abex
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.jshell;
|
||||
|
||||
import java.util.Map;
|
||||
import jdk.jshell.execution.DirectExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionControlProvider;
|
||||
import jdk.jshell.spi.ExecutionEnv;
|
||||
|
||||
public class RLShellExecutionControl extends DirectExecutionControl implements ExecutionControlProvider
|
||||
{
|
||||
public RLShellExecutionControl()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionControl generate(ExecutionEnv env, Map<String, String> parameters) throws Throwable
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Abex
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.jshell;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.jshell.EvalException;
|
||||
|
||||
class RemappingThrowable extends Throwable
|
||||
{
|
||||
private final String source;
|
||||
private final Map<String, Integer> offsets;
|
||||
private final Throwable wrapped;
|
||||
private final Map<Throwable, Throwable> dejaVu;
|
||||
|
||||
public RemappingThrowable(String source, Map<String, Integer> offsets, Throwable other)
|
||||
{
|
||||
this(source, offsets, other, new HashMap<>());
|
||||
}
|
||||
|
||||
private RemappingThrowable(String source, Map<String, Integer> offsets, Throwable other, Map<Throwable, Throwable> dejaVu)
|
||||
{
|
||||
super();
|
||||
|
||||
this.source = source;
|
||||
this.offsets = offsets;
|
||||
this.wrapped = other;
|
||||
this.dejaVu = dejaVu;
|
||||
|
||||
dejaVu.put(wrapped, this);
|
||||
|
||||
setStackTrace(Stream.of(wrapped.getStackTrace())
|
||||
.map(e ->
|
||||
{
|
||||
Integer boxOffset = offsets.get(e.getFileName());
|
||||
if (boxOffset == null)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
|
||||
int offset = boxOffset;
|
||||
int line = e.getLineNumber();
|
||||
for (int i = 0; i <= offset && i < source.length(); i++)
|
||||
{
|
||||
if (source.charAt(i) == '\n')
|
||||
{
|
||||
line++;
|
||||
}
|
||||
}
|
||||
return new StackTraceElement(
|
||||
Strings.isNullOrEmpty(e.getClassName()) ? "Shell" : e.getClassName(),
|
||||
Strings.isNullOrEmpty(e.getMethodName()) ? "global" : e.getMethodName(),
|
||||
"",
|
||||
line);
|
||||
})
|
||||
.toArray(StackTraceElement[]::new));
|
||||
|
||||
if (wrapped.getCause() != null)
|
||||
{
|
||||
initCause(remap(wrapped.getCause()));
|
||||
}
|
||||
|
||||
for (Throwable suppressed : wrapped.getSuppressed())
|
||||
{
|
||||
addSuppressed(remap(suppressed));
|
||||
}
|
||||
}
|
||||
|
||||
private Throwable remap(Throwable other)
|
||||
{
|
||||
Throwable remap = dejaVu.get(other);
|
||||
if (remap == null)
|
||||
{
|
||||
remap = new RemappingThrowable(source, offsets, other, dejaVu);
|
||||
// ctor inserts into the map
|
||||
}
|
||||
return remap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
return wrapped.getMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalizedMessage()
|
||||
{
|
||||
return wrapped.getLocalizedMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String className;
|
||||
if (wrapped instanceof EvalException)
|
||||
{
|
||||
className = ((EvalException) wrapped).getExceptionClassName();
|
||||
}
|
||||
else
|
||||
{
|
||||
className = wrapped.getClass().getName();
|
||||
}
|
||||
|
||||
String message = wrapped.getLocalizedMessage();
|
||||
if (message == null)
|
||||
{
|
||||
return className;
|
||||
}
|
||||
return className + ": " + message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Abex
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.jshell;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Injector;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Font;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Segment;
|
||||
import jdk.jshell.Diag;
|
||||
import jdk.jshell.JShell;
|
||||
import jdk.jshell.Snippet;
|
||||
import jdk.jshell.SnippetEvent;
|
||||
import jdk.jshell.SourceCodeAnalysis;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.fife.ui.autocomplete.AutoCompletion;
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
import org.fife.ui.rsyntaxtextarea.Theme;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Slf4j
|
||||
public abstract class ShellPanel extends JPanel
|
||||
{
|
||||
private final ScheduledExecutorService executor;
|
||||
|
||||
private final RSyntaxTextArea textArea;
|
||||
private final JTextArea console = new JTextArea();
|
||||
|
||||
@Getter
|
||||
private final Logger shellLogger;
|
||||
|
||||
private final List<Runnable> cleanup = new ArrayList<>();
|
||||
|
||||
private RLShellExecutionControl exec;
|
||||
private JShell shell;
|
||||
private Set<Snippet> prelude;
|
||||
private Injector injector;
|
||||
private AutoCompletion autoCompletion;
|
||||
|
||||
public static ShellPanel INSTANCE;
|
||||
|
||||
public ShellPanel(ScheduledExecutorService executor)
|
||||
{
|
||||
this.executor = executor;
|
||||
|
||||
Font codeFont = Stream.of(
|
||||
"Source code pro",
|
||||
"DejaVu Sans Code",
|
||||
"Consolas",
|
||||
Font.MONOSPACED)
|
||||
.map(name -> new Font(name, Font.PLAIN, 12))
|
||||
.filter(f -> !"Dialog.plain".equals(f.getFontName()))
|
||||
.findFirst()
|
||||
.get();
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
JPanel topPanel = new JPanel();
|
||||
topPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
|
||||
|
||||
JButton run = new JButton("⯈");
|
||||
run.setToolTipText("Run");
|
||||
run.addActionListener(ev -> run());
|
||||
topPanel.add(run);
|
||||
|
||||
JButton clear = new JButton("🗑");
|
||||
run.setToolTipText("Clear console");
|
||||
clear.addActionListener(ev -> console.setText(""));
|
||||
topPanel.add(clear);
|
||||
|
||||
add(topPanel, BorderLayout.NORTH);
|
||||
|
||||
textArea = new RSyntaxTextArea();
|
||||
|
||||
try
|
||||
{
|
||||
// RSyntaxTextArea::setAntiAliasingEnabled actually forces it to match the platform's
|
||||
// default, which is pointless
|
||||
var map = new HashMap<RenderingHints.Key, Object>();
|
||||
map.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
|
||||
var f = RSyntaxTextArea.class.getDeclaredField("aaHints");
|
||||
f.setAccessible(true);
|
||||
f.set(textArea, map);
|
||||
}
|
||||
catch (ReflectiveOperationException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
textArea.setFont(codeFont);
|
||||
textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||
textArea.setAutoIndentEnabled(true);
|
||||
textArea.setPaintTabLines(true);
|
||||
textArea.setShowMatchedBracketPopup(true);
|
||||
textArea.setCloseCurlyBraces(false);
|
||||
textArea.setTabSize(2);
|
||||
textArea.setMarkOccurrences(true);
|
||||
textArea.setMarkOccurrencesDelay(200);
|
||||
textArea.addKeyListener(new KeyAdapter()
|
||||
{
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e)
|
||||
{
|
||||
if (e.getKeyCode() == KeyEvent.VK_R && (e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0)
|
||||
{
|
||||
run();
|
||||
e.consume();
|
||||
}
|
||||
if (e.getKeyCode() == KeyEvent.VK_F10)
|
||||
{
|
||||
run();
|
||||
e.consume();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var textScrollArea = new RTextScrollPane(textArea);
|
||||
|
||||
try
|
||||
{
|
||||
Theme.load(ShellPanel.class.getResourceAsStream("darcula.xml"), codeFont)
|
||||
.apply(textArea);
|
||||
|
||||
try (var is = ShellPanel.class.getResourceAsStream("default.jsh"))
|
||||
{
|
||||
textArea.setText(new String(is.readAllBytes(), StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
console.setFont(codeFont);
|
||||
console.setFocusable(false);
|
||||
console.setEditable(false);
|
||||
console.setOpaque(false); // this turns off the hover effect for some reason
|
||||
|
||||
var split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, textScrollArea, new JScrollPane(console));
|
||||
split.setResizeWeight(.8);
|
||||
split.setPreferredSize(new Dimension(800, 800));
|
||||
add(split, BorderLayout.CENTER);
|
||||
|
||||
shellLogger = new TeeLogger(LoggerFactory.getLogger("Shell"), this::logToConsole);
|
||||
INSTANCE = this;
|
||||
|
||||
// make sure jshell is on the classpath
|
||||
JShell.builder();
|
||||
}
|
||||
|
||||
public void switchContext(Injector injector)
|
||||
{
|
||||
freeContext();
|
||||
|
||||
this.injector = injector;
|
||||
|
||||
exec = new RLShellExecutionControl()
|
||||
{
|
||||
@Override
|
||||
protected String invoke(Method doitMethod) throws Exception
|
||||
{
|
||||
var result = new AtomicReference<>();
|
||||
var sema = new Semaphore(0);
|
||||
invokeOnClientThread(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
result.set(super.invoke(doitMethod));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
result.set(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
sema.release();
|
||||
}
|
||||
});
|
||||
sema.acquire();
|
||||
if (result.get() instanceof String)
|
||||
{
|
||||
return (String) result.get();
|
||||
}
|
||||
throw (Exception) result.get();
|
||||
}
|
||||
};
|
||||
|
||||
shell = JShell.builder()
|
||||
.executionEngine(exec, null)
|
||||
.build();
|
||||
|
||||
String preludeStr;
|
||||
try (var is = ShellPanel.class.getResourceAsStream("prelude.jsh"))
|
||||
{
|
||||
preludeStr = new String(is.readAllBytes(), StandardCharsets.UTF_8);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
prelude = ImmutableSet.copyOf(eval(preludeStr, false));
|
||||
|
||||
var cp = new JShellAutocompleteProvider(shell);
|
||||
autoCompletion = new AutoCompletion(cp);
|
||||
autoCompletion.setAutoActivationDelay(200);
|
||||
autoCompletion.setAutoActivationEnabled(true);
|
||||
autoCompletion.setAutoCompleteSingleChoices(false);
|
||||
autoCompletion.install(this.textArea);
|
||||
}
|
||||
|
||||
public void logToConsole(String message)
|
||||
{
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc = console.getDocument();
|
||||
if (doc.getLength() > 100_000)
|
||||
{
|
||||
Segment seg = new Segment();
|
||||
int i = doc.getLength() - 75_000;
|
||||
for (; i < doc.getLength(); i++)
|
||||
{
|
||||
doc.getText(i, 1, seg);
|
||||
if (seg.array[0] == '\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
doc.remove(0, i);
|
||||
}
|
||||
doc.insertString(doc.getLength(), message + "\n", null);
|
||||
console.setCaretPosition(doc.getLength());
|
||||
}
|
||||
catch (BadLocationException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<Snippet> eval(String src, boolean isUserCode)
|
||||
{
|
||||
var out = new ArrayList<Snippet>();
|
||||
var offsets = new HashMap<String, Integer>();
|
||||
String output = null;
|
||||
evaluation:
|
||||
for (int offset = 0; offset < src.length(); )
|
||||
{
|
||||
// Workaround a jdk bug
|
||||
for (; src.charAt(offset) == '\n'; offset++);
|
||||
|
||||
var ci = shell.sourceCodeAnalysis().analyzeCompletion(src.substring(offset));
|
||||
int thisOffset = offset;
|
||||
offset = src.length() - ci.remaining().length();
|
||||
if (ci.completeness() == SourceCodeAnalysis.Completeness.EMPTY)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
List<SnippetEvent> evs = shell.eval(ci.source());
|
||||
for (var ev : evs)
|
||||
{
|
||||
Snippet snip = ev.snippet();
|
||||
offsets.put("#" + snip.id(), thisOffset);
|
||||
if (ev.status() != Snippet.Status.VALID && ev.status() != Snippet.Status.RECOVERABLE_DEFINED)
|
||||
{
|
||||
var diags = shell.diagnostics(snip).collect(Collectors.toList());
|
||||
for (var diag : diags)
|
||||
{
|
||||
String msg = toStringDiagnostic(src, thisOffset, diag);
|
||||
if (isUserCode)
|
||||
{
|
||||
logToConsole(msg);
|
||||
// It might be nice to highlight stuff here
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("prelude error: " + msg);
|
||||
}
|
||||
}
|
||||
if (diags.isEmpty())
|
||||
{
|
||||
logToConsole("bad snippet" + ev.status());
|
||||
}
|
||||
break evaluation;
|
||||
}
|
||||
if (ev.exception() != null)
|
||||
{
|
||||
if (isUserCode)
|
||||
{
|
||||
shellLogger.error("", new RemappingThrowable(src, offsets, ev.exception()));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("prelude error", ev.exception());
|
||||
}
|
||||
}
|
||||
output = ev.value();
|
||||
|
||||
out.add(snip);
|
||||
}
|
||||
}
|
||||
|
||||
if (isUserCode && !Strings.isNullOrEmpty(output))
|
||||
{
|
||||
logToConsole("[OUTPUT] " + output);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private String toStringDiagnostic(String source, int offset, Diag diag)
|
||||
{
|
||||
int line = 1;
|
||||
int column = 1;
|
||||
offset += (int) diag.getPosition();
|
||||
for (int i = 0; i < offset && i < source.length(); i++)
|
||||
{
|
||||
if (source.charAt(i) == '\n')
|
||||
{
|
||||
line++;
|
||||
column = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
column++;
|
||||
}
|
||||
}
|
||||
|
||||
return line + ":" + column + ": " + diag.getMessage(Locale.getDefault());
|
||||
}
|
||||
|
||||
protected void run()
|
||||
{
|
||||
String text = textArea.getText();
|
||||
executor.submit(() ->
|
||||
{
|
||||
shell.snippets()
|
||||
.filter(v -> !prelude.contains(v))
|
||||
.forEach(shell::drop);
|
||||
|
||||
cleanup();
|
||||
|
||||
eval(text, true);
|
||||
});
|
||||
}
|
||||
|
||||
public void freeContext()
|
||||
{
|
||||
cleanup();
|
||||
|
||||
exec = null;
|
||||
shell = null;
|
||||
prelude = null;
|
||||
injector = null;
|
||||
|
||||
if (autoCompletion != null)
|
||||
{
|
||||
autoCompletion.uninstall();
|
||||
}
|
||||
autoCompletion = null;
|
||||
|
||||
console.setText("");
|
||||
}
|
||||
|
||||
private void cleanup()
|
||||
{
|
||||
for (var c : cleanup)
|
||||
{
|
||||
try
|
||||
{
|
||||
c.run();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
shellLogger.error("Cleanup threw:", e);
|
||||
}
|
||||
}
|
||||
cleanup.clear();
|
||||
}
|
||||
|
||||
protected abstract void invokeOnClientThread(Runnable r);
|
||||
|
||||
public <T> T inject(Class<T> clazz)
|
||||
{
|
||||
return injector.getInstance(clazz);
|
||||
}
|
||||
|
||||
public void cleanup(Runnable r)
|
||||
{
|
||||
cleanup.add(r);
|
||||
}
|
||||
}
|
||||
483
runelite-jshell/src/main/java/net/runelite/jshell/TeeLogger.java
Normal file
483
runelite-jshell/src/main/java/net/runelite/jshell/TeeLogger.java
Normal file
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Abex
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.jshell;
|
||||
|
||||
import java.io.CharArrayWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.function.Consumer;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.Marker;
|
||||
import org.slf4j.helpers.FormattingTuple;
|
||||
import org.slf4j.helpers.MessageFormatter;
|
||||
|
||||
@SuppressWarnings("PlaceholderCountMatchesArgumentCount")
|
||||
@RequiredArgsConstructor
|
||||
public class TeeLogger implements Logger
|
||||
{
|
||||
private static final String TRACE = "[TRACE] ";
|
||||
private static final String DEBUG = "[DEBUG] ";
|
||||
private static final String INFO = "[INFO] ";
|
||||
private static final String WARN = "[WARN] ";
|
||||
private static final String ERROR = "[ERROR] ";
|
||||
|
||||
private final Logger delegate;
|
||||
private final Consumer<String> messageConsumer;
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return "RLShell";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private void log(String level, String message, Object... format)
|
||||
{
|
||||
FormattingTuple fmt = MessageFormatter.arrayFormat(message, format);
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append(level).append(fmt.getMessage());
|
||||
Throwable throwable = fmt.getThrowable();
|
||||
if (throwable != null)
|
||||
{
|
||||
msg.append("\n");
|
||||
var caw = new CharArrayWriter();
|
||||
try (PrintWriter pw = new PrintWriter(caw))
|
||||
{
|
||||
throwable.printStackTrace(pw);
|
||||
}
|
||||
msg.append(caw.toString());
|
||||
}
|
||||
messageConsumer.accept(msg.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String msg)
|
||||
{
|
||||
delegate.trace(msg);
|
||||
log(TRACE, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String format, Object arg)
|
||||
{
|
||||
delegate.trace(format, arg);
|
||||
log(TRACE, format, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String format, Object arg1, Object arg2)
|
||||
{
|
||||
delegate.trace(format, arg1, arg2);
|
||||
log(TRACE, format, arg1, arg2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String format, Object... arguments)
|
||||
{
|
||||
delegate.trace(format, arguments);
|
||||
log(TRACE, format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String msg, Throwable t)
|
||||
{
|
||||
delegate.trace(msg, t);
|
||||
log(TRACE, msg, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled(Marker marker)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String msg)
|
||||
{
|
||||
delegate.trace(marker, msg);
|
||||
log(TRACE, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String format, Object arg)
|
||||
{
|
||||
delegate.trace(marker, format, arg);
|
||||
log(TRACE, format, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String format, Object arg1, Object arg2)
|
||||
{
|
||||
delegate.trace(marker, format, arg1, arg2);
|
||||
log(TRACE, format, arg1, arg2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String format, Object... argArray)
|
||||
{
|
||||
delegate.trace(marker, format, argArray);
|
||||
log(TRACE, format, argArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String msg, Throwable t)
|
||||
{
|
||||
delegate.trace(marker, msg, t);
|
||||
log(TRACE, msg, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg)
|
||||
{
|
||||
delegate.debug(msg);
|
||||
log(DEBUG, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String format, Object arg)
|
||||
{
|
||||
delegate.debug(format, arg);
|
||||
log(DEBUG, format, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String format, Object arg1, Object arg2)
|
||||
{
|
||||
delegate.debug(format, arg1, arg2);
|
||||
log(DEBUG, format, arg1, arg2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String format, Object... arguments)
|
||||
{
|
||||
delegate.debug(format, arguments);
|
||||
log(DEBUG, format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg, Throwable t)
|
||||
{
|
||||
delegate.debug(msg, t);
|
||||
log(DEBUG, msg, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled(Marker marker)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String msg)
|
||||
{
|
||||
delegate.debug(marker, msg);
|
||||
log(DEBUG, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String format, Object arg)
|
||||
{
|
||||
delegate.debug(marker, format, arg);
|
||||
log(DEBUG, format, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String format, Object arg1, Object arg2)
|
||||
{
|
||||
delegate.debug(marker, format, arg1, arg2);
|
||||
log(DEBUG, format, arg1, arg2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String format, Object... arguments)
|
||||
{
|
||||
delegate.debug(marker, format, arguments);
|
||||
log(DEBUG, format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String msg, Throwable t)
|
||||
{
|
||||
delegate.debug(marker, msg, t);
|
||||
log(DEBUG, msg, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg)
|
||||
{
|
||||
delegate.info(msg);
|
||||
log(INFO, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String format, Object arg)
|
||||
{
|
||||
delegate.info(format, arg);
|
||||
log(INFO, format, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String format, Object arg1, Object arg2)
|
||||
{
|
||||
delegate.info(format, arg1, arg2);
|
||||
log(INFO, format, arg1, arg2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String format, Object... arguments)
|
||||
{
|
||||
delegate.info(format, arguments);
|
||||
log(INFO, format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Throwable t)
|
||||
{
|
||||
delegate.info(msg, t);
|
||||
log(INFO, msg, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled(Marker marker)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String msg)
|
||||
{
|
||||
delegate.info(marker, msg);
|
||||
log(INFO, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String format, Object arg)
|
||||
{
|
||||
delegate.info(marker, format, arg);
|
||||
log(INFO, format, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String format, Object arg1, Object arg2)
|
||||
{
|
||||
delegate.info(marker, format, arg1, arg2);
|
||||
log(INFO, format, arg1, arg2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String format, Object... arguments)
|
||||
{
|
||||
delegate.info(marker, format, arguments);
|
||||
log(INFO, format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String msg, Throwable t)
|
||||
{
|
||||
delegate.info(marker, msg, t);
|
||||
log(INFO, msg, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg)
|
||||
{
|
||||
delegate.warn(msg);
|
||||
log(WARN, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String format, Object arg)
|
||||
{
|
||||
delegate.warn(format, arg);
|
||||
log(WARN, format, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String format, Object... arguments)
|
||||
{
|
||||
delegate.warn(format, arguments);
|
||||
log(WARN, format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String format, Object arg1, Object arg2)
|
||||
{
|
||||
delegate.warn(format, arg1, arg2);
|
||||
log(WARN, format, arg1, arg2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable t)
|
||||
{
|
||||
delegate.warn(msg, t);
|
||||
log(WARN, msg, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled(Marker marker)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String msg)
|
||||
{
|
||||
delegate.warn(marker, msg);
|
||||
log(WARN, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String format, Object arg)
|
||||
{
|
||||
delegate.warn(marker, format, arg);
|
||||
log(WARN, format, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String format, Object arg1, Object arg2)
|
||||
{
|
||||
delegate.warn(marker, format, arg1, arg2);
|
||||
log(WARN, format, arg1, arg2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String format, Object... arguments)
|
||||
{
|
||||
delegate.warn(marker, format, arguments);
|
||||
log(WARN, format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String msg, Throwable t)
|
||||
{
|
||||
delegate.warn(marker, msg, t);
|
||||
log(WARN, msg, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg)
|
||||
{
|
||||
delegate.error(msg);
|
||||
log(ERROR, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String format, Object arg)
|
||||
{
|
||||
delegate.error(format, arg);
|
||||
log(ERROR, format, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String format, Object arg1, Object arg2)
|
||||
{
|
||||
delegate.error(format, arg1, arg2);
|
||||
log(ERROR, format, arg1, arg2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String format, Object... arguments)
|
||||
{
|
||||
delegate.error(format, arguments);
|
||||
log(ERROR, format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg, Throwable t)
|
||||
{
|
||||
delegate.error(msg, t);
|
||||
log(ERROR, msg, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled(Marker marker)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String msg)
|
||||
{
|
||||
delegate.error(marker, msg);
|
||||
log(ERROR, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String format, Object arg)
|
||||
{
|
||||
delegate.error(marker, format, arg);
|
||||
log(ERROR, format, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String format, Object arg1, Object arg2)
|
||||
{
|
||||
delegate.error(marker, format, arg1, arg2);
|
||||
log(ERROR, format, arg1, arg2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String format, Object... arguments)
|
||||
{
|
||||
delegate.error(marker, format, arguments);
|
||||
log(ERROR, format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String msg, Throwable t)
|
||||
{
|
||||
delegate.error(marker, msg, t);
|
||||
log(ERROR, msg, t);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE RSyntaxTheme SYSTEM "theme.dtd">
|
||||
|
||||
<RSyntaxTheme version="1.0">
|
||||
<!-- General editor colors. -->
|
||||
<background color="2B2B2B"/>
|
||||
<caret color="BBBBBB"/>
|
||||
<selection useFG="false" bg="214283" roundedEdges="false"/>
|
||||
<currentLineHighlight color="323232" fade="false"/>
|
||||
<marginLine fg="394448"/>
|
||||
<markAllHighlight color="155221"/>
|
||||
<markOccurrencesHighlight color="32593D" border="true"/>
|
||||
<matchedBracket fg="A9B7C6" bg="2E2E2E" highlightBoth="true" animate="true"/><!--ij draws a border-->
|
||||
<hyperlinks fg="287BDE"/>
|
||||
<secondaryLanguages>
|
||||
<language index="1" bg="333344"/>
|
||||
<language index="2" bg="223322"/>
|
||||
<language index="3" bg="332222"/>
|
||||
</secondaryLanguages>
|
||||
|
||||
<!-- Gutter styling. -->
|
||||
<gutterBorder color="606366"/>
|
||||
<lineNumbers fg="606366"/>
|
||||
<foldIndicator fg="6A8088" iconBg="2f383c" iconArmedBg="3f484c"/>
|
||||
<iconRowHeader activeLineRange="878787"/>
|
||||
|
||||
<!-- Syntax tokens. -->
|
||||
<tokenStyles>
|
||||
<style token="IDENTIFIER" fg="A9B7C6"/>
|
||||
<style token="RESERVED_WORD" fg="CC7832" bold="false"/>
|
||||
<style token="RESERVED_WORD_2" fg="CC7832" bold="false"/>
|
||||
<style token="ANNOTATION" fg="BBB529"/>
|
||||
<style token="COMMENT_DOCUMENTATION" fg="629755"/>
|
||||
<style token="COMMENT_EOL" fg="808080"/>
|
||||
<style token="COMMENT_MULTILINE" fg="808080"/>
|
||||
<style token="COMMENT_KEYWORD" fg="629755"/>
|
||||
<style token="COMMENT_MARKUP" fg="77B767"/>
|
||||
<style token="FUNCTION" fg="A9B7C6"/><!-- any identifier magically known -->
|
||||
<style token="DATA_TYPE" fg="CC7832" bold="false"/>
|
||||
<style token="LITERAL_BOOLEAN" fg="CC7832" bold="false"/>
|
||||
<style token="LITERAL_NUMBER_DECIMAL_INT" fg="6897BB"/>
|
||||
<style token="LITERAL_NUMBER_FLOAT" fg="6897BB"/>
|
||||
<style token="LITERAL_NUMBER_HEXADECIMAL" fg="6897BB"/>
|
||||
<style token="LITERAL_STRING_DOUBLE_QUOTE" fg="6A8759"/>
|
||||
<style token="LITERAL_CHAR" fg="6A8759"/>
|
||||
<style token="LITERAL_BACKQUOTE" fg="6A8759"/>
|
||||
|
||||
<!-- all wrong but nobody will write xml in this -->
|
||||
<style token="MARKUP_TAG_DELIMITER" fg="F92672"/>
|
||||
<style token="MARKUP_TAG_NAME" fg="ABBFD3" bold="true"/>
|
||||
<style token="MARKUP_TAG_ATTRIBUTE" fg="B3B689"/>
|
||||
<style token="MARKUP_TAG_ATTRIBUTE_VALUE" fg="e1e2cf"/>
|
||||
<style token="MARKUP_COMMENT" fg="878787"/>
|
||||
<style token="MARKUP_DTD" fg="A082BD"/>
|
||||
<style token="MARKUP_PROCESSING_INSTRUCTION" fg="A082BD"/>
|
||||
<style token="MARKUP_CDATA" fg="d5e6f0"/>
|
||||
<style token="MARKUP_CDATA_DELIMITER" fg="FD971F"/>
|
||||
<style token="MARKUP_ENTITY_REFERENCE" fg="F92672"/>
|
||||
|
||||
<style token="OPERATOR" fg="A9B7C6"/>
|
||||
<style token="PREPROCESSOR" fg="A082BD"/>
|
||||
<style token="REGEX" fg="6A8759"/>
|
||||
<style token="SEPARATOR" fg="A9B7C6"/>
|
||||
<style token="VARIABLE" fg="A9B7C6" bold="false"/>
|
||||
<style token="WHITESPACE" fg="606060"/>
|
||||
|
||||
<style token="ERROR_IDENTIFIER" fg="F9F9F9" bg="d82323"/>
|
||||
<style token="ERROR_NUMBER_FORMAT" fg="F9F9F9" bg="d82323"/>
|
||||
<style token="ERROR_STRING_DOUBLE" fg="F9F9F9" bg="d82323"/>
|
||||
<style token="ERROR_CHAR" fg="F9F9F9" bg="d82323"/>
|
||||
</tokenStyles>
|
||||
|
||||
</RSyntaxTheme>
|
||||
@@ -0,0 +1,8 @@
|
||||
// Welcome to the RuneLite Development Shell
|
||||
// Everything executed here runs on the client thread by default.
|
||||
// By default client, clientThread, configManager and log are in scope
|
||||
// You can subscribe to the Event Bus by using subscribe(Event.class, ev -> handler);
|
||||
// and you can access things in the global injector module with var thing = inject(Thing.class);
|
||||
// Press Ctrl+R or F10 to execute the contents of this editor
|
||||
|
||||
log.info("Hello {}", client.getGameState());
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Abex
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
import net.runelite.api.*;
|
||||
import net.runelite.api.coords.*;
|
||||
import net.runelite.api.events.*;
|
||||
import net.runelite.api.widgets.*;
|
||||
import net.runelite.client.events.*;
|
||||
import net.runelite.client.game.*;
|
||||
|
||||
var $PANEL = net.runelite.jshell.ShellPanel.INSTANCE;
|
||||
Logger log = $PANEL.getShellLogger();
|
||||
|
||||
static <T> T inject(Class<T> clazz)
|
||||
{
|
||||
return $PANEL.inject(clazz);
|
||||
}
|
||||
|
||||
static void cleanup(Runnable r)
|
||||
{
|
||||
$PANEL.cleanup(r);
|
||||
}
|
||||
|
||||
var $EVENT_BUS = inject(net.runelite.client.eventbus.EventBus.class);
|
||||
static <T> void subscribe(Class<T> eventType, Consumer<T> subscriber, float priority)
|
||||
{
|
||||
var sub = $EVENT_BUS.register(eventType, subscriber, priority);
|
||||
cleanup(() -> $EVENT_BUS.unregister(sub));
|
||||
}
|
||||
static <T> void subscribe(Class<T> eventType, Consumer<T> subscriber)
|
||||
{
|
||||
var sub = $EVENT_BUS.register(eventType, subscriber, 0.f);
|
||||
cleanup(() -> $EVENT_BUS.unregister(sub));
|
||||
}
|
||||
|
||||
var client = inject(Client.class);
|
||||
var clientThread = inject(ClientThread.class);
|
||||
var configManager = inject(ConfigManager.class);
|
||||
|
||||
Reference in New Issue
Block a user