aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Christopher Vogt <oss.nsp@cvogt.org>2017-04-02 15:07:41 -0400
committerGitHub <noreply@github.com>2017-04-02 15:07:41 -0400
commita40300405524c0b4f8bf5959ec06e3fe1e93837f (patch)
tree92807a01d9dd62fccd9903e18ce8765960c91603
parent50f4b1778d9ba3de15433d710d2e61cd1a73337a (diff)
parentcf2c37852a925eb3a31d237bfe00730d8e687686 (diff)
downloadcbt-a40300405524c0b4f8bf5959ec06e3fe1e93837f.tar.gz
cbt-a40300405524c0b4f8bf5959ec06e3fe1e93837f.tar.bz2
cbt-a40300405524c0b4f8bf5959ec06e3fe1e93837f.zip
Merge pull request #477 from cvogt/scalatex
Add Scalatex plugin
-rw-r--r--.gitignore1
-rw-r--r--build/build.scala1
-rw-r--r--examples/scalatex-example/Foo.scala4
-rw-r--r--examples/scalatex-example/docs/build/build.scala14
-rw-r--r--examples/scalatex-example/docs/readme.scalatex21
-rw-r--r--examples/scalatex-example/docs/static/style.css32
-rw-r--r--libraries/scalatex/AbstractMain.scala34
-rw-r--r--libraries/scalatex/build/build.scala16
-rw-r--r--libraries/scalatex/lib.scala76
-rw-r--r--plugins/scalariform/build/build.scala4
-rw-r--r--stage2/Lib.scala9
-rw-r--r--stage2/libraries.scala7
-rw-r--r--stage2/plugins/Scalatex.scala77
13 files changed, 285 insertions, 11 deletions
diff --git a/.gitignore b/.gitignore
index 979f6df..fb5cb68 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,4 @@ examples/scalajs-react-example/server/public/generated
.cbt-loop.tmp
test/simple/src_generated
examples/scalapb-example/src_generated
+ScalatexGenerated.scala
diff --git a/build/build.scala b/build/build.scala
index c596245..cf2527a 100644
--- a/build/build.scala
+++ b/build/build.scala
@@ -25,6 +25,7 @@ class Build(val context: Context) extends Shared with Scalariform with PublishLo
context.cbtHome / "stage2" / "DirectoryDependency.scala",
context.cbtHome / "stage2" / "LazyDependency.scala",
context.cbtHome / "stage2" / "plugins" / "ScalaTest.scala",
+ context.cbtHome / "stage2" / "plugins" / "Scalatex.scala",
context.cbtHome / "stage2" / "libraries.scala",
context.cbtHome / "stage2" / "plugins.scala",
context.cbtHome / "stage2" / "ports.scala"
diff --git a/examples/scalatex-example/Foo.scala b/examples/scalatex-example/Foo.scala
new file mode 100644
index 0000000..e8bfc40
--- /dev/null
+++ b/examples/scalatex-example/Foo.scala
@@ -0,0 +1,4 @@
+package cbt_example.scalatex
+object Foo{
+ def foo(i: Int, j: Int) = i * j + i * j
+}
diff --git a/examples/scalatex-example/docs/build/build.scala b/examples/scalatex-example/docs/build/build.scala
new file mode 100644
index 0000000..51b158f
--- /dev/null
+++ b/examples/scalatex-example/docs/build/build.scala
@@ -0,0 +1,14 @@
+package cbt_examples.scalatex_example_build
+import cbt._
+import java.io._
+import java.nio.file._
+import java.nio.file.attribute._
+class Build(val context: Context) extends Scalatex{
+ override def dependencies = super.dependencies ++ Seq(
+ DirectoryDependency( projectDirectory / ".." )
+ )
+ override def run = {
+ scalatex.apply
+ super.run
+ }
+}
diff --git a/examples/scalatex-example/docs/readme.scalatex b/examples/scalatex-example/docs/readme.scalatex
new file mode 100644
index 0000000..11f432e
--- /dev/null
+++ b/examples/scalatex-example/docs/readme.scalatex
@@ -0,0 +1,21 @@
+@import scalatags.Text.all._
+@h1("cbt.http.client")
+@p
+ @ul
+ @li
+ http client library
+ @li
+ super simple and easy to use
+ @li
+ type-safe and resource-leak-safe
+ @li
+ no dependencies besides JDK
+ @li
+ complete (offers everything @pre(`class`:="inline"){java.net.URLConnection} does)
+ @repl
+ cbt_example.scalatex.Foo.foo(1,2)
+
+@comment{
+ @h3
+ Usage example
+} \ No newline at end of file
diff --git a/examples/scalatex-example/docs/static/style.css b/examples/scalatex-example/docs/static/style.css
new file mode 100644
index 0000000..36547e0
--- /dev/null
+++ b/examples/scalatex-example/docs/static/style.css
@@ -0,0 +1,32 @@
+@import url('https://fonts.googleapis.com/css?family=Muli');
+body{
+ font-family: 'Muli', sans-serif;
+ width: 600px;
+ left: 50%;
+ margin-left: -300px;
+ position: absolute;
+}
+
+h1, h2, h3, h4, h5, h6{
+ color: #007bbf;
+}
+
+.path-readme li{
+ font-size: 30px;
+}
+
+pre{
+ display: block;
+ border-top: 0px;
+ border-bottom: 0px;
+ border-left: 0;
+ border-right: 0;
+ border-color: #007bbf;
+ border-style: solid;
+ padding: 5px 0;
+}
+
+pre.inline{
+ display: inline;
+ border: 0;
+}
diff --git a/libraries/scalatex/AbstractMain.scala b/libraries/scalatex/AbstractMain.scala
new file mode 100644
index 0000000..ab876d9
--- /dev/null
+++ b/libraries/scalatex/AbstractMain.scala
@@ -0,0 +1,34 @@
+package cbt.plugins.scalatex.runtime
+
+import java.io.File
+import java.nio.file.{ Files, Paths }
+import scalatags.Text.all._
+trait AbstractMain{
+ def dependencyClasspath: Seq[File]
+ def files: Seq[(String,SeqFrag[Frag])]
+ def htmlTarget: File
+ def render: SeqFrag[Frag] => String => String
+ def main(args: Array[String]): Unit = {
+ val changed = files.flatMap{
+ case (name, contents) =>
+ val path = htmlTarget.toPath.resolve(name + ".html")
+ import Files._
+ createDirectories(path.getParent)
+ val newContents = render(contents)(name)
+ if( !exists(path) || new String( Files.readAllBytes( path ) ) != newContents ){
+ write( path, newContents.getBytes )
+ Some( path )
+ } else None
+ }
+ if( args.lift(0).map(_=="open").getOrElse(false) )
+ changed.headOption.foreach{ file =>
+ System.out.println(file)
+ val old = Option(System.getProperty("apple.awt.UIElement"))
+ System.setProperty("apple.awt.UIElement", "true")
+ java.awt.Desktop.getDesktop().open(file.toFile)
+ old.foreach(System.setProperty("apple.awt.UIElement", _))
+ }
+ else System.out.println(changed.mkString("\\n"))
+ }
+ val repl = new cbt.plugins.scalatex.runtime.repl( this.getClass.getClassLoader, dependencyClasspath: _* )
+}
diff --git a/libraries/scalatex/build/build.scala b/libraries/scalatex/build/build.scala
new file mode 100644
index 0000000..0ca9b76
--- /dev/null
+++ b/libraries/scalatex/build/build.scala
@@ -0,0 +1,16 @@
+package scalatex_build
+import cbt._
+class Build(val context: Context) extends BaseBuild{
+ override def dependencies = (
+ super.dependencies ++ // don't forget super.dependencies here for scala-library, etc.
+ Seq(
+ libraries.cbt.eval
+ ) ++
+ Resolver( mavenCentral, sonatypeReleases ).bind(
+ ScalaDependency( "com.lihaoyi", "scalatex-api", "0.3.7" ),
+ ScalaDependency( "com.lihaoyi", "scalatex-site", "0.3.7" ),
+ ScalaDependency("org.cvogt","scala-extensions","0.5.0"),
+ ScalaDependency("org.scalameta", "scalameta", "1.6.0")
+ )
+ )
+}
diff --git a/libraries/scalatex/lib.scala b/libraries/scalatex/lib.scala
new file mode 100644
index 0000000..018329a
--- /dev/null
+++ b/libraries/scalatex/lib.scala
@@ -0,0 +1,76 @@
+package cbt.plugins.scalatex.runtime
+
+import scalatags.Text.TypedTag
+import scalatags.Text.all._
+
+import cbt.eval.Eval
+import java.net._
+import java.io._
+import org.cvogt.scala._
+
+object hl extends scalatex.site.Highlighter
+
+object `package`{
+ def comment(any: =>Any): Unit = ()
+ def plain = span(fontFamily:="monospace")
+ def highlight(code: String) =
+ raw( """<pre class="highlight language-scala"><code>""" ++ code.stripIndent.trim ++ "</code></pre>" )
+ def layout: SeqFrag[Frag] => String => String = { contents => path =>
+ import scalatex._
+ import scalatags.Text.tags2._
+ import java.nio.file.{Paths, Files}
+ import scalatags.stylesheet._
+ val parts = path.split(File.separator)
+ val base = ("../" * (parts.size - 1)).mkString
+ val classes = parts.inits.toList.reverse.drop(1).map( parts => "path-" ++ parts.mkString("-") ).mkString(" ")
+ html(
+ head(
+ link(rel:="stylesheet", `type`:="text/css", href := base+"style.css")
+ ),
+ body(
+ `class` := classes,
+ raw("\n"), contents, raw("\n")
+ )
+ ).render
+ }
+}
+
+class repl(classLoader: ClassLoader, dependencyClasspath: java.io.File*) { repl =>
+ private val eval = new Eval(){
+ override lazy val impliedClassPath: List[String] = dependencyClasspath.map(_.toString).to
+ override def classLoader = repl.classLoader
+ }
+ /**
+ * repl session, inspired by tut.
+ *
+ * Example: code="1 + 1" returns
+ * "scala> 1 + 1
+ * res0: Int = 2"
+ */
+ def apply(code: String) = {
+ // adapted from https://github.com/olafurpg/scalafmt/blob/a12141b5ce285a60886abab0d96044c617e20b51/readme/Readme.scala
+ import scala.meta._
+ import scala.util._
+ val expressions = s"{$code}".parse[Stat].get.asInstanceOf[Term.Block].stats
+ val output = Try(eval[Any](code)) match {
+ case Success( value ) => "res0: " ++ value.getClass.getName ++ " = " ++ (value match {
+ case v: String => "\"" ++ v ++ "\""
+ case other => other.toString
+ })
+ case Failure( e ) => e.getMessage
+ }
+
+ val lineSeparator = String.format("%n")
+ val prefix = code.lines.filterNot("\t ".contains).mkString(lineSeparator).commonLinePrefix
+ val result = (
+ expressions
+ .map(prefix ++ _.toString)
+ .map("scala> " ++ _.stripIndent.prefixLines(" ").trimLeft)
+ .mkString("\n")
+ ++
+ "\n" ++ output.trim
+ )
+
+ hl.scala(result)
+ }
+}
diff --git a/plugins/scalariform/build/build.scala b/plugins/scalariform/build/build.scala
index 80f3966..a9690db 100644
--- a/plugins/scalariform/build/build.scala
+++ b/plugins/scalariform/build/build.scala
@@ -1,5 +1,7 @@
import cbt._
class Build(val context: Context) extends Plugin {
- override def dependencies = super.dependencies :+ ports.scalariform
+ override def dependencies = super.dependencies :+ /* ports.scalariform */Resolver( mavenCentral ).bindOne(
+ ScalaDependency("org.scalariform", "scalariform", "0.1.8")
+ )
}
diff --git a/stage2/Lib.scala b/stage2/Lib.scala
index 52973f1..56f24c6 100644
--- a/stage2/Lib.scala
+++ b/stage2/Lib.scala
@@ -160,13 +160,8 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger){
}.getOrElse{
if( context =!= null && (context.workingDirectory / name).exists ){
val newContext = context.copy( workingDirectory = context.workingDirectory / name )
- callInternal(
- DirectoryDependency( newContext.cwd )( newContext ).dependency,
- members.tail,
- previous :+ taskName,
- newContext,
- callback
- )
+ val build = DirectoryDependency( newContext, None ).dependency
+ callInternal( build, members.tail, previous :+ taskName, newContext, callback )
} else {
val p = previous.mkString(".")
val msg = (if(p.nonEmpty) p ++ s" has " else " ")
diff --git a/stage2/libraries.scala b/stage2/libraries.scala
index eb7de13..08a7a74 100644
--- a/stage2/libraries.scala
+++ b/stage2/libraries.scala
@@ -15,16 +15,17 @@ class libraries( context: Context, scalaVersion: String, scalaMajorVersion: Stri
def file = dep( "file" )
def interfaces = dep( "interfaces" )
def proguard = dep( "proguard" )
- def scalatestRunner = dep( "scalatest-runner" )
def reflect = dep( "reflect" )
+ def scalatestRunner = dep( "scalatest-runner" )
+ def scalatex = dep( "scalatex" )
}
object scala {
private def _maven = ( g: String, a: String, v: String ) => {
MavenResolver(
context.cbtLastModified, context.paths.mavenCache, mavenCentral
)(
- context.logger, context.transientCache, context.classLoaderCache
- ) bindOne MavenDependency( g, a, v )
+ context.logger, context.transientCache, context.classLoaderCache
+ ) bindOne MavenDependency( g, a, v )
}
def compiler = _maven( "org.scala-lang", "scala-compiler", scalaVersion )
diff --git a/stage2/plugins/Scalatex.scala b/stage2/plugins/Scalatex.scala
new file mode 100644
index 0000000..6276332
--- /dev/null
+++ b/stage2/plugins/Scalatex.scala
@@ -0,0 +1,77 @@
+package cbt
+import java.io.File
+import java.nio.file.Files
+trait Scalatex extends BaseBuild {
+ override def dependencies = super.dependencies :+ libraries.cbt.scalatex
+
+ def scalatex = (
+ Scalatex.apply(
+ lib,
+ Math.max( context.cbtLastModified, ( dependencies ++ context.parentBuild ).map( _.lastModified ).max )
+ )
+ .config(
+ lib.autoRelative(
+ lib.sourceFiles( sources, _.string endsWith ".scalatex" )
+ ++ projectDirectory.listFiles.toVector.filter( _.toString.endsWith( ".scalatex" ) )
+ ).map {
+ case ( file, name ) => file -> name.stripPrefix( File.separator ).stripSuffix( ".scalatex" )
+ },
+ lib.autoRelative( Seq( projectDirectory / "static" ) ),
+ target / "html",
+ projectDirectory / "src_generated" / "scalatex",
+ dependencyClasspath
+ )
+ )
+}
+/** @param htmlTarget directory where the html files are generated
+ */
+object Scalatex {
+ case class apply(
+ lib: Lib, parentsLastModified: Long
+ )(
+ implicit
+ logger: Logger, transientCache: java.util.Map[AnyRef, AnyRef], classLoaderCache: cbt.ClassLoaderCache
+ ) {
+ case class config(
+ scalatexFiles: Seq[( File, String )],
+ staticFiles: Seq[( File, String )],
+ htmlTarget: File,
+ srcGenerated: File,
+ dependencyClasspath: ClassPath,
+ transform: String = "cbt.plugins.scalatex.runtime.layout", // function String => String
+ linkStaticFile: Boolean = true,
+ `package`: String = "cbt.plugins.scalatex.runtime"
+ ) {
+ def apply = {
+ staticFiles.map {
+ case ( file, relative ) => file -> htmlTarget / relative
+ }.collect {
+ case ( from, to ) if from.isDirectory => to.mkdirs
+ case ( from, to ) if !from.isDirectory && !to.exists => Files.createLink( to.toPath, from.toPath )
+ }
+ lib.cached(
+ srcGenerated,
+ ( parentsLastModified +: scalatexFiles.map( _._1 ).map( _.lastModified ) ).max
+ ) { () =>
+ lib.writeIfChanged(
+ srcGenerated / "ScalatexGenerated.scala",
+ s"""// Last generated at ${java.time.ZonedDateTime.now}
+package ${`package`}
+object ScalatexGenerate extends cbt.plugins.scalatex.runtime.AbstractMain{
+ def dependencyClasspath: Seq[java.io.File] = Seq(
+ ${dependencyClasspath.files.map( _.quote ).mkString( ",\n " )}
+ )
+ def htmlTarget = ${htmlTarget.quote}
+ import scalatags.Text.all._
+ def files = Seq[(String, scalatags.Text.all.SeqFrag[scalatags.Text.all.Frag])](
+ ${scalatexFiles.map { case ( from, to ) => s"${to.quote} -> scalatex.twf(${from.string.quote})" }.mkString( ",\n " )}
+ )
+ def render: scalatags.Text.all.SeqFrag[scalatags.Text.all.Frag] => String => String = $transform
+}
+""".trim ++ "\n"
+ )
+ }
+ }
+ }
+ }
+}