Merge remote-tracking branch 'runelite/master'
This commit is contained in:
38
runelite-jshell/runelite-jshell.gradle.kts
Normal file
38
runelite-jshell/runelite-jshell.gradle.kts
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Owain van Brakel <https://github.com/Owain94>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
description = "RuneLite JShell"
|
||||
|
||||
dependencies {
|
||||
annotationProcessor(group = "org.projectlombok", name = "lombok", version = "1.18.4")
|
||||
|
||||
compileOnly(group = "org.projectlombok", name = "lombok", version = "1.18.4")
|
||||
|
||||
implementation(group = "com.google.code.findbugs", name = "jsr305", version = "3.0.2")
|
||||
implementation(group = "com.google.inject", name = "guice", version = "4.1.0", classifier = "no_aop")
|
||||
implementation(group = "com.fifesoft", name = "rsyntaxtextarea", version = "3.1.2")
|
||||
implementation(group = "com.fifesoft", name = "autocomplete", version = "3.1.1")
|
||||
implementation(group = "org.slf4j", name = "slf4j-api", version = "1.7.12")
|
||||
}
|
||||
@@ -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 "OPRSShell";
|
||||
}
|
||||
|
||||
@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 OpenOSRS 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