Coverage Summary for Class: TocExtension (io.heapy.kotmark.ext.toc)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| TocExtension |
100%
(7/7)
|
87.5%
(7/8)
|
100%
(17/17)
|
100%
(91/91)
|
| TocExtension$Configuration |
100%
(2/2)
|
100%
(20/20)
|
100%
(10/10)
|
100%
(130/130)
|
| TocExtension$extend$$inlined$nodeRenderer$default$1 |
0%
(0/2)
|
|
| TocExtension$extend$$inlined$nodeRenderer$default$1$1 |
0%
(0/2)
|
|
| Total |
69.2%
(9/13)
|
96.4%
(27/28)
|
100%
(27/27)
|
100%
(221/221)
|
package io.heapy.kotmark.ext.toc
import io.heapy.kotmark.ExtensionsBuilder
import io.heapy.kotmark.KotmarkDsl
import io.heapy.kotmark.ext.toc.internal.TocBlockParser
import io.heapy.kotmark.ext.toc.internal.TocHtmlNodeRenderer
import io.heapy.kotmark.ext.toc.internal.TocTextNodeRenderer
import io.heapy.kotmark.ext.toc.internal.documentNodes
import io.heapy.kotmark.node.Document
import io.heapy.kotmark.parser.Parser
import io.heapy.kotmark.renderer.html.HtmlRenderer
import io.heapy.kotmark.renderer.markdown.MarkdownRenderer
import io.heapy.kotmark.renderer.markdown.nodeRenderer
import io.heapy.kotmark.renderer.text.TextContentRenderer
/** Opt-in TOC markers, HTML heading IDs and outlines. See the module README for rendering contracts. */
class TocExtension private constructor(configuration: Configuration) :
Parser.ParserExtension,
HtmlRenderer.HtmlRendererExtension,
MarkdownRenderer.MarkdownRendererExtension,
TextContentRenderer.TextContentRendererExtension {
private val markers = configuration.markers.toList()
private val levels = configuration.headingLevels
private val placement = configuration.placement
override fun extend(parserConfiguration: Parser.Configuration) {
parserConfiguration.customBlockParserFactory(TocBlockParser.Factory(markers.toSet()))
if (placement != TocPlacement.MARKERS) {
parserConfiguration.postProcessor { root ->
if (root is Document && documentNodes(root).none { it is TableOfContents }) {
val toc = TableOfContents(markers.first())
if (placement == TocPlacement.PREPEND_IF_MISSING) root.prependChild(toc) else root.appendChild(toc)
}
root
}
}
}
override fun extend(rendererConfiguration: HtmlRenderer.Configuration) {
rendererConfiguration.nodeRendererFactory { TocHtmlNodeRenderer(it, levels) }
}
override fun extend(rendererConfiguration: MarkdownRenderer.Configuration) {
rendererConfiguration.nodeRenderer<TableOfContents> { node ->
writer.raw(node.marker)
writer.block()
}
}
override fun extend(rendererConfiguration: TextContentRenderer.Configuration) {
rendererConfiguration.nodeRendererFactory { TocTextNodeRenderer(it, levels) }
}
@KotmarkDsl
class Configuration internal constructor() {
/** Case-sensitive, standalone-line markers. Replacing this list replaces both defaults. */
var markers: List<String> = listOf("[TOC]", "[[_TOC_]]")
/** Inclusive heading levels, within 1..6. Filtering does not change ID allocation. */
var headingLevels: IntRange = 1..6
var placement: TocPlacement = TocPlacement.MARKERS
internal fun create(): TocExtension {
require(markers.isNotEmpty() && markers.all {
it.isNotEmpty() && it == it.trim() && '\n' !in it && '\r' !in it
}) { "TOC markers must be nonempty single lines without surrounding whitespace" }
require(!headingLevels.isEmpty() && headingLevels.first >= 1 && headingLevels.last <= 6) {
"TOC headingLevels must be a nonempty range within 1..6"
}
return TocExtension(this)
}
}
}
/** Creates [TocExtension], snapshotting its configuration. */
fun tocExtension(configure: TocExtension.Configuration.() -> Unit = {}): TocExtension =
TocExtension.Configuration().apply(configure).create()
/** Creates and appends [TocExtension]. */
fun ExtensionsBuilder.toc(configure: TocExtension.Configuration.() -> Unit = {}) {
add(tocExtension(configure))
}