summaryrefslogtreecommitdiff
path: root/src/main/scala/workbench/Plugin.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/workbench/Plugin.scala')
-rw-r--r--src/main/scala/workbench/Plugin.scala128
1 files changed, 108 insertions, 20 deletions
diff --git a/src/main/scala/workbench/Plugin.scala b/src/main/scala/workbench/Plugin.scala
index 3a1b175..dd3cab9 100644
--- a/src/main/scala/workbench/Plugin.scala
+++ b/src/main/scala/workbench/Plugin.scala
@@ -1,9 +1,15 @@
package com.lihaoyi.workbench
+import scala.concurrent.ExecutionContext.Implicits.global
import sbt._
import sbt.Keys._
import autowire._
-import upickle.Js
-import scala.concurrent.ExecutionContext.Implicits.global
+import scala.scalajs.sbtplugin.ScalaJSPlugin.ScalaJSKeys
+import scala.scalajs.tools.io._
+import scala.scalajs.tools.optimizer.ScalaJSOptimizer
+import scala.scalajs.sbtplugin.ScalaJSPluginInternal._
+import scala.scalajs.sbtplugin.Implicits._
+
+import ScalaJSKeys._
object Plugin extends sbt.Plugin {
val refreshBrowsers = taskKey[Unit]("Sends a message to all connected web pages asking them to refresh the page")
@@ -15,6 +21,11 @@ object Plugin extends sbt.Plugin {
val bootSnippet = settingKey[String]("piece of javascript to make things happen")
val updatedJS = taskKey[List[String]]("Provides the addresses of the JS files that have changed")
+ val sjs = inputKey[Unit]("Run a command via the sjs REPL, which compiles it to Javascript and runs it in the browser")
+ val replFile = taskKey[File]("The temporary file which holds the source code for the currently executing sjs REPL")
+ val sjsReset = taskKey[Unit]("Reset the currently executing sjs REPL")
+
+ lazy val replHistory = collection.mutable.Buffer.empty[String]
val workbenchSettings = Seq(
localUrl := ("localhost", 12345),
@@ -77,23 +88,9 @@ object Plugin extends sbt.Plugin {
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) = (.*?\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 || ")
- }
- IO.write(new sbt.File(path.drop(prefix.length) + ".js"), s.getBytes)
+ 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", None).call()
}
}
@@ -103,5 +100,96 @@ object Plugin extends sbt.Plugin {
server.value.kill()
state
}}
- )
+ ) ++ inConfig(Compile)(Seq(
+ artifactPath in sjs := crossTarget.value / "repl.js",
+ replFile := {
+ val f = sourceManaged.value / "repl.scala"
+ println("Creating replFile\n" + replHistory.mkString("\n"))
+ sbt.IO.write(f, replHistory.mkString("\n"))
+ f
+ },
+ sources in Compile += replFile.value,
+ sjs <<= Def.inputTaskDyn {
+ import sbt.complete.Parsers._
+ val str = sbt.complete.Parsers.any.*.parsed.mkString
+ val newSnippet = s"""
+ @scalajs.js.annotation.JSExport object O${replHistory.length}{
+ $str
+ };
+ import O${replHistory.length}._
+ """
+ replHistory.append(newSnippet)
+ Def.taskDyn {
+ // Basically C&Ped from fastOptJS, since we dont want this
+ // special mode from triggering updateBrowsers or similar
+ val s = streams.value
+ val output = (artifactPath in sjs).value
+
+ val taskCache = WritableFileVirtualTextFile(s.cacheDirectory / "fastopt-js")
+
+ sbt.IO.createDirectory(output.getParentFile)
+
+ val relSourceMapBase =
+ if ((relativeSourceMaps in fastOptJS).value)
+ Some(output.getParentFile.toURI())
+ else None
+
+ import ScalaJSOptimizer._
+
+ (scalaJSOptimizer in fastOptJS).value.optimizeCP(
+ Inputs(input = (preLinkClasspath in fastOptJS).value),
+ OutputConfig(
+ output = WritableFileVirtualJSFile(output),
+ cache = None,
+ wantSourceMap = (emitSourceMaps in fastOptJS).value,
+ relativizeSourceMapBase = relSourceMapBase,
+ checkIR = (checkScalaJSIR in fastOptJS).value,
+ disableInliner = (inliningMode in fastOptJS).value.disabled,
+ batchInline = (inliningMode in fastOptJS).value.batch),
+ s.log
+ )
+ // end of C&P
+ val outPath = sbt.IO.relativize(
+ baseDirectory.value,
+ (artifactPath in sjs).value
+ ).get
+
+ sbt.IO.write(
+ (artifactPath in sjs).value,
+ sbt.IO.read(output) + s"\n\nO${replHistory.length - 1}()"
+ )
+ Def.task {
+ server.value.Wire[Api].run(
+ s"http://localhost:12345/$outPath",
+ None
+ ).call()
+ ()
+ }
+ }.dependsOn(packageJSDependencies, packageLauncher, compile)
+ },
+ sjsReset := {
+ println("Clearing sjs REPL History")
+ replHistory.clear()
+ },
+ sjsReset <<= sjsReset.triggeredBy(fastOptJS)
+ ))
+
+ 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
+ }
}