diff options
author | Oleg Yukhnevich <whyoleg@gmail.com> | 2023-11-16 16:58:19 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-16 16:58:19 +0200 |
commit | f333e425440701e50361f61acc2f9cb2d10fac1a (patch) | |
tree | 85fded28ef08dd658bb53f16af2976b89a3b1aa7 /dokka-subprojects/plugin-base/src/main | |
parent | 1e126789a92e512b0a426044220043632e7dbf1b (diff) | |
download | dokka-f333e425440701e50361f61acc2f9cb2d10fac1a.tar.gz dokka-f333e425440701e50361f61acc2f9cb2d10fac1a.tar.bz2 dokka-f333e425440701e50361f61acc2f9cb2d10fac1a.zip |
Implement custom code block renderers support (#3320)
* multiple custom renderers can be installed to support different languages independently
* only language and code properties are provided for extension
Diffstat (limited to 'dokka-subprojects/plugin-base/src/main')
3 files changed, 83 insertions, 0 deletions
diff --git a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/DokkaBase.kt b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/DokkaBase.kt index ca86d4d5..6fa4270b 100644 --- a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/DokkaBase.kt +++ b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/DokkaBase.kt @@ -49,6 +49,14 @@ public class DokkaBase : DokkaPlugin() { public val outputWriter: ExtensionPoint<OutputWriter> by extensionPoint() public val htmlPreprocessors: ExtensionPoint<PageTransformer> by extensionPoint() + /** + * Extension point for providing custom HTML code block renderers. + * + * This extension point allows overriding the rendering of code blocks in different programming languages. + * Multiple renderers can be installed to support different languages independently. + */ + public val htmlCodeBlockRenderers: ExtensionPoint<HtmlCodeBlockRenderer> by extensionPoint() + @Deprecated("It is not used anymore") public val tabSortingStrategy: ExtensionPoint<TabSortingStrategy> by extensionPoint() public val immediateHtmlCommandConsumer: ExtensionPoint<ImmediateHtmlCommandConsumer> by extensionPoint() diff --git a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/HtmlCodeBlockRenderer.kt b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/HtmlCodeBlockRenderer.kt new file mode 100644 index 00000000..29af6f98 --- /dev/null +++ b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/HtmlCodeBlockRenderer.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.base.renderers.html + +import kotlinx.html.FlowContent + +/** + * Provides an ability to override code blocks rendering differently dependent on the code language. + * + * Multiple renderers can be installed to support different languages in an independent way. + */ +public interface HtmlCodeBlockRenderer { + + /** + * Whether this renderer supports rendering Markdown code blocks + * for the given [language] explicitly specified in the fenced code block definition, + */ + public fun isApplicableForDefinedLanguage(language: String): Boolean + + /** + * Whether this renderer supports rendering Markdown code blocks + * for the given [code] when language is not specified in fenced code blocks + * or indented code blocks are used. + */ + public fun isApplicableForUndefinedLanguage(code: String): Boolean + + /** + * Defines how to render [code] for specified [language] via HTML tags. + * + * The value of the [language] will be the same as in the input Markdown fenced code block definition. + * In the following example [language] = `kotlin` and [code] = `val a`: + * ~~~markdown + * ```kotlin + * val a + * ``` + * ~~~ + * The value of the [language] will be `null` if language is not specified in the fenced code block definition + * or indented code blocks are used. + * In the following example [language] = `null` and [code] = `val a`: + * ~~~markdown + * ``` + * val a + * ``` + * ~~~ + */ + public fun FlowContent.buildCodeBlock(language: String?, code: String) +} diff --git a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/HtmlRenderer.kt b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/HtmlRenderer.kt index 083876d5..e7b77383 100644 --- a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/HtmlRenderer.kt +++ b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/HtmlRenderer.kt @@ -52,6 +52,7 @@ public open class HtmlRenderer( private var shouldRenderSourceSetTabs: Boolean = false override val preprocessors: List<PageTransformer> = context.plugin<DokkaBase>().query { htmlPreprocessors } + private val customCodeBlockRenderers = context.plugin<DokkaBase>().query { htmlCodeBlockRenderers } /** * Tabs themselves are created in HTML plugin since, currently, only HTML format supports them. @@ -816,6 +817,31 @@ public open class HtmlRenderer( code: ContentCodeBlock, pageContext: ContentPage ) { + if (customCodeBlockRenderers.isNotEmpty()) { + val language = code.language.takeIf(String::isNotBlank) + val codeText = buildString { + code.children.forEach { + when (it) { + is ContentText -> append(it.text) + is ContentBreakLine -> appendLine() + } + } + } + + // we use first applicable renderer to override rendering + val applicableRenderer = when (language) { + null -> customCodeBlockRenderers.firstOrNull { it.isApplicableForUndefinedLanguage(codeText) } + else -> customCodeBlockRenderers.firstOrNull { it.isApplicableForDefinedLanguage(language) } + } + if (applicableRenderer != null) { + return with(applicableRenderer) { + buildCodeBlock(language, codeText) + } + } + } + + // if there are no applicable custom renderers - fall back to default + div("sample-container") { val codeLang = "lang-" + code.language.ifEmpty { "kotlin" } val stylesWithBlock = code.style + TextStyle.Block + codeLang |