From a57376f40b539260f1d13d3278f10e16a4a2fbe1 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Wed, 24 Sep 2014 20:19:19 -0700 Subject: wip --- example/build.sbt | 4 ++- .../src/main/scala/example/ScalaJSExample.scala | 32 +++++++++++----------- src/main/scala/workbench/Plugin.scala | 26 +++++++++++++++++- src/main/scala/workbench/Server.scala | 4 ++- 4 files changed, 47 insertions(+), 19 deletions(-) diff --git a/example/build.sbt b/example/build.sbt index ceefedc..0bca703 100644 --- a/example/build.sbt +++ b/example/build.sbt @@ -21,5 +21,7 @@ libraryDependencies ++= Seq( bootSnippet := "ScalaJSExample().main();" -updateBrowsers <<= updateBrowsers.triggeredBy(ScalaJSKeys.fastOptJS in Compile) +ScalaJSKeys.inliningMode := scala.scalajs.sbtplugin.InliningMode.Off + +spliceBrowsers <<= spliceBrowsers.triggeredBy(ScalaJSKeys.fastOptJS in Compile) diff --git a/example/src/main/scala/example/ScalaJSExample.scala b/example/src/main/scala/example/ScalaJSExample.scala index 7a41c44..9df7b18 100644 --- a/example/src/main/scala/example/ScalaJSExample.scala +++ b/example/src/main/scala/example/ScalaJSExample.scala @@ -7,6 +7,7 @@ case class Point(x: Int, y: Int){ def +(p: Point) = Point(x + p.x, y + p.y) def /(d: Int) = Point(x / d, y / d) } + // Seems like you need this for sbt ~fastOptJS to work // mkdir ~/.sbt/0.13/plugins/target/scala-2.10/sbt-0.13/classes @JSExport @@ -17,31 +18,30 @@ object ScalaJSExample { .getContext("2d") .asInstanceOf[dom.CanvasRenderingContext2D] - var count = 0 - var p = Point(0, 0) - val corners = Seq(Point(255, 255), Point(0, 255), Point(128, 0)) + var p = Point(128, 128) + def color = "black" + var enemies = List.fill(10)(Point(util.Random.nextInt(255), util.Random.nextInt(255))) def clear() = { - ctx.fillStyle = "white" + ctx.fillStyle = color ctx.fillRect(0, 0, 255, 255) } - def run = for (i <- 0 until 10){ - if (count % 30000 == 0) clear() - count += 1 - p = (p + corners(Random.nextInt(3))) / 2 - val height = 512.0 / (255 + p.y) - val r = (p.x * height).toInt - val g = ((255-p.x) * height).toInt - val b = p.y - ctx.fillStyle = s"rgb($g, $r, $b)" - - ctx.fillRect(p.x, p.y, 1, 1) + def run = { + clear() + ctx.fillStyle = "cyan" + p = Point(p.x, (p.y + 2) % 255) + ctx.fillRect(p.x, p.y, 5, 20) + enemies = for (enemy <- enemies) yield { + ctx.fillStyle = "red" + ctx.fillRect(enemy.x, enemy.y, 10, 10) + Point((enemy.x + 1) % 255, (enemy.y + 1) % 255) + } } @JSExport def main(): Unit = { dom.console.log("main") - dom.setInterval(() => run, 50) + dom.setInterval(() => run, 10) } } diff --git a/src/main/scala/workbench/Plugin.scala b/src/main/scala/workbench/Plugin.scala index 8e122fe..85b8f39 100644 --- a/src/main/scala/workbench/Plugin.scala +++ b/src/main/scala/workbench/Plugin.scala @@ -7,7 +7,8 @@ import scala.concurrent.ExecutionContext.Implicits.global object Plugin extends sbt.Plugin { val refreshBrowsers = taskKey[Unit]("Sends a message to all connected web pages asking them to refresh the page") - val updateBrowsers = taskKey[Unit]("partially resets some of the stuff in the browser") + val updateBrowsers = taskKey[Unit]("Partially resets some of the stuff in the browser") + val spliceBrowsers = taskKey[Unit]("Attempts to do a live update of the code running in the browser while maintaining state") val localUrl = settingKey[(String, Int)]("localUrl") private[this] val server = settingKey[Server]("local websocket server") @@ -65,6 +66,29 @@ object Plugin extends sbt.Plugin { } } }, + spliceBrowsers := { + val changed = updatedJS.value + // There is no point in clearing the browser if no js files have changed. + if (changed.length > 0) { + for{ + path <- changed + if !path.endsWith(".js.js") + }{ + + streams.value.log.info("workbench: Splicing " + path) + val prefix = "http://localhost:12345/" + var s = IO.read(new sbt.File(path.drop(prefix.length))) + + s = s.replace("\nvar ScalaJS = ", "\nvar ScalaJS = ScalaJS || ") + s = s.replaceAll("\n(ScalaJS\\.c\\.[a-zA-Z_$0-9]+\\.prototype) = ", "/*X*/\n$1 = $1 || ") + for(char <- Seq("d", "c", "h", "i", "n", "m")){ + s = s.replaceAll("\n(ScalaJS\\." + char + "\\.[a-zA-Z_$0-9]+) = ", "\n$1 = $1 || ") + } + IO.write(new sbt.File(path.drop(prefix.length) + ".js"), s.getBytes) + server.value.Wire[Api].run(path + ".js", None).call() + } + } + }, server := new Server(localUrl.value._1, localUrl.value._2, bootSnippet.value), (onUnload in Global) := { (onUnload in Global).value.compose{ state => server.value.kill() diff --git a/src/main/scala/workbench/Server.scala b/src/main/scala/workbench/Server.scala index 4d37073..8d05037 100644 --- a/src/main/scala/workbench/Server.scala +++ b/src/main/scala/workbench/Server.scala @@ -3,11 +3,12 @@ package com.lihaoyi.workbench import akka.actor.{ActorRef, Actor, ActorSystem} import com.typesafe.config.ConfigFactory import sbt.IO +import spray.httpx.encoding.Gzip import spray.routing.SimpleRoutingApp import akka.actor.ActorDSL._ import upickle.{Reader, Writer, Js} -import spray.http.{AllOrigins, HttpResponse} +import spray.http.{HttpEntity, AllOrigins, HttpResponse} import spray.http.HttpHeaders.`Access-Control-Allow-Origin` import concurrent.duration._ import scala.concurrent.Future @@ -94,6 +95,7 @@ class Server(url: String, port: Int, bootSnippet: String) extends SimpleRoutingA } } ~ getFromDirectory(".") + } ~ post { path("notifications") { ctx => -- cgit v1.2.3