diff --git a/dokka-mkdocs/src/main/kotlin/DokkaMkDocsPlugin.kt b/dokka-mkdocs/src/main/kotlin/DokkaMkDocsPlugin.kt index 931e8a5..20757bb 100644 --- a/dokka-mkdocs/src/main/kotlin/DokkaMkDocsPlugin.kt +++ b/dokka-mkdocs/src/main/kotlin/DokkaMkDocsPlugin.kt @@ -77,8 +77,6 @@ abstract class DokkaMkDocsPlugin : DokkaFormatPlugin(formatName = "mkdocs") { aR.isDirectory && aR in bR -> -1 bR.isDirectory && bR in aR -> 1 else -> aR.path.replace(File.separatorChar, '\u0001').decodeAsDokkaUrl().compareTo(bR.path.replace(File.separatorChar, '\u0001').decodeAsDokkaUrl()) - }.also { - println("$it — $a \t $b") } } .forEach { file -> -- 2.51.2 From a7878df91473975bd0d4b04be487964261733d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 8 Jan 2025 16:39:12 +0100 Subject: [PATCH 02/24] feat(renderer): Pure renderer implementation start --- gradle/libs.versions.toml | 3 + renderer/build.gradle.kts | 1 + .../main/kotlin/MaterialForMkDocsPlugin.kt | 20 +++- .../main/kotlin/renderer3/MkDocsRenderer3.kt | 99 +++++++++++++++++++ 4 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 renderer/src/main/kotlin/renderer3/MkDocsRenderer3.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b8bdfec..c6ffa85 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,12 +1,15 @@ # List of dependencies of the project [versions] +coroutines = "1.10.1" # https://github.com/Kotlin/kotlinx.coroutines/releases dokka = "2.0.0-Beta" # https://github.com/Kotlin/dokka/releases dokkatoo = "2.3.1" # https://github.com/adamko-dev/dokkatoo/releases [plugins] [libraries] +kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" } + dokka-base = { module = "org.jetbrains.dokka:dokka-base", version.ref = "dokka" } dokka-core = { module = "org.jetbrains.dokka:dokka-core", version.ref = "dokka" } diff --git a/renderer/build.gradle.kts b/renderer/build.gradle.kts index b18d2f0..9c8b4e5 100644 --- a/renderer/build.gradle.kts +++ b/renderer/build.gradle.kts @@ -14,6 +14,7 @@ kotlin { } dependencies { + implementation(libs.kotlinx.coroutines) compileOnly(libs.dokka.base) compileOnly(libs.dokka.core) } diff --git a/renderer/src/main/kotlin/MaterialForMkDocsPlugin.kt b/renderer/src/main/kotlin/MaterialForMkDocsPlugin.kt index d607ba8..16162b0 100644 --- a/renderer/src/main/kotlin/MaterialForMkDocsPlugin.kt +++ b/renderer/src/main/kotlin/MaterialForMkDocsPlugin.kt @@ -1,8 +1,24 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package opensavvy.dokka.material.mkdocs import opensavvy.dokka.material.mkdocs.location.MarkdownLocationProvider import opensavvy.dokka.material.mkdocs.renderer.BriefCommentPreprocessor -import opensavvy.dokka.material.mkdocs.renderer.MkDocsRenderer2 +import opensavvy.dokka.material.mkdocs.renderer3.MkDocsRenderer3 import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.renderers.PackageListCreator @@ -21,7 +37,7 @@ class MaterialForMkDocsPlugin : DokkaPlugin() { val dokkaBase by lazy { plugin() } val renderer: Extension by extending { - CoreExtensions.renderer providing ::MkDocsRenderer2 override dokkaBase.htmlRenderer + CoreExtensions.renderer providing ::MkDocsRenderer3 override dokkaBase.htmlRenderer } val locationProvider: Extension by extending { diff --git a/renderer/src/main/kotlin/renderer3/MkDocsRenderer3.kt b/renderer/src/main/kotlin/renderer3/MkDocsRenderer3.kt new file mode 100644 index 0000000..958218b --- /dev/null +++ b/renderer/src/main/kotlin/renderer3/MkDocsRenderer3.kt @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.dokka.material.mkdocs.renderer3 + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import opensavvy.dokka.material.mkdocs.MaterialForMkDocsPlugin +import org.jetbrains.dokka.DokkaException +import org.jetbrains.dokka.base.DokkaBase +import org.jetbrains.dokka.base.resolvers.local.LocationProvider +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.query +import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.dokka.renderers.Renderer + +class MkDocsRenderer3( + private val context: DokkaContext, +) : Renderer { + private val outputWriter = context.plugin().querySingle { outputWriter } + private val preprocessors = context.plugin().query { mkdocsPreprocessor } + private lateinit var locationProvider: LocationProvider + + override fun render(root: RootPageNode) { + val newRoot = preprocessors.fold(root) { acc, t -> t(acc) } + + locationProvider = + context.plugin().querySingle { locationProviderFactory }.getLocationProvider(newRoot) + + runBlocking(Dispatchers.Default) { + renderPages(newRoot) + } + } + + private fun CoroutineScope.renderPages(page: PageNode) { + launch { + renderPage(page) + } + + for (child in page.children) + renderPages(child) + } + + private suspend fun renderPage(page: PageNode) { + val path by lazy { + locationProvider.resolve(page, skipExtension = true) + ?: throw DokkaException("Cannot resolve path for ${page.name}") + } + when (page) { + is ContentPage -> outputWriter.write(path, buildPage(page), ".md") + is RendererSpecificPage -> when (val strategy = page.strategy) { + is RenderingStrategy.Copy -> outputWriter.writeResources(strategy.from, path) + is RenderingStrategy.Write -> outputWriter.write(path, strategy.text, "") + is RenderingStrategy.Callback -> outputWriter.write(path, strategy.instructions(this, page), ".html") + is RenderingStrategy.DriLocationResolvableWrite -> outputWriter.write( + path, + strategy.contentToResolve { dri, sourcesets -> + locationProvider.resolve(dri, sourcesets) + }, + "" + ) + + is RenderingStrategy.PageLocationResolvableWrite -> outputWriter.write( + path, + strategy.contentToResolve { pageToLocate, context -> + locationProvider.resolve(pageToLocate, context) + }, + "" + ) + + RenderingStrategy.DoNothing -> Unit + } + + else -> throw AssertionError( + "Page ${page.name} cannot be rendered by renderer as it is not renderer specific nor contains content" + ) + } + } + + private suspend fun buildPage(page: ContentPage): String = + "The contents of the page ${page.dri}" +} -- 2.51.2 From 14f765305658f1e31871a72120d104ba3458eed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 8 Jan 2025 17:12:14 +0100 Subject: [PATCH 03/24] feat(renderer): Page metadata & navigation bar --- renderer/src/main/kotlin/renderer3/Links.kt | 30 ++++++++ .../main/kotlin/renderer3/MkDocsRenderer3.kt | 19 ++++- renderer/src/main/kotlin/renderer3/Page.kt | 70 +++++++++++++++++++ .../main/kotlin/renderer3/RenderingContext.kt | 26 +++++++ 4 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 renderer/src/main/kotlin/renderer3/Links.kt create mode 100644 renderer/src/main/kotlin/renderer3/Page.kt create mode 100644 renderer/src/main/kotlin/renderer3/RenderingContext.kt diff --git a/renderer/src/main/kotlin/renderer3/Links.kt b/renderer/src/main/kotlin/renderer3/Links.kt new file mode 100644 index 0000000..4588ab6 --- /dev/null +++ b/renderer/src/main/kotlin/renderer3/Links.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.dokka.material.mkdocs.renderer3 + +import org.jetbrains.dokka.pages.PageNode + +internal fun RenderingContext.buildLink(to: PageNode, from: PageNode) = + buildLink(locations.resolve(to, from, skipExtension = true)!! + ".html") { + append(to.name) + } + +internal fun RenderingContext.buildLink(address: String, label: RenderingContext.() -> Unit) { + append("") + label() + append("") +} diff --git a/renderer/src/main/kotlin/renderer3/MkDocsRenderer3.kt b/renderer/src/main/kotlin/renderer3/MkDocsRenderer3.kt index 958218b..61e1127 100644 --- a/renderer/src/main/kotlin/renderer3/MkDocsRenderer3.kt +++ b/renderer/src/main/kotlin/renderer3/MkDocsRenderer3.kt @@ -94,6 +94,21 @@ class MkDocsRenderer3( } } - private suspend fun buildPage(page: ContentPage): String = - "The contents of the page ${page.dri}" + private fun buildPage(page: ContentPage): String { + val writer = StringBuilder() + + val context = RenderingContext( + locations = locationProvider, + writer = writer, + page = page, + ) + + with(context) { + buildFrontMatter() + buildNavigation() + appendLine("Page ${page.dri}") + } + + return writer.toString() + } } diff --git a/renderer/src/main/kotlin/renderer3/Page.kt b/renderer/src/main/kotlin/renderer3/Page.kt new file mode 100644 index 0000000..cc60885 --- /dev/null +++ b/renderer/src/main/kotlin/renderer3/Page.kt @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.dokka.material.mkdocs.renderer3 + +import org.jetbrains.dokka.pages.* + +internal fun RenderingContext.buildFrontMatter() { + appendLine("---") + appendLine("tags:") + (page as? WithDocumentables) + ?.documentables + ?.flatMapTo(HashSet()) { it.sourceSets } + ?.map { it.analysisPlatform.key } + ?.forEach { + appendLine(" - $it") + } + page.content + .children + .flatMap { + if (it is ContentGroup) + it.children + else listOf(it) + } + .filterIsInstance() + .firstOrNull { it.level == 1 } + ?.children + ?.filterIsInstance() + ?.joinToString(" ") { it.text } + ?.also { appendLine("title: \"$it\"") } + appendLine("---") + appendLine() +} + +internal fun RenderingContext.buildNavigation() { + var first = true + + locations.ancestors(page).asReversed() + .filter { it.name.isNotBlank() } + .takeIf { it.size > 1 }.orEmpty() // Don't render the navigation bar for module pages + .forEach { node -> + if (first) { + first = false + } else { + append(" • ") + } + + if (node.isNavigable) buildLink(node, page) + else append(node.name) + } + + appendLine() + appendLine() +} + +private val PageNode.isNavigable: Boolean + get() = this !is RendererSpecificPage || strategy != RenderingStrategy.DoNothing diff --git a/renderer/src/main/kotlin/renderer3/RenderingContext.kt b/renderer/src/main/kotlin/renderer3/RenderingContext.kt new file mode 100644 index 0000000..11fa585 --- /dev/null +++ b/renderer/src/main/kotlin/renderer3/RenderingContext.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.dokka.material.mkdocs.renderer3 + +import org.jetbrains.dokka.base.resolvers.local.LocationProvider +import org.jetbrains.dokka.pages.ContentPage + +internal class RenderingContext( + val locations: LocationProvider, + val writer: StringBuilder, + val page: ContentPage, +) : Appendable by writer, CharSequence by writer -- 2.51.2 From 3ce5d14aaa249b23a56113d80766c831e7acbb6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 8 Jan 2025 17:39:08 +0100 Subject: [PATCH 04/24] feat(renderer): Display headers and simple text --- renderer/src/main/kotlin/renderer3/Content.kt | 34 ++++++++++++++++ renderer/src/main/kotlin/renderer3/Header.kt | 40 +++++++++++++++++++ .../main/kotlin/renderer3/MkDocsRenderer3.kt | 2 +- .../main/kotlin/renderer3/RenderingContext.kt | 8 +++- renderer/src/main/kotlin/renderer3/Text.kt | 25 ++++++++++++ 5 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 renderer/src/main/kotlin/renderer3/Content.kt create mode 100644 renderer/src/main/kotlin/renderer3/Header.kt create mode 100644 renderer/src/main/kotlin/renderer3/Text.kt diff --git a/renderer/src/main/kotlin/renderer3/Content.kt b/renderer/src/main/kotlin/renderer3/Content.kt new file mode 100644 index 0000000..3fd704c --- /dev/null +++ b/renderer/src/main/kotlin/renderer3/Content.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.dokka.material.mkdocs.renderer3 + +import org.jetbrains.dokka.pages.* + +internal fun RenderingContext.buildContent(node: ContentNode) { + when (node) { + is ContentText -> buildText(node) + is ContentHeader -> buildHeader(node) + is ContentGroup -> buildGroup(node) + else -> appendParagraph("[Unknown content of type ${node::class}]") + } +} + +internal fun RenderingContext.buildGroup(node: ContentComposite) { + for (child in node.children) { + buildContent(child) + } +} diff --git a/renderer/src/main/kotlin/renderer3/Header.kt b/renderer/src/main/kotlin/renderer3/Header.kt new file mode 100644 index 0000000..1bb425a --- /dev/null +++ b/renderer/src/main/kotlin/renderer3/Header.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.dokka.material.mkdocs.renderer3 + +import opensavvy.dokka.material.mkdocs.renderer.Decoration +import opensavvy.dokka.material.mkdocs.renderer.wrapIn +import org.jetbrains.dokka.pages.ContentHeader + +internal fun RenderingContext.buildHeader( + header: ContentHeader, +) { + val decorator = when (header.level) { + 1 -> Decoration.ofPrefix("# ") + 2 -> Decoration.ofPrefix("## ") + 3 -> Decoration.ofPrefix("### ") + 4 -> Decoration.ofPrefix("#### ") + 5 -> Decoration.ofPrefix("##### ") + else -> Decoration.ofPrefix("###### ") + } + + decorator.wrapIn(writer) { + buildGroup(header) + } + + appendLine() +} diff --git a/renderer/src/main/kotlin/renderer3/MkDocsRenderer3.kt b/renderer/src/main/kotlin/renderer3/MkDocsRenderer3.kt index 61e1127..5772411 100644 --- a/renderer/src/main/kotlin/renderer3/MkDocsRenderer3.kt +++ b/renderer/src/main/kotlin/renderer3/MkDocsRenderer3.kt @@ -106,7 +106,7 @@ class MkDocsRenderer3( with(context) { buildFrontMatter() buildNavigation() - appendLine("Page ${page.dri}") + buildContent(page.content) } return writer.toString() diff --git a/renderer/src/main/kotlin/renderer3/RenderingContext.kt b/renderer/src/main/kotlin/renderer3/RenderingContext.kt index 11fa585..7d4e573 100644 --- a/renderer/src/main/kotlin/renderer3/RenderingContext.kt +++ b/renderer/src/main/kotlin/renderer3/RenderingContext.kt @@ -23,4 +23,10 @@ internal class RenderingContext( val locations: LocationProvider, val writer: StringBuilder, val page: ContentPage, -) : Appendable by writer, CharSequence by writer +) : Appendable by writer, CharSequence by writer { + + fun appendParagraph(text: String) { + appendLine(text) + appendLine() + } +} diff --git a/renderer/src/main/kotlin/renderer3/Text.kt b/renderer/src/main/kotlin/renderer3/Text.kt new file mode 100644 index 0000000..23c1870 --- /dev/null +++ b/renderer/src/main/kotlin/renderer3/Text.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.dokka.material.mkdocs.renderer3 + +import org.jetbrains.dokka.pages.ContentText + +internal fun RenderingContext.buildText(node: ContentText) { + appendLine(node.text) + + // TODO: handle entities within text (italics…) +} -- 2.51.2 From a88d992dc623dbeb9e0ced884f79e9aa776b4896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 18 Jan 2025 17:57:38 +0100 Subject: [PATCH 05/24] feat(renderer): Display platform-specific content --- renderer/src/main/kotlin/renderer3/Content.kt | 2 + .../main/kotlin/renderer3/PlatformSpecific.kt | 72 +++++++++++++++++++ .../main/kotlin/renderer3/RenderingContext.kt | 2 +- 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 renderer/src/main/kotlin/renderer3/PlatformSpecific.kt diff --git a/renderer/src/main/kotlin/renderer3/Content.kt b/renderer/src/main/kotlin/renderer3/Content.kt index 3fd704c..7cfb34d 100644 --- a/renderer/src/main/kotlin/renderer3/Content.kt +++ b/renderer/src/main/kotlin/renderer3/Content.kt @@ -22,6 +22,8 @@ internal fun RenderingContext.buildContent(node: ContentNode) { when (node) { is ContentText -> buildText(node) is ContentHeader -> buildHeader(node) + is PlatformHintedContent -> buildPlatformHinted(node) + is ContentDivergentGroup -> buildPlatformDivergent(node) is ContentGroup -> buildGroup(node) else -> appendParagraph("[Unknown content of type ${node::class}]") } diff --git a/renderer/src/main/kotlin/renderer3/PlatformSpecific.kt b/renderer/src/main/kotlin/renderer3/PlatformSpecific.kt new file mode 100644 index 0000000..cea33a4 --- /dev/null +++ b/renderer/src/main/kotlin/renderer3/PlatformSpecific.kt @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.dokka.material.mkdocs.renderer3 + +import org.jetbrains.dokka.model.DisplaySourceSet +import org.jetbrains.dokka.pages.ContentDivergentGroup +import org.jetbrains.dokka.pages.ContentNode +import org.jetbrains.dokka.pages.PlatformHintedContent + +private fun RenderingContext.platformMarker(sourceSet: DisplaySourceSet) { + append("${sourceSet.platform.name}") +} + +private fun RenderingContext.platformMarkers(sourceSets: Iterable) { + append("") + for (sourceSet in sourceSets) { + platformMarker(sourceSet) + } + append("") +} + +internal fun RenderingContext.buildPlatformHinted(node: PlatformHintedContent) { + buildPlatformsGroup(node.inner) +} + +internal fun RenderingContext.buildPlatformDivergent(node: ContentDivergentGroup) { + for (instance in node.children) { + for (group in instance.children) { + buildPlatformsGroup(group) + } + } +} + +private fun RenderingContext.buildPlatformsGroup(group: ContentNode) { + append("\n
\n\n") + val bySourceSet = group.children.groupBy { child -> + child.sourceSets.joinToString(", ") { it.name } + } + + for ((sourceSet, specific) in bySourceSet) { + appendLine("=== \"${sourceSet}\"") + appendLine() + + val childWriter = StringBuilder() + val childContext = this.copy(writer = childWriter) + for (child in specific) { + childContext.buildContent(child) + appendLine() + appendLine() + } + childWriter.split("\n") + .map { " $it" } + .forEach { appendLine(it) } + + appendLine() + } + appendLine("\n
\n") +} diff --git a/renderer/src/main/kotlin/renderer3/RenderingContext.kt b/renderer/src/main/kotlin/renderer3/RenderingContext.kt index 7d4e573..04a5c6a 100644 --- a/renderer/src/main/kotlin/renderer3/RenderingContext.kt +++ b/renderer/src/main/kotlin/renderer3/RenderingContext.kt @@ -19,7 +19,7 @@ package opensavvy.dokka.material.mkdocs.renderer3 import org.jetbrains.dokka.base.resolvers.local.LocationProvider import org.jetbrains.dokka.pages.ContentPage -internal class RenderingContext( +internal data class RenderingContext( val locations: LocationProvider, val writer: StringBuilder, val page: ContentPage, -- 2.51.2 From 2137eed5b55883a61b52c550e625250f92542198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 18 Jan 2025 18:45:49 +0100 Subject: [PATCH 06/24] feat(renderer): Implement code block headers --- renderer/src/main/kotlin/renderer3/Content.kt | 6 -- .../src/main/kotlin/renderer3/Decorator.kt | 65 +++++++++++++++++++ renderer/src/main/kotlin/renderer3/Groups.kt | 37 +++++++++++ renderer/src/main/kotlin/renderer3/Text.kt | 19 +++++- 4 files changed, 118 insertions(+), 9 deletions(-) create mode 100644 renderer/src/main/kotlin/renderer3/Decorator.kt create mode 100644 renderer/src/main/kotlin/renderer3/Groups.kt diff --git a/renderer/src/main/kotlin/renderer3/Content.kt b/renderer/src/main/kotlin/renderer3/Content.kt index 7cfb34d..2b4d067 100644 --- a/renderer/src/main/kotlin/renderer3/Content.kt +++ b/renderer/src/main/kotlin/renderer3/Content.kt @@ -28,9 +28,3 @@ internal fun RenderingContext.buildContent(node: ContentNode) { else -> appendParagraph("[Unknown content of type ${node::class}]") } } - -internal fun RenderingContext.buildGroup(node: ContentComposite) { - for (child in node.children) { - buildContent(child) - } -} diff --git a/renderer/src/main/kotlin/renderer3/Decorator.kt b/renderer/src/main/kotlin/renderer3/Decorator.kt new file mode 100644 index 0000000..dcabec1 --- /dev/null +++ b/renderer/src/main/kotlin/renderer3/Decorator.kt @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.dokka.material.mkdocs.renderer3 + +import org.jetbrains.dokka.pages.ContentNode +import org.jetbrains.dokka.pages.Style +import org.jetbrains.dokka.pages.hasStyle + +internal fun interface Decorator { + fun RenderingContext.decorate(content: RenderingContext.() -> Unit) + + companion object { + fun ofPrefix(prefix: String) = Decorator { content -> + append(prefix) + content() + } + + fun ofElement(elementName: String) = Decorator { content -> + append("<$elementName>") + content() + append("") + } + + fun ofSpan(className: String) = Decorator { content -> + append("") + content() + append("") + } + } +} + +internal fun RenderingContext.decorateWith(decorators: Sequence, block: RenderingContext.() -> Unit) { + decorateWith(decorators.iterator(), block) +} + +private fun RenderingContext.decorateWith(decorators: Iterator, block: RenderingContext.() -> Unit) { + when { + !decorators.hasNext() -> block(this) + else -> with(decorators.next()) { + decorate { + decorateWith(decorators, block) + } + } + } +} + +internal fun Map.matches(node: ContentNode): Sequence = asSequence() + .filter { (style, _) -> + node.hasStyle(style) + } + .map { (_, decorator) -> decorator } diff --git a/renderer/src/main/kotlin/renderer3/Groups.kt b/renderer/src/main/kotlin/renderer3/Groups.kt new file mode 100644 index 0000000..ae15ef7 --- /dev/null +++ b/renderer/src/main/kotlin/renderer3/Groups.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.dokka.material.mkdocs.renderer3 + +import org.jetbrains.dokka.pages.ContentComposite +import org.jetbrains.dokka.pages.TextStyle + +private val groupStyles = mapOf( + TextStyle.Monospace to Decorator { content -> + append("
\n")
+		content()
+		append("\n
") + }, +) + +internal fun RenderingContext.buildGroup(node: ContentComposite) { + decorateWith(groupStyles.matches(node)) { + for (child in node.children) { + buildContent(child) + } + appendLine() + } +} diff --git a/renderer/src/main/kotlin/renderer3/Text.kt b/renderer/src/main/kotlin/renderer3/Text.kt index 23c1870..94705c2 100644 --- a/renderer/src/main/kotlin/renderer3/Text.kt +++ b/renderer/src/main/kotlin/renderer3/Text.kt @@ -17,9 +17,22 @@ package opensavvy.dokka.material.mkdocs.renderer3 import org.jetbrains.dokka.pages.ContentText +import org.jetbrains.dokka.pages.TokenStyle -internal fun RenderingContext.buildText(node: ContentText) { - appendLine(node.text) +private val textStyles = mapOf( + TokenStyle.Keyword to Decorator.ofSpan("kd"), + TokenStyle.Punctuation to Decorator.ofSpan("p"), + TokenStyle.Function to Decorator.ofSpan("nf"), + TokenStyle.Operator to Decorator.ofSpan("o"), + TokenStyle.Annotation to Decorator.ofSpan("se"), + TokenStyle.Number to Decorator.ofSpan("mi"), + TokenStyle.String to Decorator.ofSpan("s"), + TokenStyle.Boolean to Decorator.ofSpan("kc"), + TokenStyle.Constant to Decorator.ofSpan("nb"), +) - // TODO: handle entities within text (italics…) +internal fun RenderingContext.buildText(node: ContentText) { + decorateWith(textStyles.matches(node)) { + append(node.text) + } } -- 2.51.2 From 45bc4ebdf28c1ba81c41758e77ed930231504b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 18 Jan 2025 19:09:07 +0100 Subject: [PATCH 07/24] feat(renderer): Resolve links to other pages --- renderer/src/main/kotlin/renderer3/Content.kt | 1 + renderer/src/main/kotlin/renderer3/Groups.kt | 7 +++++-- renderer/src/main/kotlin/renderer3/Links.kt | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/renderer/src/main/kotlin/renderer3/Content.kt b/renderer/src/main/kotlin/renderer3/Content.kt index 2b4d067..fc32941 100644 --- a/renderer/src/main/kotlin/renderer3/Content.kt +++ b/renderer/src/main/kotlin/renderer3/Content.kt @@ -24,6 +24,7 @@ internal fun RenderingContext.buildContent(node: ContentNode) { is ContentHeader -> buildHeader(node) is PlatformHintedContent -> buildPlatformHinted(node) is ContentDivergentGroup -> buildPlatformDivergent(node) + is ContentDRILink -> buildDRILink(node) is ContentGroup -> buildGroup(node) else -> appendParagraph("[Unknown content of type ${node::class}]") } diff --git a/renderer/src/main/kotlin/renderer3/Groups.kt b/renderer/src/main/kotlin/renderer3/Groups.kt index ae15ef7..b876e61 100644 --- a/renderer/src/main/kotlin/renderer3/Groups.kt +++ b/renderer/src/main/kotlin/renderer3/Groups.kt @@ -21,10 +21,14 @@ import org.jetbrains.dokka.pages.TextStyle private val groupStyles = mapOf( TextStyle.Monospace to Decorator { content -> - append("
\n")
+		append("
")
 		content()
 		append("\n
") }, + TextStyle.Paragraph to Decorator { content -> + content() + appendLine() + } ) internal fun RenderingContext.buildGroup(node: ContentComposite) { @@ -32,6 +36,5 @@ internal fun RenderingContext.buildGroup(node: ContentComposite) { for (child in node.children) { buildContent(child) } - appendLine() } } diff --git a/renderer/src/main/kotlin/renderer3/Links.kt b/renderer/src/main/kotlin/renderer3/Links.kt index 4588ab6..1d49c14 100644 --- a/renderer/src/main/kotlin/renderer3/Links.kt +++ b/renderer/src/main/kotlin/renderer3/Links.kt @@ -16,6 +16,7 @@ package opensavvy.dokka.material.mkdocs.renderer3 +import org.jetbrains.dokka.pages.ContentDRILink import org.jetbrains.dokka.pages.PageNode internal fun RenderingContext.buildLink(to: PageNode, from: PageNode) = @@ -28,3 +29,19 @@ internal fun RenderingContext.buildLink(address: String, label: RenderingContext label() append("") } + +internal fun RenderingContext.buildDRILink(link: ContentDRILink) { + var address = locations.resolve(link.address, link.sourceSets, page) + + if (address != null && address.endsWith(".md")) { + address = address.removeSuffix(".md") + ".html" + } + + if (address != null) { + buildLink(address) { + buildGroup(link) + } + } else { + buildGroup(link) + } +} -- 2.51.2 From 6d38ecda314170aa184d4ca560c0a30b1d1f1888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Thu, 20 Feb 2025 21:34:09 +0100 Subject: [PATCH 08/24] feat(renderer): Support bold, italic & strikethrough --- renderer/src/main/kotlin/renderer3/Text.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/renderer/src/main/kotlin/renderer3/Text.kt b/renderer/src/main/kotlin/renderer3/Text.kt index 94705c2..6377fb4 100644 --- a/renderer/src/main/kotlin/renderer3/Text.kt +++ b/renderer/src/main/kotlin/renderer3/Text.kt @@ -17,9 +17,11 @@ package opensavvy.dokka.material.mkdocs.renderer3 import org.jetbrains.dokka.pages.ContentText +import org.jetbrains.dokka.pages.Style +import org.jetbrains.dokka.pages.TextStyle import org.jetbrains.dokka.pages.TokenStyle -private val textStyles = mapOf( +private val textStyles: Map = mapOf( TokenStyle.Keyword to Decorator.ofSpan("kd"), TokenStyle.Punctuation to Decorator.ofSpan("p"), TokenStyle.Function to Decorator.ofSpan("nf"), @@ -29,6 +31,10 @@ private val textStyles = mapOf( TokenStyle.String to Decorator.ofSpan("s"), TokenStyle.Boolean to Decorator.ofSpan("kc"), TokenStyle.Constant to Decorator.ofSpan("nb"), + + TextStyle.Strong to Decorator.ofElement("strong"), + TextStyle.Italic to Decorator.ofElement("em"), + TextStyle.Strikethrough to Decorator.ofElement("s"), ) internal fun RenderingContext.buildText(node: ContentText) { -- 2.51.2 From 95ff74457d19630d55a266889d5683643d0e79bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Thu, 20 Feb 2025 21:45:35 +0100 Subject: [PATCH 09/24] feat(renderer): Support inline code blocks --- renderer/src/main/kotlin/renderer3/Content.kt | 1 + renderer/src/main/kotlin/renderer3/Text.kt | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/renderer/src/main/kotlin/renderer3/Content.kt b/renderer/src/main/kotlin/renderer3/Content.kt index fc32941..4dc3f44 100644 --- a/renderer/src/main/kotlin/renderer3/Content.kt +++ b/renderer/src/main/kotlin/renderer3/Content.kt @@ -21,6 +21,7 @@ import org.jetbrains.dokka.pages.* internal fun RenderingContext.buildContent(node: ContentNode) { when (node) { is ContentText -> buildText(node) + is ContentCodeInline -> buildCodeInline(node) is ContentHeader -> buildHeader(node) is PlatformHintedContent -> buildPlatformHinted(node) is ContentDivergentGroup -> buildPlatformDivergent(node) diff --git a/renderer/src/main/kotlin/renderer3/Text.kt b/renderer/src/main/kotlin/renderer3/Text.kt index 6377fb4..24b7173 100644 --- a/renderer/src/main/kotlin/renderer3/Text.kt +++ b/renderer/src/main/kotlin/renderer3/Text.kt @@ -16,10 +16,7 @@ package opensavvy.dokka.material.mkdocs.renderer3 -import org.jetbrains.dokka.pages.ContentText -import org.jetbrains.dokka.pages.Style -import org.jetbrains.dokka.pages.TextStyle -import org.jetbrains.dokka.pages.TokenStyle +import org.jetbrains.dokka.pages.* private val textStyles: Map = mapOf( TokenStyle.Keyword to Decorator.ofSpan("kd"), @@ -42,3 +39,13 @@ internal fun RenderingContext.buildText(node: ContentText) { append(node.text) } } + +internal fun RenderingContext.buildCodeInline(node: ContentCodeInline) { + if (node.language.isNotBlank()) { + append("`#!${node.language} ") + } else { + append("`") + } + buildGroup(node) + append("`") +} -- 2.51.2 From 027438ffb442d08e3cccbec8c68cd581c013e33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Thu, 20 Feb 2025 21:48:03 +0100 Subject: [PATCH 10/24] feat(renderer): Fix paragraphs --- renderer/src/main/kotlin/renderer3/Groups.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/renderer/src/main/kotlin/renderer3/Groups.kt b/renderer/src/main/kotlin/renderer3/Groups.kt index b876e61..de65136 100644 --- a/renderer/src/main/kotlin/renderer3/Groups.kt +++ b/renderer/src/main/kotlin/renderer3/Groups.kt @@ -28,6 +28,7 @@ private val groupStyles = mapOf( TextStyle.Paragraph to Decorator { content -> content() appendLine() + appendLine() } ) -- 2.51.2 From 82de9568dd8da7239051b313f520717b871cdee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Thu, 20 Feb 2025 21:52:40 +0100 Subject: [PATCH 11/24] feat(renderer): Support links to external addresses --- renderer/src/main/kotlin/renderer3/Content.kt | 1 + renderer/src/main/kotlin/renderer3/Links.kt | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/renderer/src/main/kotlin/renderer3/Content.kt b/renderer/src/main/kotlin/renderer3/Content.kt index 4dc3f44..5d9fbdb 100644 --- a/renderer/src/main/kotlin/renderer3/Content.kt +++ b/renderer/src/main/kotlin/renderer3/Content.kt @@ -26,6 +26,7 @@ internal fun RenderingContext.buildContent(node: ContentNode) { is PlatformHintedContent -> buildPlatformHinted(node) is ContentDivergentGroup -> buildPlatformDivergent(node) is ContentDRILink -> buildDRILink(node) + is ContentResolvedLink -> buildResolvedLink(node) is ContentGroup -> buildGroup(node) else -> appendParagraph("[Unknown content of type ${node::class}]") } diff --git a/renderer/src/main/kotlin/renderer3/Links.kt b/renderer/src/main/kotlin/renderer3/Links.kt index 1d49c14..5d93fca 100644 --- a/renderer/src/main/kotlin/renderer3/Links.kt +++ b/renderer/src/main/kotlin/renderer3/Links.kt @@ -17,6 +17,7 @@ package opensavvy.dokka.material.mkdocs.renderer3 import org.jetbrains.dokka.pages.ContentDRILink +import org.jetbrains.dokka.pages.ContentResolvedLink import org.jetbrains.dokka.pages.PageNode internal fun RenderingContext.buildLink(to: PageNode, from: PageNode) = @@ -45,3 +46,9 @@ internal fun RenderingContext.buildDRILink(link: ContentDRILink) { buildGroup(link) } } + +internal fun RenderingContext.buildResolvedLink(link: ContentResolvedLink) { + buildLink(link.address) { + buildGroup(link) + } +} -- 2.51.2 From 8d23cc716281af07765d4f322c21b83db2947b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Thu, 20 Feb 2025 22:14:34 +0100 Subject: [PATCH 12/24] feat(renderer): Support package lists, type lists, function & constructor lists, and property lists --- renderer/src/main/kotlin/renderer3/Content.kt | 1 + renderer/src/main/kotlin/renderer3/Tables.kt | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 renderer/src/main/kotlin/renderer3/Tables.kt diff --git a/renderer/src/main/kotlin/renderer3/Content.kt b/renderer/src/main/kotlin/renderer3/Content.kt index 5d9fbdb..f50c048 100644 --- a/renderer/src/main/kotlin/renderer3/Content.kt +++ b/renderer/src/main/kotlin/renderer3/Content.kt @@ -28,6 +28,7 @@ internal fun RenderingContext.buildContent(node: ContentNode) { is ContentDRILink -> buildDRILink(node) is ContentResolvedLink -> buildResolvedLink(node) is ContentGroup -> buildGroup(node) + is ContentTable -> buildTable(node) else -> appendParagraph("[Unknown content of type ${node::class}]") } } diff --git a/renderer/src/main/kotlin/renderer3/Tables.kt b/renderer/src/main/kotlin/renderer3/Tables.kt new file mode 100644 index 0000000..94fbfb9 --- /dev/null +++ b/renderer/src/main/kotlin/renderer3/Tables.kt @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.dokka.material.mkdocs.renderer3 + +import org.jetbrains.dokka.pages.ContentDRILink +import org.jetbrains.dokka.pages.ContentHeader +import org.jetbrains.dokka.pages.ContentKind +import org.jetbrains.dokka.pages.ContentTable + +internal fun RenderingContext.buildTable(node: ContentTable) { + when (node.dci.kind) { + ContentKind.Packages, ContentKind.Classlikes, + ContentKind.Functions, ContentKind.Constructors, + ContentKind.Properties, + -> { + buildTableAsSections(node) + } + + else -> appendParagraph("[Unknown table of kind ${node.dci.kind}]") + } +} + +private fun RenderingContext.buildTableAsSections(node: ContentTable) { + for (pkg in node.children) { + for (child in pkg.children) { + if (child is ContentDRILink) { + buildHeader( + ContentHeader( + listOf(child), + 3, + child.dci, + child.sourceSets, + child.style, + child.extra, + ) + ) + } else { + buildContent(child) + } + } + } +} -- 2.51.2 From a77bfa1c9bcab1caf921d5266a1a01128ea4be31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Thu, 20 Feb 2025 22:26:04 +0100 Subject: [PATCH 13/24] feat(renderer): If a symbol is only supported on one platform, do not generate platform-specific tabs --- .../main/kotlin/renderer3/PlatformSpecific.kt | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/renderer/src/main/kotlin/renderer3/PlatformSpecific.kt b/renderer/src/main/kotlin/renderer3/PlatformSpecific.kt index cea33a4..54aabcc 100644 --- a/renderer/src/main/kotlin/renderer3/PlatformSpecific.kt +++ b/renderer/src/main/kotlin/renderer3/PlatformSpecific.kt @@ -51,22 +51,31 @@ private fun RenderingContext.buildPlatformsGroup(group: ContentNode) { child.sourceSets.joinToString(", ") { it.name } } - for ((sourceSet, specific) in bySourceSet) { - appendLine("=== \"${sourceSet}\"") - appendLine() - - val childWriter = StringBuilder() - val childContext = this.copy(writer = childWriter) - for (child in specific) { - childContext.buildContent(child) + if (bySourceSet.size == 1) { + // There is a single available platform for this definition, + // no need to emit the different tabs. + for (child in group.children) { + buildContent(child) + } + } else { + for ((sourceSet, specific) in bySourceSet) { + appendLine("=== \"${sourceSet}\"") appendLine() + + val childWriter = StringBuilder() + val childContext = this.copy(writer = childWriter) + for (child in specific) { + childContext.buildContent(child) + appendLine() + appendLine() + } + childWriter.split("\n") + .map { " $it" } + .forEach { appendLine(it) } + appendLine() } - childWriter.split("\n") - .map { " $it" } - .forEach { appendLine(it) } - - appendLine() } + appendLine("\n
\n") } -- 2.51.2 From 5500dab3040db72047889b90aec1b7fa51c219f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 22 Feb 2025 17:25:05 +0100 Subject: [PATCH 14/24] fix(renderer): Fix nested code blocks in type aliases --- renderer/src/main/kotlin/renderer3/Groups.kt | 10 +++++++--- renderer/src/main/kotlin/renderer3/RenderingContext.kt | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/renderer/src/main/kotlin/renderer3/Groups.kt b/renderer/src/main/kotlin/renderer3/Groups.kt index de65136..be85ff9 100644 --- a/renderer/src/main/kotlin/renderer3/Groups.kt +++ b/renderer/src/main/kotlin/renderer3/Groups.kt @@ -21,9 +21,13 @@ import org.jetbrains.dokka.pages.TextStyle private val groupStyles = mapOf( TextStyle.Monospace to Decorator { content -> - append("
")
-		content()
-		append("\n
") + if (!this.isInCodeBlock) + append("
")
+		with(this.copy(isInCodeBlock = true)) {
+			content()
+		}
+		if (!this.isInCodeBlock)
+			append("\n
") }, TextStyle.Paragraph to Decorator { content -> content() diff --git a/renderer/src/main/kotlin/renderer3/RenderingContext.kt b/renderer/src/main/kotlin/renderer3/RenderingContext.kt index 04a5c6a..a98a6e9 100644 --- a/renderer/src/main/kotlin/renderer3/RenderingContext.kt +++ b/renderer/src/main/kotlin/renderer3/RenderingContext.kt @@ -23,6 +23,7 @@ internal data class RenderingContext( val locations: LocationProvider, val writer: StringBuilder, val page: ContentPage, + val isInCodeBlock: Boolean = false, ) : Appendable by writer, CharSequence by writer { fun appendParagraph(text: String) { -- 2.51.2 From 8186f1f7c51a7b23a58895ccb87893041d340492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 22 Feb 2025 17:30:40 +0100 Subject: [PATCH 15/24] feat(renderer): Annotations are displayed on their own line --- renderer/src/main/kotlin/renderer3/Text.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/renderer/src/main/kotlin/renderer3/Text.kt b/renderer/src/main/kotlin/renderer3/Text.kt index 24b7173..54c7665 100644 --- a/renderer/src/main/kotlin/renderer3/Text.kt +++ b/renderer/src/main/kotlin/renderer3/Text.kt @@ -38,6 +38,10 @@ internal fun RenderingContext.buildText(node: ContentText) { decorateWith(textStyles.matches(node)) { append(node.text) } + + if (node.hasStyle(TokenStyle.Annotation) && node.text != "@") { + appendLine() + } } internal fun RenderingContext.buildCodeInline(node: ContentCodeInline) { -- 2.51.2 From 0833f31a384decbfcd95fa4929452bccdd748389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 22 Feb 2025 17:46:12 +0100 Subject: [PATCH 16/24] feat(renderer): Support inheritors lists for sealed interfaces & classes --- renderer/src/main/kotlin/renderer3/Tables.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/renderer/src/main/kotlin/renderer3/Tables.kt b/renderer/src/main/kotlin/renderer3/Tables.kt index 94fbfb9..f20eabd 100644 --- a/renderer/src/main/kotlin/renderer3/Tables.kt +++ b/renderer/src/main/kotlin/renderer3/Tables.kt @@ -30,6 +30,10 @@ internal fun RenderingContext.buildTable(node: ContentTable) { buildTableAsSections(node) } + ContentKind.Inheritors -> { + buildTableAsList(node) + } + else -> appendParagraph("[Unknown table of kind ${node.dci.kind}]") } } @@ -54,3 +58,17 @@ private fun RenderingContext.buildTableAsSections(node: ContentTable) { } } } + +private fun RenderingContext.buildTableAsList(node: ContentTable) { + appendLine() + appendLine() + + for (child in node.children) { + append(" - ") + buildContent(child) + appendLine() + } + + appendLine() + appendLine() +} -- 2.51.2 From 0a4b44333614d35dd4855c49661a95cfbc567097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 22 Feb 2025 17:54:37 +0100 Subject: [PATCH 17/24] feat(renderer): Exclude the generated navigation links from website search --- renderer/src/main/kotlin/renderer3/Page.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/renderer/src/main/kotlin/renderer3/Page.kt b/renderer/src/main/kotlin/renderer3/Page.kt index cc60885..35deea3 100644 --- a/renderer/src/main/kotlin/renderer3/Page.kt +++ b/renderer/src/main/kotlin/renderer3/Page.kt @@ -48,10 +48,10 @@ internal fun RenderingContext.buildFrontMatter() { internal fun RenderingContext.buildNavigation() { var first = true - locations.ancestors(page).asReversed() + val targets = locations.ancestors(page).asReversed() .filter { it.name.isNotBlank() } - .takeIf { it.size > 1 }.orEmpty() // Don't render the navigation bar for module pages - .forEach { node -> + .takeIf { it.size > 1 } // Don't render the navigation bar for module pages + ?.forEach { node -> if (first) { first = false } else { @@ -61,8 +61,9 @@ internal fun RenderingContext.buildNavigation() { if (node.isNavigable) buildLink(node, page) else append(node.name) } - appendLine() + if (targets != null) + appendLine(" { data-search-exclude }") appendLine() } -- 2.51.2 From 0d9dc1b9cf9303bf6f82a37f5587de690aa271d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 22 Feb 2025 18:18:23 +0100 Subject: [PATCH 18/24] feat(renderer): Support code blocks --- renderer/src/main/kotlin/renderer3/Content.kt | 2 ++ renderer/src/main/kotlin/renderer3/Text.kt | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/renderer/src/main/kotlin/renderer3/Content.kt b/renderer/src/main/kotlin/renderer3/Content.kt index f50c048..07d67ba 100644 --- a/renderer/src/main/kotlin/renderer3/Content.kt +++ b/renderer/src/main/kotlin/renderer3/Content.kt @@ -22,6 +22,7 @@ internal fun RenderingContext.buildContent(node: ContentNode) { when (node) { is ContentText -> buildText(node) is ContentCodeInline -> buildCodeInline(node) + is ContentCodeBlock -> buildCodeBlock(node) is ContentHeader -> buildHeader(node) is PlatformHintedContent -> buildPlatformHinted(node) is ContentDivergentGroup -> buildPlatformDivergent(node) @@ -29,6 +30,7 @@ internal fun RenderingContext.buildContent(node: ContentNode) { is ContentResolvedLink -> buildResolvedLink(node) is ContentGroup -> buildGroup(node) is ContentTable -> buildTable(node) + is ContentBreakLine -> appendLine() else -> appendParagraph("[Unknown content of type ${node::class}]") } } diff --git a/renderer/src/main/kotlin/renderer3/Text.kt b/renderer/src/main/kotlin/renderer3/Text.kt index 54c7665..fe0f94e 100644 --- a/renderer/src/main/kotlin/renderer3/Text.kt +++ b/renderer/src/main/kotlin/renderer3/Text.kt @@ -53,3 +53,10 @@ internal fun RenderingContext.buildCodeInline(node: ContentCodeInline) { buildGroup(node) append("`") } + +internal fun RenderingContext.buildCodeBlock(node: ContentCodeBlock) { + appendLine("```${node.language}") + buildGroup(node) + appendLine("\n```") + appendLine() +} -- 2.51.2 From 2ce843e2c7102dec9690ce1287ecb7f7eacb89c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 22 Feb 2025 18:26:34 +0100 Subject: [PATCH 19/24] feat(renderer): Support ordered and unordered lists --- renderer/src/main/kotlin/renderer3/Content.kt | 1 + renderer/src/main/kotlin/renderer3/Lists.kt | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 renderer/src/main/kotlin/renderer3/Lists.kt diff --git a/renderer/src/main/kotlin/renderer3/Content.kt b/renderer/src/main/kotlin/renderer3/Content.kt index 07d67ba..23840be 100644 --- a/renderer/src/main/kotlin/renderer3/Content.kt +++ b/renderer/src/main/kotlin/renderer3/Content.kt @@ -30,6 +30,7 @@ internal fun RenderingContext.buildContent(node: ContentNode) { is ContentResolvedLink -> buildResolvedLink(node) is ContentGroup -> buildGroup(node) is ContentTable -> buildTable(node) + is ContentList -> buildList(node) is ContentBreakLine -> appendLine() else -> appendParagraph("[Unknown content of type ${node::class}]") } diff --git a/renderer/src/main/kotlin/renderer3/Lists.kt b/renderer/src/main/kotlin/renderer3/Lists.kt new file mode 100644 index 0000000..013483c --- /dev/null +++ b/renderer/src/main/kotlin/renderer3/Lists.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.dokka.material.mkdocs.renderer3 + +import org.jetbrains.dokka.pages.ContentList + +internal fun RenderingContext.buildList(node: ContentList) { + if (node.ordered) { + append("
    ") + } else { + append("
      ") + } + + for (child in node.children) { + append("
    • \n\n") + buildContent(child) + append("\n
    • ") + } + + if (node.ordered) { + append("
") + } else { + append("") + } +} -- 2.51.2 From 8da9a60aee6efdc88ec33df42a28ce27253cdc15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 22 Feb 2025 18:45:16 +0100 Subject: [PATCH 20/24] feat(renderer): Support the @throws tag --- renderer/src/main/kotlin/renderer3/Tables.kt | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/renderer/src/main/kotlin/renderer3/Tables.kt b/renderer/src/main/kotlin/renderer3/Tables.kt index f20eabd..48c9e38 100644 --- a/renderer/src/main/kotlin/renderer3/Tables.kt +++ b/renderer/src/main/kotlin/renderer3/Tables.kt @@ -34,6 +34,10 @@ internal fun RenderingContext.buildTable(node: ContentTable) { buildTableAsList(node) } + ContentKind.Main -> { + buildTableAsDefinitions(node) + } + else -> appendParagraph("[Unknown table of kind ${node.dci.kind}]") } } @@ -72,3 +76,20 @@ private fun RenderingContext.buildTableAsList(node: ContentTable) { appendLine() appendLine() } + +private fun RenderingContext.buildTableAsDefinitions(node: ContentTable) { + appendLine() + appendLine() + + for (child in node.children) { + val (header, body) = child.children + buildContent(header) + append("\n\n") + append(": ") + buildContent(body) + appendLine() + } + + appendLine() + appendLine() +} -- 2.51.2 From 5e46462e0890e72b54ae7ea9a69c8f1e4aa51205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 22 Feb 2025 19:30:54 +0100 Subject: [PATCH 21/24] feat(renderer): Support type parameters --- renderer/src/main/kotlin/renderer3/Tables.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renderer/src/main/kotlin/renderer3/Tables.kt b/renderer/src/main/kotlin/renderer3/Tables.kt index 48c9e38..3fc0839 100644 --- a/renderer/src/main/kotlin/renderer3/Tables.kt +++ b/renderer/src/main/kotlin/renderer3/Tables.kt @@ -34,7 +34,7 @@ internal fun RenderingContext.buildTable(node: ContentTable) { buildTableAsList(node) } - ContentKind.Main -> { + ContentKind.Main, ContentKind.Parameters -> { buildTableAsDefinitions(node) } -- 2.51.2 From dcbb931b56fac351a202afcbf629161e31462aa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 22 Feb 2025 19:31:09 +0100 Subject: [PATCH 22/24] feat(renderer): Support the @see tag --- renderer/src/main/kotlin/renderer3/Tables.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renderer/src/main/kotlin/renderer3/Tables.kt b/renderer/src/main/kotlin/renderer3/Tables.kt index 3fc0839..8ccdae0 100644 --- a/renderer/src/main/kotlin/renderer3/Tables.kt +++ b/renderer/src/main/kotlin/renderer3/Tables.kt @@ -30,7 +30,7 @@ internal fun RenderingContext.buildTable(node: ContentTable) { buildTableAsSections(node) } - ContentKind.Inheritors -> { + ContentKind.Inheritors, ContentKind.Comment -> { buildTableAsList(node) } -- 2.51.2 From 8d481b04f6f3011b47170370a7a0aa91aee7d1c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 22 Feb 2025 21:09:49 +0100 Subject: [PATCH 23/24] feat(renderer): Prefer emitting MarkDown links when possible --- renderer/src/main/kotlin/renderer3/Links.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/renderer/src/main/kotlin/renderer3/Links.kt b/renderer/src/main/kotlin/renderer3/Links.kt index 5d93fca..3b54e7e 100644 --- a/renderer/src/main/kotlin/renderer3/Links.kt +++ b/renderer/src/main/kotlin/renderer3/Links.kt @@ -26,9 +26,15 @@ internal fun RenderingContext.buildLink(to: PageNode, from: PageNode) = } internal fun RenderingContext.buildLink(address: String, label: RenderingContext.() -> Unit) { - append("") - label() - append("") + if (isInCodeBlock) { + append("") + label() + append("") + } else { + append('[') + label() + append("]($address)") + } } internal fun RenderingContext.buildDRILink(link: ContentDRILink) { -- 2.51.2 From 18e088afe42f0d37b0e923893feea73df3d65baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 22 Feb 2025 21:10:07 +0100 Subject: [PATCH 24/24] feat(renderer): Prefer emitting MarkDown lists --- renderer/src/main/kotlin/renderer3/Lists.kt | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/renderer/src/main/kotlin/renderer3/Lists.kt b/renderer/src/main/kotlin/renderer3/Lists.kt index 013483c..5d0ed29 100644 --- a/renderer/src/main/kotlin/renderer3/Lists.kt +++ b/renderer/src/main/kotlin/renderer3/Lists.kt @@ -19,21 +19,13 @@ package opensavvy.dokka.material.mkdocs.renderer3 import org.jetbrains.dokka.pages.ContentList internal fun RenderingContext.buildList(node: ContentList) { - if (node.ordered) { - append("
    ") - } else { - append("
      ") - } + val prefix = + if (node.ordered) "1. " + else " - " for (child in node.children) { - append("
    • \n\n") + append(prefix) buildContent(child) - append("\n
    • ") - } - - if (node.ordered) { - append("
") - } else { - append("") + appendLine() } }