aboutsummaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorPaweł Marks <pmarks@virtuslab.com>2020-09-23 19:48:14 +0200
committerBłażej Kardyś <bkardys@virtuslab.com>2020-11-27 03:15:02 +0100
commit52f64c664573567259f8f678d32924f86b4f147c (patch)
tree0882ce51f477acc71412b36307495a0e0ba97359 /plugins
parent80b6d1824960205e1c1d57c0c51e913d3c2360db (diff)
downloaddokka-52f64c664573567259f8f678d32924f86b4f147c.tar.gz
dokka-52f64c664573567259f8f678d32924f86b4f147c.tar.bz2
dokka-52f64c664573567259f8f678d32924f86b4f147c.zip
Add navigation fragments for templating
Diffstat (limited to 'plugins')
-rw-r--r--plugins/all-module-page/src/main/kotlin/templates/DirectiveBasedTemplateProcessing.kt46
-rw-r--r--plugins/all-module-page/src/main/kotlin/templates/TemplateProcessor.kt11
-rw-r--r--plugins/base/src/main/kotlin/DokkaBase.kt2
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt3
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt15
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/Tags.kt14
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt3
-rw-r--r--plugins/base/src/main/kotlin/templating/AddToNavigationCommand.kt3
-rw-r--r--plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt121
9 files changed, 81 insertions, 137 deletions
diff --git a/plugins/all-module-page/src/main/kotlin/templates/DirectiveBasedTemplateProcessing.kt b/plugins/all-module-page/src/main/kotlin/templates/DirectiveBasedTemplateProcessing.kt
index 7786ca18..705e6678 100644
--- a/plugins/all-module-page/src/main/kotlin/templates/DirectiveBasedTemplateProcessing.kt
+++ b/plugins/all-module-page/src/main/kotlin/templates/DirectiveBasedTemplateProcessing.kt
@@ -4,6 +4,7 @@ import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+import org.jetbrains.dokka.base.templating.AddToNavigationCommand
import org.jetbrains.dokka.base.templating.Command
import org.jetbrains.dokka.base.templating.ResolveLinkCommand
import org.jetbrains.dokka.base.templating.parseJson
@@ -14,8 +15,11 @@ import org.jsoup.nodes.Element
import org.jsoup.parser.Tag
import java.io.File
import java.nio.file.Files
+import java.util.concurrent.ConcurrentHashMap
+
+class DirectiveBasedTemplateProcessingStrategy(private val context: DokkaContext) : TemplateProcessingStrategy {
+ private val navigationFragments = ConcurrentHashMap<String, Element>()
-class DirectiveBasedTemplateProcessingStrategy(context: DokkaContext) : TemplateProcessingStrategy {
override suspend fun process(input: File, output: File): Unit = coroutineScope {
if (input.extension == "html") {
launch {
@@ -23,8 +27,10 @@ class DirectiveBasedTemplateProcessingStrategy(context: DokkaContext) : Template
document.outputSettings().indentAmount(0).prettyPrint(false)
document.select("dokka-template-command").forEach {
val command = parseJson<Command>(it.attr("data"))
- if (command is ResolveLinkCommand) {
- resolveLink(it, command)
+ when (command) {
+ is ResolveLinkCommand -> resolveLink(it, command)
+ is AddToNavigationCommand -> navigationFragments[command.moduleName] = it
+ else -> context.logger.warn("Unknown templating command $command")
}
}
withContext(IO) { Files.writeString(output.toPath(), document.outerHtml()) }
@@ -36,6 +42,40 @@ class DirectiveBasedTemplateProcessingStrategy(context: DokkaContext) : Template
}
}
+ override suspend fun finish(output: File) {
+ val attributes = Attributes().apply {
+ put("class", "sideMenu")
+ }
+ val node = Element(Tag.valueOf("div"), "", attributes)
+ navigationFragments.entries.sortedBy { it.key }.forEach { (moduleName, command) ->
+ command.select("a").forEach { a ->
+ a.attr("href")?.also { a.attr("href", "${moduleName}/${it}") }
+ }
+ command.childNodes().toList().forEachIndexed { index, child ->
+ if (index == 0) {
+ child.attr("id", "$moduleName-nav-submenu")
+ }
+ node.appendChild(child)
+ }
+ }
+
+ withContext(IO) {
+ Files.writeString(output.resolve("navigation.html").toPath(), node.outerHtml())
+ }
+
+ node.select("a").forEach { a ->
+ a.attr("href")?.also { a.attr("href", "../${it}") }
+ }
+ navigationFragments.keys.forEach {
+ withContext(IO) {
+ Files.writeString(
+ output.resolve(it).resolve("navigation.html").toPath(),
+ node.outerHtml()
+ )
+ }
+ }
+ }
+
private fun resolveLink(it: Element, command: ResolveLinkCommand) {
val attributes = Attributes().apply {
put("href", "") // TODO: resolve
diff --git a/plugins/all-module-page/src/main/kotlin/templates/TemplateProcessor.kt b/plugins/all-module-page/src/main/kotlin/templates/TemplateProcessor.kt
index 4c247d94..cd144046 100644
--- a/plugins/all-module-page/src/main/kotlin/templates/TemplateProcessor.kt
+++ b/plugins/all-module-page/src/main/kotlin/templates/TemplateProcessor.kt
@@ -5,6 +5,7 @@ import org.jetbrains.dokka.plugability.DokkaContext
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
+import kotlin.coroutines.coroutineContext
interface TemplateProcessor {
fun process()
@@ -12,6 +13,7 @@ interface TemplateProcessor {
interface TemplateProcessingStrategy {
suspend fun process(input: File, output: File)
+ suspend fun finish(output: File) {}
}
class DefaultTemplateProcessor(
@@ -19,11 +21,14 @@ class DefaultTemplateProcessor(
private val strategy: TemplateProcessingStrategy
): TemplateProcessor {
override fun process() = runBlocking(Dispatchers.Default) {
- context.configuration.modules.forEach {
- launch {
- it.sourceOutputDirectory.visit(context.configuration.outputDir.resolve(it.relativePathToOutputDirectory))
+ coroutineScope {
+ context.configuration.modules.forEach {
+ launch {
+ it.sourceOutputDirectory.visit(context.configuration.outputDir.resolve(it.relativePathToOutputDirectory))
+ }
}
}
+ strategy.finish(context.configuration.outputDir)
}
private suspend fun File.visit(target: File): Unit = coroutineScope {
diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt
index afda6f24..8289447c 100644
--- a/plugins/base/src/main/kotlin/DokkaBase.kt
+++ b/plugins/base/src/main/kotlin/DokkaBase.kt
@@ -209,4 +209,4 @@ class DokkaBase : DokkaPlugin() {
val baseSearchbarDataInstaller by extending {
htmlPreprocessors providing ::SearchbarDataInstaller order { after(sourceLinksTransformer) }
}
-}
+} \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
index 661e1e58..16f60a83 100644
--- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
@@ -706,7 +706,8 @@ open class HtmlRenderer(
buildHtml(page, page.embeddedResources) {
div("main-content") {
id = "content"
- attributes["pageIds"] = page.pageId
+ // TODO: Investigate possible problem
+ attributes["pageIds"] = "${context.configuration.moduleName}::${page.pageId}"
content(this, page)
}
}
diff --git a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt
index 3758b8d3..15d2473f 100644
--- a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt
@@ -3,6 +3,7 @@ package org.jetbrains.dokka.base.renderers.html
import kotlinx.html.*
import kotlinx.html.stream.createHTML
import org.jetbrains.dokka.base.renderers.pageId
+import org.jetbrains.dokka.base.templating.AddToNavigationCommand
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.DisplaySourceSet
import org.jetbrains.dokka.model.WithChildren
@@ -10,7 +11,7 @@ import org.jetbrains.dokka.pages.PageNode
import org.jetbrains.dokka.pages.RendererSpecificPage
import org.jetbrains.dokka.pages.RenderingStrategy
-class NavigationPage(val root: NavigationNode) : RendererSpecificPage {
+class NavigationPage(val root: NavigationNode, val moduleName: String) : RendererSpecificPage {
override val name = "navigation"
override val children = emptyList<PageNode>()
@@ -18,14 +19,20 @@ class NavigationPage(val root: NavigationNode) : RendererSpecificPage {
override fun modified(name: String, children: List<PageNode>) = this
override val strategy = RenderingStrategy<HtmlRenderer> {
- createHTML().visit(root, "nav-submenu", this)
+ createHTML().visit(root, this)
+ }
+
+ private fun <R> TagConsumer<R>.visit(node: NavigationNode, renderer: HtmlRenderer): R = with(renderer) {
+ templateCommand(AddToNavigationCommand(moduleName)) {
+ visit(node,"${moduleName}-nav-submenu", renderer)
+ }
}
private fun <R> TagConsumer<R>.visit(node: NavigationNode, navId: String, renderer: HtmlRenderer): R =
with(renderer) {
div("sideMenuPart") {
id = navId
- attributes["pageId"] = node.pageId
+ attributes["pageId"] = "${moduleName}::${node.pageId}"
div("overview") {
buildLink(node.dri, node.sourceSets.toList()) { buildBreakableText(node.name) }
if (node.children.isNotEmpty()) {
@@ -47,7 +54,7 @@ data class NavigationNode(
override val children: List<NavigationNode>
): WithChildren<NavigationNode>
-fun NavigationPage.transform(block: (NavigationNode) -> NavigationNode) = NavigationPage(root.transform(block))
+fun NavigationPage.transform(block: (NavigationNode) -> NavigationNode) = NavigationPage(root.transform(block), moduleName)
fun NavigationNode.transform(block: (NavigationNode) -> NavigationNode) =
run(block).let { NavigationNode(it.name, it.dri, it.sourceSets, it.children.map(block)) }
diff --git a/plugins/base/src/main/kotlin/renderers/html/Tags.kt b/plugins/base/src/main/kotlin/renderers/html/Tags.kt
index 67eed686..3db49ebf 100644
--- a/plugins/base/src/main/kotlin/renderers/html/Tags.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/Tags.kt
@@ -13,9 +13,19 @@ open class WBR(initialAttributes: Map<String, String>, consumer: TagConsumer<*>)
HTMLTag("wbr", consumer, initialAttributes, namespace = null, inlineTag = true, emptyTag = false),
HtmlBlockInlineTag
-fun FlowOrPhrasingContent.templateCommand(data: Command, block: TemplateCommand.() -> Unit = {}):Unit =
+fun FlowOrPhrasingContent.templateCommand(data: Command, block: TemplateCommand.() -> Unit = {}): Unit =
TemplateCommand(attributesMapOf("data", toJsonString(data)), consumer).visit(block)
+fun <T> TagConsumer<T>.templateCommand(data: Command, block: TemplateCommand.() -> Unit = {}): T =
+ TemplateCommand(attributesMapOf("data", toJsonString(data)), this).visitAndFinalize(this, block)
+
class TemplateCommand(initialAttributes: Map<String, String>, consumer: TagConsumer<*>) :
- HTMLTag("dokka-template-command", consumer, initialAttributes, namespace = null, inlineTag = true, emptyTag = false),
+ HTMLTag(
+ "dokka-template-command",
+ consumer,
+ initialAttributes,
+ namespace = null,
+ inlineTag = true,
+ emptyTag = false
+ ),
CommonAttributeGroupFacadeFlowInteractivePhrasingContent
diff --git a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
index 45159fea..fbebec70 100644
--- a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
@@ -177,5 +177,4 @@ class SourcesetDependencyAppender(val context: DokkaContext) : PageTransformer {
children = input.children + deps
).transformContentPagesTree { it.modified(embeddedResources = it.embeddedResources + name) }
}
-}
-
+} \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/templating/AddToNavigationCommand.kt b/plugins/base/src/main/kotlin/templating/AddToNavigationCommand.kt
new file mode 100644
index 00000000..817501d7
--- /dev/null
+++ b/plugins/base/src/main/kotlin/templating/AddToNavigationCommand.kt
@@ -0,0 +1,3 @@
+package org.jetbrains.dokka.base.templating
+
+class AddToNavigationCommand(val moduleName: String) : Command
diff --git a/plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt b/plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt
index b35310a5..e69de29b 100644
--- a/plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt
+++ b/plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt
@@ -1,121 +0,0 @@
-package locationProvider
-
-import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProvider
-import org.jetbrains.dokka.model.dfs
-import org.jetbrains.dokka.plugability.DokkaContext
-import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest
-import org.junit.jupiter.api.Assertions.assertNotEquals
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.params.ParameterizedTest
-import org.junit.jupiter.params.provider.MethodSource
-import kotlin.test.assertEquals
-import kotlin.test.assertNotNull
-
-class DefaultLocationProviderTest : AbstractCoreTest() {
- val configuration = dokkaConfiguration {
- sourceSets {
- sourceSet {
- sourceRoots = listOf("src/")
- }
- }
- }
-
- @Test
- fun `#644 same directory for module and package`() {
- testInline(
- """
- |/src/main/kotlin/basic/Test.kt
- |
- |class Test {
- | val x = 1
- |}
- """.trimMargin(),
- configuration
- ) {
- var context: DokkaContext? = null
- pluginsSetupStage = {
- context = it
- }
-
- pagesGenerationStage = { module ->
- val lp = DokkaLocationProvider(module, context!!)
- assertNotEquals(lp.resolve(module.children.single()).removePrefix("/"), lp.resolve(module))
- }
- }
- }
-
- @Test
- fun `should escape illegal pipe character in file name`() {
- /*
- Currently even kotlin doesn't escape pipe characters in file names so it is impossible to have a
- class named || on windows
- */
- testInline(
- """
- |/src/main/kotlin/basic/Test.kt
- |
- |class Test {
- | fun `||`() { }
- |}
- """.trimMargin(),
- configuration
- ) {
- var context: DokkaContext? = null
- pluginsSetupStage = {
- context = it
- }
-
- pagesGenerationStage = { module ->
- val lp = DokkaLocationProvider(module, context!!)
- val functionWithPipes = module.dfs { it.name == "||" }
- assertNotNull(functionWithPipes, "Failed to find a page for a function named ||")
- assertEquals(lp.resolve(functionWithPipes), "[root]/-test/[124][124].html")
- }
- }
- }
-
- @ParameterizedTest
- @MethodSource
- fun runEscapeTestForCharacter(data: TestData) {
- testInline(
- """
- |/src/main/kotlin/basic/Test.kt
- |
- |class Test {
- | fun `${data.tested}`() { }
- |}
- """.trimMargin(),
- configuration
- ) {
- var context: DokkaContext? = null
- pluginsSetupStage = {
- context = it
- }
-
- pagesGenerationStage = { module ->
- val lp = DokkaLocationProvider(module, context!!)
- val functionWithPipes = module.dfs { it.name == "${data.tested}" }
- assertNotNull(functionWithPipes, "Failed to find a page for a function named ${data.tested}")
- assertEquals(lp.resolve(functionWithPipes), "[root]/-test/${data.expectedReplacement}.html")
- }
- }
- }
-
- data class TestData(val tested: Char, val expectedReplacement: String)
-
- companion object TestDataSources {
- @JvmStatic
- fun runEscapeTestForCharacter(): List<TestData> = listOf(
- '|' to "[124]",
- '>' to "[62]",
- '<' to "[60]",
- '*' to "[42]",
- ':' to "[58]",
- '"' to "[34]",
- '?' to "[63]",
- '%' to "[37]"
- ).map {
- TestData(it.first, it.second)
- }
- }
-}