Skip to content

Commit

Permalink
Merge pull request #148 from olafurpg/toString
Browse files Browse the repository at this point in the history
Add `toString` modifier to customize value pretty-printer.
  • Loading branch information
olafurpg committed Jan 15, 2019
2 parents 39563ec + c1ede5d commit 0254c0e
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 85 deletions.
126 changes: 70 additions & 56 deletions docs/modifiers.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ x + y
```
````

## Silent
## `silent`

The `silent` modifier is identical to the default modifier except that it hides
the evaluated output. The input code fence renders unchanged.
Expand All @@ -35,7 +35,7 @@ x + y
```
````

## Fail
## `fail`

The `fail` modifier asserts that the code block will not compile. The rendered
output contains the type error message.
Expand All @@ -57,7 +57,7 @@ val x: String = ""
> Note that `fail` does not assert that the program compiles but crashes at
> runtime. To assert runtime exceptions, use the `crash` modifier.
## Crash
## `crash`

The `crash` modifier asserts that the code block throws an exception at runtime

Expand All @@ -67,7 +67,7 @@ val y = ???
```
````

## Passthrough
## `passthrough`

The `passthrough` modifier collects the stdout and stderr output from the
program and embeds it verbatim in the markdown file.
Expand All @@ -92,7 +92,7 @@ $table
```
````

## Invisible
## `invisible`

The `invisible` modifier evaluates the code but does not render anything. The
`invisible` modifier is equivalent to `passthrough` when the expression does not
Expand All @@ -106,7 +106,7 @@ println("I am invisible")
More prose.
````

## Reset
## `reset`

The `reset` modifier starts a new scope where previous statements in the
document are no longer available. This can be helpful to clear existing imports
Expand All @@ -126,7 +126,7 @@ println(x)
```
````

## Reset class
## `reset-class`

The `:reset-class` modifier is like `:reset` except that it wraps the following
statements in a class instead of an object. By default, statements are wrapped
Expand Down Expand Up @@ -164,6 +164,69 @@ including:
reference in this type test cannot be checked at run time." warnings under
`-Xfatal-warnings`.

## `to-string`

The `toString` modifier changes the pretty-printer for runtime values to use
`Object.toString` instead of [PPrint](http://www.lihaoyi.com/PPrint/).

````scala mdoc:mdoc
```scala mdoc:to-string
List("no quotes")
```
```scala mdoc
List("with quotes")
```
````

## `scastie`

The `scastie` modifier transforms a Scala code block into a
[Scastie](https://scastie.scala-lang.org/) snippet.

> ℹ️ This modifier will work only in environments that support embedding a
> `<script>` tag. For example, it won't work in GitHub readmes, but it will work
> when building a static website from Markdown (e.g., with
> [Docusaurus](https://docusaurus.io/))
You can embed an existing Scastie snippet by its id:

````scala mdoc:mdoc
```scala mdoc:scastie:xbrvky6fTjysG32zK6kzRQ

```
````

or in case of a user's snippet:

````scala mdoc:mdoc
```scala mdoc:scastie:MasseGuillaume/CpO2s8v2Q1qGdO3vROYjfg

```
````

> ⚠️ The empty line in the block can't be omitted due to how the Markdown parser
> works
Moreover, you can quickly translate any Scala code block block into a Scastie
snippet on the fly.

````scala mdoc:mdoc
```scala mdoc:scastie
val x = 1 + 2
println(x)
```
````

> ⚠️ Inline snippets are slower to run than embedded ones, since they won't be
> cached. You should prefer embedding existing snippets whenever possible.
You can choose the Scastie theme when initializing the Scastie modifier:

```scala mdoc
import mdoc.modifiers.ScastieModifier
new ScastieModifier(theme = "dark") // default is "light"
```

## PostModifier

A `PostModifier` is a custom modifier that post-processes a compiled and
Expand Down Expand Up @@ -276,52 +339,3 @@ We can also add the argument `:crash` to render "BOOM".
Hello world!
```
````

## Scastie

The `scastie` modifier transforms a Scala code block into a
[Scastie](https://scastie.scala-lang.org/) snippet.

> ℹ️ This modifier will work only in environments that support embedding a
> `<script>` tag. For example, it won't work in GitHub readmes, but it will work
> when building a static website from Markdown (e.g., with
> [Docusaurus](https://docusaurus.io/))
You can embed an existing Scastie snippet by its id:

````scala mdoc:mdoc
```scala mdoc:scastie:xbrvky6fTjysG32zK6kzRQ

```
````

or in case of a user's snippet:

````scala mdoc:mdoc
```scala mdoc:scastie:MasseGuillaume/CpO2s8v2Q1qGdO3vROYjfg

```
````

> ⚠️ The empty line in the block can't be omitted due to how the Markdown parser
> works
Moreover, you can quickly translate any Scala code block block into a Scastie
snippet on the fly.

````scala mdoc:mdoc
```scala mdoc:scastie
val x = 1 + 2
println(x)
```
````

> ⚠️ Inline snippets are slower to run than embedded ones, since they won't be
> cached. You should prefer embedding existing snippets whenever possible.
You can choose the Scastie theme when initializing the Scastie modifier:

```scala mdoc
import mdoc.modifiers.ScastieModifier
new ScastieModifier(theme = "dark") // default is "light"
```
5 changes: 4 additions & 1 deletion mdoc/src/main/scala/mdoc/Variable.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package mdoc

import mdoc.internal.markdown.Modifier
import mdoc.internal.markdown.ReplVariablePrinter
import scala.meta.inputs.Position

Expand Down Expand Up @@ -54,8 +55,10 @@ final class Variable private[mdoc] (
val indexOfVariableInStatement: Int,
val totalVariablesInStatement: Int,
val indexOfStatementInCodeFence: Int,
val totalStatementsInCodeFence: Int
val totalStatementsInCodeFence: Int,
private[mdoc] val mods: Modifier
) {
def isToString: Boolean = mods.isToString
def isUnit: Boolean = staticType.endsWith("Unit")
override def toString: String = {
ReplVariablePrinter(this)
Expand Down
16 changes: 7 additions & 9 deletions mdoc/src/main/scala/mdoc/internal/markdown/Instrumenter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ class Instrumenter(sections: List[SectionInput]) {
sb.print(s"; $$doc.binder($name, ${position(pos)})")
}
private def printStatement(stat: Stat, m: Modifier, sb: PrintStream): Unit = {
if (m.isDefault || m.isPassthrough || m.isInvisible || m.isSilent || m.isReset || m.isPost) {
if (m.isCrash) {
sb.append("$doc.crash(")
.append(position(stat.pos))
.append(") {\n")
.append(stat.pos.text)
.append("\n}")
} else {
val binders = stat match {
case Binders(names) =>
names.map(name => name -> name.pos)
Expand All @@ -65,14 +71,6 @@ class Instrumenter(sections: List[SectionInput]) {
case (name, pos) =>
printBinder(name.syntax, pos)
}
} else if (m.isCrash) {
sb.append("$doc.crash(")
.append(position(stat.pos))
.append(") {\n")
.append(stat.pos.text)
.append("\n}")
} else {
throw new IllegalArgumentException(stat.pos.text)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ class MdocPostProcessor(implicit ctx: Context) extends DocumentPostProcessor {
j,
n,
i,
m
m,
section.mod
)
}
val postCtx = new PostModifierContext(
Expand All @@ -186,10 +187,8 @@ class MdocPostProcessor(implicit ctx: Context) extends DocumentPostProcessor {
replaceNodeWithText(doc, block, stacktrace)
} else if (m.isSilent) {
() // Do nothing
} else if (m.isDefault || m.isReset || m.isFail) {
block.setContent(List[BasedSequence](CharSubSequence.of(defaultRender)).asJava)
} else {
throw new IllegalArgumentException(m.toString)
block.setContent(List[BasedSequence](CharSubSequence.of(defaultRender)).asJava)
}
case c: Modifier.Str =>
throw new IllegalArgumentException(c.toString)
Expand Down
6 changes: 5 additions & 1 deletion mdoc/src/main/scala/mdoc/internal/markdown/Mod.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ object Mod {
case object ResetClass extends Mod {
override def toString: String = "reset-class"
}
case object ToString extends Mod {
override def toString: String = "to-string"
}

def all: List[Mod] = List(
Passthrough,
Expand All @@ -19,7 +22,8 @@ object Mod {
ResetClass,
Fail,
Crash,
Silent
Silent,
ToString
)
def unapply(string: String): Option[Mod] = {
all.find(_.toString.equalsIgnoreCase(string))
Expand Down
1 change: 1 addition & 0 deletions mdoc/src/main/scala/mdoc/internal/markdown/Modifier.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ sealed abstract class Modifier(mods: Set[Mod]) {
def isInvisible: Boolean = mods(Invisible)
def isReset: Boolean = mods(Reset) || isResetClass
def isResetClass: Boolean = mods(ResetClass)
def isToString: Boolean = mods(ToString)
}
object Modifier {
object Default {
Expand Down
7 changes: 3 additions & 4 deletions mdoc/src/main/scala/mdoc/internal/markdown/Renderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ object Renderer {
s"Expected FailSection. Obtained $obtained"
)
}
case Modifier.PrintVariable() | Modifier.Post(_, _) =>
case _ =>
val pos = binder.pos.toMeta(section)
val variable = new mdoc.Variable(
binder.name,
Expand All @@ -159,11 +159,10 @@ object Renderer {
i,
N,
statementIndex,
totalStats
totalStats,
section.mod
)
sb.append(printer(variable))
case c @ (Modifier.Str(_, _) | Modifier.Builtin(_)) =>
throw new IllegalArgumentException(c.toString)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@ class ReplVariablePrinter(
.append(": ")
.append(binder.staticType)
.append(" = ")
val lines = pprint.PPrinter.BlackWhite.tokenize(
binder.runtimeValue,
width = width,
height = height,
indent = 2,
initialOffset = baos.size()
)
lines.foreach { lineStr =>
val line = lineStr.plainText
Renderer.appendMultiline(sb, line)
if (binder.isToString) {
Renderer.appendMultiline(sb, binder.runtimeValue.toString)
} else {
val lines = pprint.PPrinter.BlackWhite.tokenize(
binder.runtimeValue,
width = width,
height = height,
indent = 2,
initialOffset = baos.size()
)
lines.foreach { lineStr =>
val line = lineStr.plainText
Renderer.appendMultiline(sb, line)
}
}
baos.toString()
}
Expand Down
27 changes: 27 additions & 0 deletions tests/unit/src/test/scala/tests/markdown/ToStringSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package tests.markdown

class ToStringSuite extends BaseMarkdownSuite {
check(
"basic",
"""
|```scala mdoc:to-string
|List("a")
|```
|```scala mdoc
|List("a")
|```
""".stripMargin,
"""|
|```scala
|List("a")
|// res0: List[String] = List(a)
|```
|
|```scala
|List("a")
|// res1: List[String] = List("a")
|```
""".stripMargin
)

}

0 comments on commit 0254c0e

Please sign in to comment.