1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
package org.pacien.pandoc.filter.plantuml
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.ArrayNode
import com.fasterxml.jackson.databind.node.ObjectNode
import com.fasterxml.jackson.databind.node.TextNode
import java.io.InputStream
import java.io.OutputStream
object Filter {
private val mapper = ObjectMapper()
private inline fun <T> T.conditionally(condition: Boolean, block: (T) -> T): T =
if (condition) block(this) else this
private inline fun <T, A> T.withNonNull(value: A?, block: (T, A) -> T): T =
if (value != null) block(this, value) else this
private fun JsonNode.isCodeBlock() = type() == "CodeBlock"
private fun JsonNode.isPlantUmlBlock() = isCodeBlock() && "puml" in classNames()
private fun Latex.resizeBox(attrs: Map<String, String>) =
resizeBox(attrs["width"] ?: "!", attrs["height"] ?: "!")
private fun Latex.setOptions(classes: List<String>, attrs: Map<String, String>) =
this
.conditionally("width" in attrs || "height" in attrs) { it -> it.resizeBox(attrs) }
.conditionally("centered" in classes, Latex::centering)
.withNonNull(attrs["caption"], Latex::caption)
.withNonNull(attrs["label"], Latex::label)
.conditionally("caption" in attrs || "label" in attrs, Latex::figure)
private fun arrayNodeOf(type: String, content: String): ArrayNode =
mapper.createArrayNode()
.add(TextNode.valueOf(type))
.add(TextNode.valueOf(content))
private fun renderPlantumlNode(node: ObjectNode) {
val puml = node.content()
val tikz = PlantUml.renderTikz(puml)
val block = tikz.setOptions(node.classNames(), node.attributeMap())
node.setBlock("RawBlock", arrayNodeOf("latex", block.raw()))
}
private fun walk(node: JsonNode): Unit = when {
node.isPlantUmlBlock() -> renderPlantumlNode(node as ObjectNode)
else -> node.forEach(Filter::walk)
}
fun filter(input: InputStream, output: OutputStream) {
mapper.readTree(input)?.let { tree ->
walk(tree)
mapper.writeValue(output, tree)
}
}
}
|