summaryrefslogtreecommitdiff
path: root/src/main/scala/workbench/WorkbenchSplicePlugin.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/workbench/WorkbenchSplicePlugin.scala')
-rw-r--r--src/main/scala/workbench/WorkbenchSplicePlugin.scala88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/main/scala/workbench/WorkbenchSplicePlugin.scala b/src/main/scala/workbench/WorkbenchSplicePlugin.scala
new file mode 100644
index 0000000..9d68ad3
--- /dev/null
+++ b/src/main/scala/workbench/WorkbenchSplicePlugin.scala
@@ -0,0 +1,88 @@
+package com.lihaoyi.workbench
+import scala.concurrent.ExecutionContext.Implicits.global
+import sbt._
+import sbt.Keys._
+import autowire._
+import org.scalajs.sbtplugin.ScalaJSPlugin
+import org.scalajs.core.tools.io._
+import org.scalajs.sbtplugin.ScalaJSPluginInternal._
+import org.scalajs.sbtplugin.Implicits._
+
+object WorkbenchSplicePlugin extends AutoPlugin {
+
+ override def requires = WorkbenchPlugin
+
+ object autoImport {
+ val updatedJS = taskKey[List[String]]("Provides the addresses of the JS files that have changed")
+ val spliceBrowsers = taskKey[Unit]("Attempts to do a live update of the code running in the browser while maintaining state")
+ }
+ import autoImport._
+ import WorkbenchBasePlugin.autoImport._
+ import WorkbenchBasePlugin.server
+ import ScalaJSPlugin.AutoImport._
+
+ val spliceSettings = Seq(
+ updatedJS := {
+ var files: List[String] = Nil
+ ((crossTarget in Compile).value * "*.js").get.foreach {
+ (x: File) =>
+ streams.value.log.info("workbench: Checking " + x.getName)
+ FileFunction.cached(streams.value.cacheDirectory / x.getName, FilesInfo.lastModified, FilesInfo.lastModified) {
+ (f: Set[File]) =>
+ val fsPath = f.head.getAbsolutePath.drop(new File("").getAbsolutePath.length)
+ files = fsPath :: files
+ f
+ }(Set(x))
+ }
+ files
+ },
+ updatedJS := {
+ val paths = updatedJS.value
+ val url = localUrl.value
+ paths.map { path =>
+ s"http://${url._1}:${url._2}$path"
+ }
+ },
+ 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 url = localUrl.value
+ val prefix = s"http://${url._1}:${url._2}/"
+ val s = munge(sbt.IO.read(new sbt.File(path.drop(prefix.length))))
+
+ sbt.IO.write(new sbt.File(path.drop(prefix.length) + ".js"), s.getBytes)
+ server.value.Wire[Api].run(path + ".js").call()
+ }
+ }
+ },
+ spliceBrowsers <<= spliceBrowsers.triggeredBy(fastOptJS in Compile)
+ )
+
+ override def projectSettings = spliceSettings
+
+ def munge(s0: String) = {
+ var s = s0
+ s = s.replace("\nvar ScalaJS = ", "\nvar ScalaJS = ScalaJS || ")
+ s = s.replaceAll(
+ "\n(ScalaJS\\.c\\.[a-zA-Z_$0-9]+\\.prototype) = (.*?\n)",
+ """
+ |$1 = $1 || {}
+ |(function(){
+ | var newProto = $2
+ | for (var attrname in newProto) { $1[attrname] = newProto[attrname]; }
+ |})()
+ |""".stripMargin
+ )
+ for(char <- Seq("d", "c", "h", "i", "n", "m")){
+ s = s.replaceAll("\n(ScalaJS\\." + char + "\\.[a-zA-Z_$0-9]+) = ", "\n$1 = $1 || ")
+ }
+ s
+ }
+
+}