IDEA: run debug server when running dev server in debug mode, connect to this server automatically from the web page

This commit is contained in:
Alexey Andreev 2018-12-17 19:31:53 +03:00
parent b1e04da597
commit 66126856a2
15 changed files with 343 additions and 87 deletions

View File

@ -54,7 +54,6 @@
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
<optional>true</optional>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -0,0 +1,27 @@
/*
* Copyright 2018 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
window.addEventListener("message", function(event) {
if (event.source !== window) {
return;
}
var data = event.data;
if (typeof data.teavmDebugger !== "undefined") {
chrome.runtime.sendMessage({ command: "debug", port: data.teavmDebugger.port });
}
}, false);
window.postMessage({ teavmDebuggerRequest: true }, "*");

View File

@ -1,15 +1,16 @@
debuggerAgentMap = {}; debuggerAgentMap = {};
chrome.browserAction.onClicked.addListener(function(tab) { chrome.browserAction.onClicked.addListener(function(tab) {
new DebuggerAgent(tab).attach(); new DebuggerAgent(tab, 2357).attach();
}); });
function DebuggerAgent(tab) { function DebuggerAgent(tab, port) {
this.pendingMessages = []; this.pendingMessages = [];
this.connection = null; this.connection = null;
this.tab = null; this.tab = null;
this.debuggee = { tabId : tab.id }; this.debuggee = { tabId : tab.id };
this.attachedToDebugger = false; this.attachedToDebugger = false;
this.messageBuffer = ""; this.messageBuffer = "";
this.port = port;
debuggerAgentMap[tab.id] = this; debuggerAgentMap[tab.id] = this;
} }
DebuggerAgent.MAX_MESSAGE_SIZE = 65534; DebuggerAgent.MAX_MESSAGE_SIZE = 65534;
@ -20,12 +21,12 @@ DebuggerAgent.prototype.attach = function() {
}.bind(this, this.connectToServer.bind(this))); }.bind(this, this.connectToServer.bind(this)));
}; };
DebuggerAgent.prototype.connectToServer = function() { DebuggerAgent.prototype.connectToServer = function() {
this.connection = new WebSocket("ws://localhost:2357/"); this.connection = new WebSocket("ws://localhost:" + this.port + "/");
this.connection.onmessage = function(event) { this.connection.onmessage = function(event) {
var str = event.data; var str = event.data;
var ctl = str.substring(0, 1); var ctl = str.substring(0, 1);
this.messageBuffer += str.substring(1); this.messageBuffer += str.substring(1);
if (ctl == '.') { if (ctl === '.') {
this.receiveMessage(JSON.parse(this.messageBuffer)); this.receiveMessage(JSON.parse(this.messageBuffer));
this.messageBuffer = ""; this.messageBuffer = "";
} }
@ -95,4 +96,10 @@ chrome.debugger.onDetach.addListener(function(source) {
agent.attachedToDebugger = false; agent.attachedToDebugger = false;
agent.disconnect(); agent.disconnect();
} }
});
chrome.runtime.onMessage.addListener(function(message, sender, callback) {
if (message.command === "debug") {
new DebuggerAgent(sender.tab, message.port).attach();
}
}); });

View File

@ -3,9 +3,9 @@
"name": "TeaVM debugger agent", "name": "TeaVM debugger agent",
"description": "TeaVM debugger agent, that sends RDP commands over WebSocket", "description": "TeaVM debugger agent, that sends RDP commands over WebSocket",
"version": "0.2", "version": "0.6.0",
"permissions" : ["debugger", "activeTab", "tabs"], "permissions" : ["debugger", "activeTab", "tabs", "*://*/*"],
"browser_action" : { "browser_action" : {
"default_icon": "teavm-16.png", "default_icon": "teavm-16.png",
@ -14,5 +14,12 @@
"background": { "background": {
"scripts": ["main.js"] "scripts": ["main.js"]
} },
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*", "file://*/*"],
"js": ["contentscript.js"]
}
]
} }

View File

@ -79,6 +79,7 @@ public class CodeServlet extends HttpServlet {
private boolean indicator; private boolean indicator;
private boolean automaticallyReloaded; private boolean automaticallyReloaded;
private int port; private int port;
private int debugPort;
private Map<String, Supplier<InputStream>> sourceFileCache = new HashMap<>(); private Map<String, Supplier<InputStream>> sourceFileCache = new HashMap<>();
@ -138,6 +139,10 @@ public class CodeServlet extends HttpServlet {
this.port = port; this.port = port;
} }
public void setDebugPort(int debugPort) {
this.debugPort = debugPort;
}
public void setAutomaticallyReloaded(boolean automaticallyReloaded) { public void setAutomaticallyReloaded(boolean automaticallyReloaded) {
this.automaticallyReloaded = automaticallyReloaded; this.automaticallyReloaded = automaticallyReloaded;
} }
@ -450,10 +455,6 @@ public class CodeServlet extends HttpServlet {
} }
private void addIndicator() { private void addIndicator() {
if (!indicator) {
return;
}
String script = getIndicatorScript(false); String script = getIndicatorScript(false);
try (Writer writer = new OutputStreamWriter(buildTarget.appendToResource(fileName), StandardCharsets.UTF_8)) { try (Writer writer = new OutputStreamWriter(buildTarget.appendToResource(fileName), StandardCharsets.UTF_8)) {
writer.append("\n"); writer.append("\n");
@ -472,6 +473,8 @@ public class CodeServlet extends HttpServlet {
script = script.replace("BOOT_FLAG", Boolean.toString(boot)); script = script.replace("BOOT_FLAG", Boolean.toString(boot));
script = script.replace("RELOAD_FLAG", Boolean.toString(automaticallyReloaded)); script = script.replace("RELOAD_FLAG", Boolean.toString(automaticallyReloaded));
script = script.replace("FILE_NAME", "http://localhost:" + port + pathToFile + fileName); script = script.replace("FILE_NAME", "http://localhost:" + port + pathToFile + fileName);
script = script.replace("INDICATOR_FLAG", Boolean.toString(indicator));
script = script.replace("DEBUG_PORT", Integer.toString(debugPort));
return script; return script;
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("IO error occurred writing debug information", e); throw new RuntimeException("IO error occurred writing debug information", e);

View File

@ -46,6 +46,7 @@ public class DevServer {
private Server server; private Server server;
private int port = 9090; private int port = 9090;
private int debugPort;
public void setMainClass(String mainClass) { public void setMainClass(String mainClass) {
this.mainClass = mainClass; this.mainClass = mainClass;
@ -59,6 +60,10 @@ public class DevServer {
this.port = port; this.port = port;
} }
public void setDebugPort(int debugPort) {
this.debugPort = debugPort;
}
public void setPathToFile(String pathToFile) { public void setPathToFile(String pathToFile) {
if (!pathToFile.startsWith("/")) { if (!pathToFile.startsWith("/")) {
pathToFile = "/" + pathToFile; pathToFile = "/" + pathToFile;
@ -122,6 +127,7 @@ public class DevServer {
servlet.setIndicator(indicator); servlet.setIndicator(indicator);
servlet.setAutomaticallyReloaded(reloadedAutomatically); servlet.setAutomaticallyReloaded(reloadedAutomatically);
servlet.setPort(port); servlet.setPort(port);
servlet.setDebugPort(debugPort);
for (DevServerListener listener : listeners) { for (DevServerListener listener : listeners) {
servlet.addListener(listener); servlet.addListener(listener);
} }

View File

@ -16,6 +16,8 @@
(function () { (function () {
var boot = BOOT_FLAG; var boot = BOOT_FLAG;
var reload = RELOAD_FLAG; var reload = RELOAD_FLAG;
var indicatorVisible = INDICATOR_FLAG;
var debugPort = DEBUG_PORT;
function createWebSocket() { function createWebSocket() {
var loc = window.location; var loc = window.location;
@ -121,10 +123,12 @@
document.body.appendChild(indicator.container); document.body.appendChild(indicator.container);
} }
if (document.body) { if (indicatorVisible) {
onLoad(); if (document.body) {
} else { onLoad();
window.addEventListener("load", onLoad); } else {
window.addEventListener("load", onLoad);
}
} }
function startMain() { function startMain() {
@ -164,4 +168,17 @@
if (boot) { if (boot) {
indicator.show("File is not ready, about to compile"); indicator.show("File is not ready, about to compile");
} }
if (debugPort > 0) {
function connectDebugAgent(event) {
if (event.source !== window) {
return;
}
var data = event.data;
if (typeof data.teavmDebuggerRequest !== "undefined") {
window.postMessage({teavmDebugger: {port: debugPort}}, "*");
}
}
window.addEventListener("message", connectDebugAgent);
}
})(); })();

View File

@ -94,7 +94,7 @@
<target> <target>
<mkdir dir="${basedir}/dependencies/"/> <mkdir dir="${basedir}/dependencies/"/>
<get src="https://plugins.jetbrains.com/plugin/download?updateId=42362" <get src="https://plugins.jetbrains.com/plugin/download?updateId=42362"
dest="${basedir}/dependencies/scala.zip"/> dest="${basedir}/dependencies/scala.zip" skipexisting="true"/>
<unzip src="${basedir}/dependencies/scala.zip" dest="${basedir}/dependencies"/> <unzip src="${basedir}/dependencies/scala.zip" dest="${basedir}/dependencies"/>
</target> </target>
</configuration> </configuration>

View File

@ -16,6 +16,8 @@
package org.teavm.idea.debug; package org.teavm.idea.debug;
import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType; import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.icons.AllIcons; import com.intellij.icons.AllIcons;
import com.intellij.openapi.extensions.ExtensionPoint; import com.intellij.openapi.extensions.ExtensionPoint;
import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.extensions.Extensions;
@ -49,6 +51,7 @@ public class TeaVMDebugProcess extends XDebugProcess {
private final int port; private final int port;
private ChromeRDPServer debugServer; private ChromeRDPServer debugServer;
ConcurrentMap<Breakpoint, XBreakpoint<?>> breakpointMap = new ConcurrentHashMap<>(); ConcurrentMap<Breakpoint, XBreakpoint<?>> breakpointMap = new ConcurrentHashMap<>();
public ExecutionConsole console;
public TeaVMDebugProcess(@NotNull XDebugSession session, int port) { public TeaVMDebugProcess(@NotNull XDebugSession session, int port) {
super(session); super(session);
@ -188,4 +191,10 @@ public class TeaVMDebugProcess extends XDebugProcess {
public XBreakpointHandler<?>[] getBreakpointHandlers() { public XBreakpointHandler<?>[] getBreakpointHandlers() {
return breakpointHandlers.toArray(new XBreakpointHandler<?>[0]); return breakpointHandlers.toArray(new XBreakpointHandler<?>[0]);
} }
@NotNull
@Override
public ExecutionConsole createConsole() {
return console != null ? console : super.createConsole();
}
} }

View File

@ -26,4 +26,5 @@ public class DevServerConfiguration {
public int port; public int port;
public String pathToFile; public String pathToFile;
public String fileName; public String fileName;
public int debugPort;
} }

View File

@ -125,6 +125,9 @@ public class DevServerRunner extends UnicastRemoteObject implements DevServerMan
case "-f": case "-f":
server.setFileName(args[++i]); server.setFileName(args[++i]);
break; break;
case "-P":
server.setDebugPort(Integer.parseInt(args[++i]));
break;
} }
} }
server.setClassPath(classPath.toArray(new String[0])); server.setClassPath(classPath.toArray(new String[0]));
@ -179,6 +182,11 @@ public class DevServerRunner extends UnicastRemoteObject implements DevServerMan
arguments.add(entry); arguments.add(entry);
} }
if (options.debugPort > 0) {
arguments.add("-P");
arguments.add(Integer.toString(options.debugPort));
}
ProcessBuilder builder = new ProcessBuilder(arguments.toArray(new String[0])); ProcessBuilder builder = new ProcessBuilder(arguments.toArray(new String[0]));
Process process = builder.start(); Process process = builder.start();
BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(process.getInputStream(), BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(process.getInputStream(),

View File

@ -21,12 +21,11 @@ import com.intellij.execution.ExecutionResult;
import com.intellij.execution.Executor; import com.intellij.execution.Executor;
import com.intellij.execution.configurations.RunProfileState; import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.configurations.SearchScopeProvider; import com.intellij.execution.configurations.SearchScopeProvider;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.filters.TextConsoleBuilder; import com.intellij.execution.filters.TextConsoleBuilder;
import com.intellij.execution.filters.TextConsoleBuilderFactory; import com.intellij.execution.filters.TextConsoleBuilderFactory;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner; import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.util.JavaParametersUtil; import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.openapi.module.Module; import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
@ -36,24 +35,24 @@ import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.net.Socket;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects; import java.util.Objects;
import java.util.Random;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.teavm.idea.DaemonUtil;
import org.teavm.idea.DevServerRunnerListener;
import org.teavm.idea.devserver.ui.TeaVMDevServerConsole; import org.teavm.idea.devserver.ui.TeaVMDevServerConsole;
public class TeaVMDevServerRunState implements RunProfileState { public class TeaVMDevServerRunState implements RunProfileState {
private final TeaVMDevServerConfiguration configuration; private final TeaVMDevServerConfiguration configuration;
private final TextConsoleBuilder consoleBuilder; private final TextConsoleBuilder consoleBuilder;
private final Project project;
public TeaVMDevServerRunState(@NotNull ExecutionEnvironment environment, public TeaVMDevServerRunState(@NotNull ExecutionEnvironment environment,
@NotNull TeaVMDevServerConfiguration configuration) { @NotNull TeaVMDevServerConfiguration configuration) {
this.configuration = configuration; this.configuration = configuration;
Project project = environment.getProject(); project = environment.getProject();
GlobalSearchScope searchScope = SearchScopeProvider.createSearchScope(project, environment.getRunProfile()); GlobalSearchScope searchScope = SearchScopeProvider.createSearchScope(project, environment.getRunProfile());
consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project, searchScope); consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project, searchScope);
} }
@ -83,15 +82,44 @@ public class TeaVMDevServerRunState implements RunProfileState {
config.mainClass = configuration.getMainClass(); config.mainClass = configuration.getMainClass();
config.maxHeap = configuration.getMaxHeap(); config.maxHeap = configuration.getMaxHeap();
if (executor.getId().equals(DefaultDebugExecutor.EXECUTOR_ID)) {
config.debugPort = choosePort();
}
TeaVMProcessHandler processHandler;
ExecutionResult executionResult;
try { try {
TeaVMDevServerConsole console = new TeaVMDevServerConsole(consoleBuilder.getConsole()); TeaVMDevServerConsole console = new TeaVMDevServerConsole(consoleBuilder.getConsole());
ProcessHandlerImpl processHandler = new ProcessHandlerImpl(config, console); processHandler = new TeaVMProcessHandler(config, console);
console.getUnderlyingConsole().attachToProcess(processHandler); console.getUnderlyingConsole().attachToProcess(processHandler);
processHandler.start(); processHandler.start();
return new DefaultExecutionResult(console, processHandler); executionResult = new DefaultExecutionResult(console, processHandler);
} catch (IOException e) { } catch (IOException e) {
throw new ExecutionException(e); throw new ExecutionException(e);
} }
return executionResult;
}
private int choosePort() {
Random random = new Random();
int minPort = 10000;
int maxPort = 1 << 16;
for (int i = 0; i < 20; ++i) {
int port = minPort + random.nextInt(maxPort - minPort);
if (isPortAvailable(port)) {
return port;
}
}
throw new RuntimeException("Could not find available port");
}
private boolean isPortAvailable(int port) {
try (Socket ignored = new Socket("localhost", port)) {
return false;
} catch (IOException ignored) {
return true;
}
} }
private String path(VirtualFile file) { private String path(VirtualFile file) {
@ -103,63 +131,4 @@ public class TeaVMDevServerRunState implements RunProfileState {
} }
return file.getCanonicalPath(); return file.getCanonicalPath();
} }
class ProcessHandlerImpl extends ProcessHandler implements DevServerRunnerListener {
private DevServerConfiguration config;
private TeaVMDevServerConsole console;
private DevServerInfo info;
ProcessHandlerImpl(DevServerConfiguration config, TeaVMDevServerConsole console) {
this.config = config;
this.console = console;
}
void start() throws IOException {
info = DevServerRunner.start(DaemonUtil.detectClassPath().toArray(new String[0]), config, this);
console.setServerManager(info.server);
startNotify();
}
@Override
protected void destroyProcessImpl() {
info.process.destroy();
}
@Override
protected void detachProcessImpl() {
try {
info.server.stop();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public boolean detachIsDefault() {
return true;
}
@Nullable
@Override
public OutputStream getProcessInput() {
return null;
}
@Override
public void error(String text) {
console.getUnderlyingConsole().print(text + System.lineSeparator(), ConsoleViewContentType.ERROR_OUTPUT);
}
@Override
public void info(String text) {
console.getUnderlyingConsole().print(text + System.lineSeparator(), ConsoleViewContentType.NORMAL_OUTPUT);
}
@Override
public void stopped(int code) {
console.stop();
notifyProcessTerminated(code);
}
}
} }

View File

@ -20,11 +20,21 @@ import com.intellij.execution.ExecutionResult;
import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.configurations.RunProfileState; import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.configurations.RunnerSettings; import com.intellij.execution.configurations.RunnerSettings;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.GenericProgramRunner; import com.intellij.execution.runners.GenericProgramRunner;
import com.intellij.execution.runners.RunContentBuilder;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.xdebugger.XDebugProcess;
import com.intellij.xdebugger.XDebugProcessStarter;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerManager;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.teavm.idea.debug.TeaVMDebugProcess;
public class TeaVMDevServerRunner extends GenericProgramRunner<RunnerSettings> { public class TeaVMDevServerRunner extends GenericProgramRunner<RunnerSettings> {
@NotNull @NotNull
@ -47,6 +57,32 @@ public class TeaVMDevServerRunner extends GenericProgramRunner<RunnerSettings> {
return null; return null;
} }
return null; RunContentDescriptor runContent = new RunContentBuilder(executionResult, environment).showRunContent(null);
int debugPort = ((TeaVMProcessHandler) executionResult.getProcessHandler()).config.debugPort;
ExecutionConsole console = runContent.getExecutionConsole();
ProcessHandler processHandler = runContent.getProcessHandler();
if (debugPort > 0) {
XDebuggerManager debuggerManager = XDebuggerManager.getInstance(environment.getProject());
XDebugSession debugSession = debuggerManager.startSession(environment, new XDebugProcessStarter() {
@NotNull
@Override
public XDebugProcess start(@NotNull XDebugSession session) {
TeaVMDebugProcess debugProcess = new TeaVMDebugProcess(session, debugPort);
debugProcess.console = console;
return debugProcess;
}
});
runContent = debugSession.getRunContentDescriptor();
ProcessHandler debugProcessHandler = debugSession.getDebugProcess().getProcessHandler();
debugProcessHandler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(@NotNull ProcessEvent event) {
processHandler.destroyProcess();
}
});
}
return runContent;
} }
} }

View File

@ -0,0 +1,85 @@
/*
* Copyright 2018 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.idea.devserver;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.ConsoleViewContentType;
import java.io.IOException;
import java.io.OutputStream;
import org.jetbrains.annotations.Nullable;
import org.teavm.idea.DaemonUtil;
import org.teavm.idea.DevServerRunnerListener;
import org.teavm.idea.devserver.ui.TeaVMDevServerConsole;
class TeaVMProcessHandler extends ProcessHandler implements DevServerRunnerListener {
DevServerConfiguration config;
private TeaVMDevServerConsole console;
private DevServerInfo info;
TeaVMProcessHandler(DevServerConfiguration config, TeaVMDevServerConsole console) {
this.config = config;
this.console = console;
}
void start() throws IOException {
info = DevServerRunner.start(DaemonUtil.detectClassPath().toArray(new String[0]), config, this);
console.setServerManager(info.server);
startNotify();
Runtime.getRuntime().addShutdownHook(new Thread(() -> info.process.destroy()));
}
@Override
protected void destroyProcessImpl() {
info.process.destroy();
}
@Override
protected void detachProcessImpl() {
try {
info.server.stop();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public boolean detachIsDefault() {
return true;
}
@Nullable
@Override
public OutputStream getProcessInput() {
return null;
}
@Override
public void error(String text) {
console.getUnderlyingConsole().print(text + System.lineSeparator(), ConsoleViewContentType.ERROR_OUTPUT);
}
@Override
public void info(String text) {
console.getUnderlyingConsole().print(text + System.lineSeparator(), ConsoleViewContentType.NORMAL_OUTPUT);
}
@Override
public void stopped(int code) {
console.stop();
notifyProcessTerminated(code);
}
}

View File

@ -15,8 +15,12 @@
*/ */
package org.teavm.idea.devserver.ui; package org.teavm.idea.devserver.ui;
import com.intellij.execution.filters.Filter;
import com.intellij.execution.filters.HyperlinkInfo;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleView;
import com.intellij.execution.ui.ExecutionConsole; import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.openapi.actionSystem.AnAction;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.GridBagLayout; import java.awt.GridBagLayout;
import java.rmi.RemoteException; import java.rmi.RemoteException;
@ -26,11 +30,13 @@ import javax.swing.JButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JProgressBar; import javax.swing.JProgressBar;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.teavm.idea.devserver.DevServerBuildResult; import org.teavm.idea.devserver.DevServerBuildResult;
import org.teavm.idea.devserver.DevServerManager; import org.teavm.idea.devserver.DevServerManager;
import org.teavm.idea.devserver.DevServerManagerListener; import org.teavm.idea.devserver.DevServerManagerListener;
public class TeaVMDevServerConsole extends JPanel implements ExecutionConsole { public class TeaVMDevServerConsole extends JPanel implements ConsoleView {
private ConsoleView underlyingConsole; private ConsoleView underlyingConsole;
private DevServerManager serverManager; private DevServerManager serverManager;
private ServerListenerImpl serverListener; private ServerListenerImpl serverListener;
@ -135,6 +141,82 @@ public class TeaVMDevServerConsole extends JPanel implements ExecutionConsole {
rebuildButton.setEnabled(false); rebuildButton.setEnabled(false);
} }
@Override
public void print(@NotNull String s, @NotNull ConsoleViewContentType consoleViewContentType) {
underlyingConsole.print(s, consoleViewContentType);
}
@Override
public void clear() {
underlyingConsole.clear();
}
@Override
public void scrollTo(int i) {
underlyingConsole.scrollTo(i);
}
@Override
public void attachToProcess(ProcessHandler processHandler) {
underlyingConsole.attachToProcess(processHandler);
}
@Override
public void setOutputPaused(boolean b) {
underlyingConsole.setOutputPaused(b);
}
@Override
public boolean isOutputPaused() {
return underlyingConsole.isOutputPaused();
}
@Override
public boolean hasDeferredOutput() {
return underlyingConsole.hasDeferredOutput();
}
@Override
public void performWhenNoDeferredOutput(@NotNull Runnable runnable) {
underlyingConsole.performWhenNoDeferredOutput(runnable);
}
@Override
public void setHelpId(@NotNull String s) {
underlyingConsole.setHelpId(s);
}
@Override
public void addMessageFilter(@NotNull Filter filter) {
underlyingConsole.addMessageFilter(filter);
}
@Override
public void printHyperlink(@NotNull String s, @Nullable HyperlinkInfo hyperlinkInfo) {
underlyingConsole.printHyperlink(s, hyperlinkInfo);
}
@Override
public int getContentSize() {
return underlyingConsole.getContentSize();
}
@Override
public boolean canPause() {
return underlyingConsole.canPause();
}
@NotNull
@Override
public AnAction[] createConsoleActions() {
return underlyingConsole.createConsoleActions();
}
@Override
public void allowHeavyFilters() {
underlyingConsole.allowHeavyFilters();
}
class ServerListenerImpl extends UnicastRemoteObject implements DevServerManagerListener { class ServerListenerImpl extends UnicastRemoteObject implements DevServerManagerListener {
private NumberFormat percentFormat = NumberFormat.getPercentInstance(); private NumberFormat percentFormat = NumberFormat.getPercentInstance();