mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
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:
parent
b1e04da597
commit
66126856a2
|
@ -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>
|
||||||
|
|
||||||
|
|
27
tools/chrome-rdp/src/main/js/chrome/contentscript.js
Normal file
27
tools/chrome-rdp/src/main/js/chrome/contentscript.js
Normal 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 }, "*");
|
|
@ -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();
|
||||||
|
}
|
||||||
});
|
});
|
|
@ -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"]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
})();
|
})();
|
|
@ -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>
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user