Skip to content

Commit

Permalink
Merge pull request #508 from eed3si9n/wip/snippet
Browse files Browse the repository at this point in the history
implement Snippet mechanism like Paradox
  • Loading branch information
dwijnand authored Oct 4, 2017
2 parents 043a943 + e01a35d commit ac28c74
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ before_script:
- export JVM_OPTS="-Dfile.encoding=UTF-8 -Xmx1G -Xms1G -server -XX:ReservedCodeCacheSize=128M"

script:
- /usr/bin/sbt scalafmtTest makeSite
- /usr/bin/sbt scalafmtTest scripted makeSite
# Tricks to avoid unnecessary cache updates
- find $HOME/.sbt -name "*.lock" | xargs rm
- find $HOME/.ivy2 -name "ivydata-*.properties" | xargs rm
Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,23 @@ To push site, from sbt shell:
```

Beware of https://github.com/sbt/sbt-ghpages/issues/25

## Including code examples

To include a validated code examples, create a scripted test under `src/sbt-test`,
and in the markdown include as:

```
// This includes the entire file as Scala code snippet
@@snip [build.sbt]($root$/src/sbt-test/ref/basic/build.sbt) {}
or
// This includes snippet between a line containing #example another line with #example
@@snip [build.sbt]($root$/src/sbt-test/ref/basic/build.sbt) { #example }
or
// This specifies syntax highlight
@@snip [build.sbt]($root$/src/sbt-test/ref/basic/build.sbt) { #example type=text }
```
7 changes: 6 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ lazy val tutorialSubDirName = settingKey[String]("subdir name for old tutorial")
lazy val fileEncoding = settingKey[String]("check the file encoding")

lazy val root = (project in file("."))
.enablePlugins(NanocPlugin, PamfletPlugin)
.enablePlugins(NanocPlugin, LowTechSnippetPamfletPlugin)
.settings(
organization := "org.scala-sbt",
name := "website",
Expand Down Expand Up @@ -34,5 +34,10 @@ lazy val root = (project in file("."))
case x => sys.error(s"Unexpected encoding $x")
}
},
scriptedLaunchOpts := {
scriptedLaunchOpts.value ++
Seq("-Xmx1024M", "-Dplugin.version=" + version.value)
},
scriptedBufferLog := false,
isGenerateSiteMap := true
)
35 changes: 35 additions & 0 deletions project/LowTechSnippletPlugin.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import sbt._
import Keys._

object LowTechSnippetPamfletPlugin extends AutoPlugin {
import com.typesafe.sbt.site.pamflet._
import PamfletPlugin.autoImport._
import pamflet._

override def requires = PamfletPlugin
override def trigger = noTrigger
override def projectSettings = pamfletSettings

def pamfletSettings: Seq[Setting[_]] =
Seq(
mappings in Pamflet := generate(
(sourceDirectory in Pamflet).value,
(target.value / "lowtech_generated"),
(target in Pamflet).value,
(includeFilter in Pamflet).value,
(pamfletFencePlugins in Pamflet).value
)
)

def generate(input: File,
generated: File,
output: File,
includeFilter: FileFilter,
fencePlugins: Seq[FencePlugin]): Seq[(File, String)] = {
// this is the added step
Snippet.processDirectory(input, generated)
val storage = FileStorage(generated, fencePlugins.toList)
Produce(storage.globalized, output)
output ** includeFilter --- output pair Path.relativeTo(output)
}
}
79 changes: 79 additions & 0 deletions project/Snippet.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import sbt._
import Keys._
import Path.rebase

object Snippet {

/**
* Processes all files under base directory, and outputs to newBase.
* Markdown files are snippet-processed, and the rest are just copied.
*/
def processDirectory(base: File, newBase: File): File = {
IO.createDirectory(newBase)
val files: Seq[File] = (base ** (-DirectoryFilter)).get
val isMarkdown = Set("markdown", "md")
(files pair rebase(base :: Nil, newBase)) foreach {
case (x, newFile) if isMarkdown(x.ext) => processFile(x, newFile)
case (x, newFile) => IO.copyFile(x, newFile)
}
newBase
}

def processFile(baseFile: File, newFile: File): File = {
val xs0 = IO.readLines(baseFile)
val xs: List[String] = xs0 flatMap {
case x if x.trim.startsWith("@@snip") => snippet(x, baseFile)
case x => List(x)
}
IO.writeLines(newFile, xs)
newFile
}

/**
* Use the Lightbend Paradox syntax for snippet inclusion.
* `@@snip [example.log](example.log) { #example-log type=text }`
*/
lazy val Snippet = ("""\@\@snip\s*\[[^\]]+\]\(([^)]*)\)\s*"""
+ """\{\s*(\#[\w-]+)?(\s+type\=[\w-]+)?.*\}\s*""").r
def snippet(line: String, baseFile: File): List[String] = {
def readFromRef(ref: File, tagOpt: Option[String], ty: String): List[String] = {
tagOpt match {
case Some(tag) =>
val xs0 = IO.readLines(ref)
val xs = xs0
.dropWhile({ x =>
!x.contains(tag)
})
.drop(1)
.takeWhile({ x =>
!x.contains(tag)
})
if (xs.isEmpty) {
sys.error(s"@@snip was detected for $ref with tag $tag, but the code was empty!")
}
List(s"```$ty") ::: xs ::: List("```")
case None => List(s"```$ty") ::: IO.readLines(ref) ::: List("```")
}
}
line match {
case Snippet(path0, tag0, ty0) =>
val tag = Option(tag0).map(_.trim)
val ty = Option(ty0).map(_.trim).getOrElse("scala")
val ref = resolvePath(path0, baseFile)
if (!ref.exists) {
sys.error(s"@@snip was detected, but $ref was not found!")
}
readFromRef(ref, tag, ty)
case _ => sys.error(s"Invalid snippet notation: $line")
}
}

/**
* If the path starts from `$root$/` then use the path as is from root.
* Otherwise, treat it as a relative path from the markdown file.
*/
def resolvePath(p: String, baseFile: File): File = {
if (p.startsWith("$root$/")) file(p.drop(7))
else new File(uri(baseFile.getParentFile.toURI.toString + p))
}
}
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=1.0.0
sbt.version=1.0.2
3 changes: 1 addition & 2 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.3.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.2")

addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "1.2.0")
libraryDependencies += { "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value }
16 changes: 2 additions & 14 deletions src/reference/00-Getting-Started/05-Basic-Def.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,27 +47,15 @@ we often call it a *subproject* in this guide.
For instance, in `build.sbt` you define
the subproject located in the current directory like this:

```scala
lazy val root = (project in file("."))
.settings(
name := "Hello",
scalaVersion := "$example_scala_version$"
)
```
@@snip [build.sbt]($root$/src/sbt-test/ref/basic/build.sbt) {}

Each subproject is configured by key-value pairs.

For example, one key is `name` and it maps to a string value, the name of
your subproject.
The key-value pairs are listed under the `.settings(...)` method as follows:

```scala
lazy val root = (project in file("."))
.settings(
name := "Hello",
scalaVersion := "$example_scala_version$"
)
```
@@snip [build.sbt]($root$/src/sbt-test/ref/basic/build.sbt) {}

### How build.sbt defines settings

Expand Down
5 changes: 5 additions & 0 deletions src/reference/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
lazy val root = (project in file("."))
.settings(
name := "Hello",
scalaVersion := "$example_scala_version$"
)
16 changes: 2 additions & 14 deletions src/reference/ja/00-Getting-Started/05-Basic-Def.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,14 @@ sbt.version=$app_version$

例えば、カレントディレクトリにあるサブプロジェクトは `build.sbt` に以下のように定義できる:

```scala
lazy val root = (project in file("."))
.settings(
name := "Hello",
scalaVersion := "$example_scala_version$"
)
```
@@snip [build.sbt]($root$/src/sbt-test/ref/basic/build.sbt) {}

それぞれのサブプロジェクトは、キーと値のペアによって詳細が設定される。

例えば、`name` というキーがあるが、それはサブプロジェクト名という文字列の値に関連付けられる。
キーと値のペア列は `.settings(...)` メソッド内に列挙される:

```scala
lazy val root = (project in file("."))
.settings(
name := "Hello",
scalaVersion := "$example_scala_version$"
)
```
@@snip [build.sbt]($root$/src/sbt-test/ref/basic/build.sbt) {}

### `build.sbt` はどのように settings を定義するか

Expand Down
5 changes: 5 additions & 0 deletions src/sbt-test/ref/basic/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
lazy val root = (project in file("."))
.settings(
name := "Hello",
scalaVersion := "2.12.3"
)
1 change: 1 addition & 0 deletions src/sbt-test/ref/basic/test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
> name

0 comments on commit ac28c74

Please sign in to comment.