diff --git a/tools/cli/src/main/java/org/teavm/cli/TeaVMDevServerRunner.java b/tools/cli/src/main/java/org/teavm/cli/TeaVMDevServerRunner.java index 0298db148..8073ac924 100644 --- a/tools/cli/src/main/java/org/teavm/cli/TeaVMDevServerRunner.java +++ b/tools/cli/src/main/java/org/teavm/cli/TeaVMDevServerRunner.java @@ -52,7 +52,7 @@ public final class TeaVMDevServerRunner { .create('f')); options.addOption(OptionBuilder .withArgName("classpath") - .hasArg() + .hasArgs() .withDescription("classpath element (either directory or jar file)") .withLongOpt("classpath") .create('p')); @@ -66,10 +66,16 @@ public final class TeaVMDevServerRunner { .withArgName("number") .hasArg() .withDescription("port (default is 9090)") - .create("port")); + .withLongOpt("port") + .create()); options.addOption(OptionBuilder .withDescription("display indicator on web page") - .create("indicator")); + .withLongOpt("indicator") + .create()); + options.addOption(OptionBuilder + .withDescription("automatically reload page when compilation completes") + .withLongOpt("auto-reload") + .create()); options.addOption(OptionBuilder .withDescription("display more messages on server log") .withLongOpt("verbose") @@ -107,6 +113,7 @@ public final class TeaVMDevServerRunner { parseOutputOptions(); devServer.setIndicator(commandLine.hasOption("indicator")); + devServer.setReloadedAutomatically(commandLine.hasOption("auto-reload")); if (commandLine.hasOption("port")) { try { devServer.setPort(Integer.parseInt(commandLine.getOptionValue("port"))); diff --git a/tools/core/src/main/java/org/teavm/tooling/util/FileSystemWatcher.java b/tools/core/src/main/java/org/teavm/tooling/util/FileSystemWatcher.java index 349f73d6a..d37482961 100644 --- a/tools/core/src/main/java/org/teavm/tooling/util/FileSystemWatcher.java +++ b/tools/core/src/main/java/org/teavm/tooling/util/FileSystemWatcher.java @@ -159,6 +159,9 @@ public class FileSystemWatcher { return Collections.emptyList(); } Path basePath = keysToPath.get(baseKey); + if (basePath == null) { + return Collections.emptyList(); + } Path path = basePath.resolve((Path) event.context()); WatchKey key = pathsToKey.get(path); diff --git a/tools/devserver/src/main/java/org/teavm/devserver/CodeServlet.java b/tools/devserver/src/main/java/org/teavm/devserver/CodeServlet.java index 0b788e5a2..37530efcc 100644 --- a/tools/devserver/src/main/java/org/teavm/devserver/CodeServlet.java +++ b/tools/devserver/src/main/java/org/teavm/devserver/CodeServlet.java @@ -75,6 +75,7 @@ public class CodeServlet extends HttpServlet { private List sourcePath = new ArrayList<>(); private TeaVMToolLog log = new EmptyTeaVMToolLog(); private boolean indicator; + private boolean automaticallyReloaded; private int port; private Map> sourceFileCache = new HashMap<>(); @@ -132,6 +133,10 @@ public class CodeServlet extends HttpServlet { this.wsEndpoint = wsEndpoint; } + public void setAutomaticallyReloaded(boolean automaticallyReloaded) { + this.automaticallyReloaded = automaticallyReloaded; + } + @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { String path = req.getPathInfo(); @@ -353,6 +358,9 @@ public class CodeServlet extends HttpServlet { log.info("Starting build"); progressListener.last = 0; progressListener.lastTime = System.currentTimeMillis(); + if (wsEndpoint != null) { + wsEndpoint.progress(0); + } vm.build(buildTarget, fileName); addIndicator(); generateDebug(debugInformationBuilder); @@ -381,6 +389,7 @@ public class CodeServlet extends HttpServlet { script = script.substring(script.indexOf("*/") + 2); script = script.replace("WS_PATH", "localhost:" + port + pathToFile + fileName + ".ws"); script = script.replace("BOOT_FLAG", Boolean.toString(boot)); + script = script.replace("RELOAD_FLAG", Boolean.toString(automaticallyReloaded)); script = script.replace("FILE_NAME", "http://localhost:" + port + pathToFile + fileName); return script; } catch (IOException e) { @@ -510,7 +519,7 @@ public class CodeServlet extends HttpServlet { switch (phase) { case DEPENDENCY_ANALYSIS: start = 0; - end = 500; + end = 400; break; case LINKING: start = 400; diff --git a/tools/devserver/src/main/java/org/teavm/devserver/CodeWsEndpoint.java b/tools/devserver/src/main/java/org/teavm/devserver/CodeWsEndpoint.java index 9d2382dea..76bc95151 100644 --- a/tools/devserver/src/main/java/org/teavm/devserver/CodeWsEndpoint.java +++ b/tools/devserver/src/main/java/org/teavm/devserver/CodeWsEndpoint.java @@ -23,6 +23,8 @@ import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/") public class CodeWsEndpoint { private Session session; + private boolean compiling; + private double progress; @OnOpen public void open(Session session) { @@ -32,13 +34,27 @@ public class CodeWsEndpoint { if (consumer != null) { consumer.accept(this); } + if (compiling) { + sendProgress(progress); + } } public void progress(double value) { - session.getAsyncRemote().sendText("{ \"command\": \"compiling\", \"progress\": " + value + " }"); + if (session != null) { + sendProgress(value); + } + compiling = true; + progress = value; } public void complete(boolean success) { - session.getAsyncRemote().sendText("{ \"command\": \"complete\", \"success\": " + success + " }"); + if (session != null) { + session.getAsyncRemote().sendText("{ \"command\": \"complete\", \"success\": " + success + " }"); + } + compiling = false; + } + + private void sendProgress(double value) { + session.getAsyncRemote().sendText("{ \"command\": \"compiling\", \"progress\": " + value + " }"); } } diff --git a/tools/devserver/src/main/java/org/teavm/devserver/DevServer.java b/tools/devserver/src/main/java/org/teavm/devserver/DevServer.java index 507c00d1b..8aa43a639 100644 --- a/tools/devserver/src/main/java/org/teavm/devserver/DevServer.java +++ b/tools/devserver/src/main/java/org/teavm/devserver/DevServer.java @@ -37,10 +37,11 @@ import org.teavm.tooling.TeaVMToolLog; public class DevServer { private String mainClass; private String[] classPath; - private String pathToFile = ""; + private String pathToFile = "/"; private String fileName = "classes.js"; private List sourcePath = new ArrayList<>(); private boolean indicator; + private boolean reloadedAutomatically; private TeaVMToolLog log = new ConsoleTeaVMToolLog(false); private Server server; @@ -80,6 +81,10 @@ public class DevServer { this.indicator = indicator; } + public void setReloadedAutomatically(boolean reloadedAutomatically) { + this.reloadedAutomatically = reloadedAutomatically; + } + public List getSourcePath() { return sourcePath; } @@ -99,6 +104,7 @@ public class DevServer { servlet.setLog(log); servlet.getSourcePath().addAll(sourcePath); servlet.setIndicator(indicator); + servlet.setAutomaticallyReloaded(reloadedAutomatically); servlet.setPort(port); context.addServlet(new ServletHolder(servlet), "/*"); diff --git a/tools/devserver/src/main/resources/org/teavm/devserver/indicator.js b/tools/devserver/src/main/resources/org/teavm/devserver/indicator.js index 3e191a329..539041f3c 100644 --- a/tools/devserver/src/main/resources/org/teavm/devserver/indicator.js +++ b/tools/devserver/src/main/resources/org/teavm/devserver/indicator.js @@ -15,6 +15,7 @@ */ (function () { var boot = BOOT_FLAG; + var reload = RELOAD_FLAG; function createWebSocket() { var loc = window.location; @@ -90,7 +91,7 @@ timer: void 0, show: function(text, timeout) { - this.container.style.display = ""; + this.container.style.display = "block"; this.label.innerText = text; if (this.timer) { clearTimeout(this.timer); @@ -111,14 +112,27 @@ hideProgress() { this.progress.container.style.display = "none"; - } + }, }; } var indicator = createIndicator(); - window.addEventListener("load", function() { + function onLoad() { document.body.appendChild(indicator.container); - }); + } + + if (document.body) { + onLoad(); + } else { + window.addEventListener("load", onLoad); + } + + function startMain() { + ws.close(); + window.removeEventListener("load", onLoad); + document.body.removeChild(indicator.container); + main(); + } var ws = createWebSocket(); ws.onmessage = function(event) { @@ -131,12 +145,12 @@ case "complete": if (message.success) { indicator.show("Compilation complete", 10); - if (boot) { + if (reload) { + window.location.reload(true); + } else if (boot) { var scriptElem = document.createElement("script"); scriptElem.src = "FILE_NAME"; - scriptElem.onload = function() { - main(); - }; + scriptElem.onload = startMain; document.head.appendChild(scriptElem); } } else {