aboutsummaryrefslogtreecommitdiff
path: root/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt')
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt193
1 files changed, 193 insertions, 0 deletions
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt b/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt
new file mode 100644
index 00000000..ad83968e
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt
@@ -0,0 +1,193 @@
+package javadoc
+
+import com.soywiz.korte.*
+import javadoc.pages.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.jetbrains.dokka.base.renderers.OutputWriter
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.pages.PageNode
+import org.jetbrains.dokka.pages.RendererSpecificPage
+import org.jetbrains.dokka.pages.RenderingStrategy
+import org.jetbrains.dokka.pages.RootPageNode
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.renderers.Renderer
+import java.nio.file.Path
+import java.nio.file.Paths
+import java.time.LocalDate
+
+class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaContext, val resourceDir: String) :
+ Renderer {
+ private lateinit var locationProvider: JavadocLocationProvider
+
+ override fun render(root: RootPageNode) = root.let { preprocessors.fold(root) { r, t -> t.invoke(r) } }.let { r ->
+ locationProvider = JavadocLocationProvider(r, context)
+ runBlocking(Dispatchers.IO) {
+ renderModulePageNode(r as JavadocModulePageNode)
+ }
+ }
+
+ private fun templateForNode(node: JavadocPageNode) = when (node) {
+ is JavadocClasslikePageNode -> "class.korte"
+ is JavadocPackagePageNode -> "tabPage.korte"
+ is JavadocModulePageNode -> "tabPage.korte"
+ is AllClassesPage -> "listPage.korte"
+ is TreeViewPage -> "treePage.korte"
+ else -> ""
+ }
+
+ private fun CoroutineScope.renderNode(node: PageNode, path: String = "") {
+ if (node is JavadocPageNode) {
+ renderJavadocNode(node)
+ } else if (node is RendererSpecificPage) {
+ renderSpecificPage(node, path)
+ }
+ }
+
+ private fun CoroutineScope.renderModulePageNode(node: JavadocModulePageNode) {
+ val link = "."
+ val name = "index"
+ val pathToRoot = ""
+
+ val contentMap = mapOf(
+ "docName" to "docName", // todo docname
+ "pathToRoot" to pathToRoot
+ ) + node.contentMap
+ writeFromTemplate(outputWriter, "$link/$name".toNormalized(), "tabPage.korte", contentMap.toList())
+ node.children.forEach { renderNode(it, link) }
+ }
+
+ private fun CoroutineScope.renderJavadocNode(node: JavadocPageNode) {
+ val link = locationProvider.resolve(node, skipExtension = true)
+ val dir = Paths.get(link).parent?.let { it.toNormalized() }.orEmpty()
+ val pathToRoot = dir.split("/").joinToString("/") { ".." }.let {
+ if (it.isNotEmpty()) "$it/" else it
+ }
+
+ val contentMap = mapOf(
+ "docName" to "docName", // todo docname
+ "pathToRoot" to pathToRoot,
+ "dir" to dir
+ ) + node.contentMap
+// DokkaConsoleLogger.info("${node::class.java.canonicalName}::${node.name} - $link")
+ writeFromTemplate(outputWriter, link, templateForNode(node), contentMap.toList())
+ node.children.forEach { renderNode(it, link.toNormalized()) }
+ }
+
+ fun CoroutineScope.renderSpecificPage(node: RendererSpecificPage, path: String) = launch {
+ when (val strategy = node.strategy) {
+ is RenderingStrategy.Copy -> outputWriter.writeResources(strategy.from, "")
+ is RenderingStrategy.Write -> outputWriter.writeHtml(path, strategy.text)
+ is RenderingStrategy.Callback -> outputWriter.writeResources(
+ path,
+ strategy.instructions(this@KorteJavadocRenderer, node)
+ )
+ RenderingStrategy.DoNothing -> Unit
+ }
+ }
+
+ fun Pair<String, String>.pairToTag() = "\n<th class=\"colFirst\" scope=\"row\">${first}</th>\n<td class=\"colLast\">${second}</td>"
+
+ fun LinkJavadocListEntry.toLinkTag(parent: String? = null) =
+ createLinkTag(locationProvider.resolve(dri.first(), sourceSets.toList()).let {
+ if (parent != null) it.relativizePath(parent)
+ else it
+ }, name)
+
+ fun DRI.toLink(context: PageNode? = null) = locationProvider.resolve(this, emptyList(), context)
+
+ fun createLinkTag(address: String, name: String) =
+ address.let { if (it.endsWith(".html")) it else "$it.html" }.let {
+ """<a href="$it">$name</a>"""
+ }
+
+ private fun String.parent() = Paths.get(this).parent.toNormalized()
+ private fun Path.toNormalized() = this.normalize().toFile().toString()
+ private fun String.toNormalized() = Paths.get(this).toNormalized()
+ private fun String.relativizePath(parent: String) = Paths.get(parent).relativize(Paths.get(this)).toNormalized()
+
+ private suspend fun OutputWriter.writeHtml(path: String, text: String) = write(path, text, ".html")
+ private fun CoroutineScope.writeFromTemplate(
+ writer: OutputWriter,
+ path: String,
+ template: String,
+ args: List<Pair<String, *>>
+ ) =
+ launch {
+ val tmp = templateRenderer.render(template, *(args.toTypedArray()))
+ writer.writeHtml(
+ path,
+ tmp
+ )
+ }
+
+ fun getTemplateConfig() = TemplateConfig().also { config ->
+ listOf(
+ TeFunction("curDate") { LocalDate.now() },
+ TeFunction("jQueryVersion") { "3.1" },
+ TeFunction("jQueryMigrateVersion") { "1.2.1" },
+ TeFunction("rowColor") { args -> if ((args.first() as Int) % 2 == 0) "altColor" else "rowColor" },
+ TeFunction("h1Title") { args -> if ((args.first() as? String) == "package") "title=\"Package\" " else "" },
+ TeFunction("createTabRow") { args ->
+ val (link, doc) = args.first() as RowJavadocListEntry
+ val dir = args[1] as String?
+ (createLinkTag(locationProvider.resolve(link, dir.orEmpty()), link.name) to doc).pairToTag().trim()
+ },
+ TeFunction("createListRow") { args ->
+ val link = args.first() as LinkJavadocListEntry
+ val dir = args[1] as String?
+// link.toLinkTag(dir)
+ createLinkTag(locationProvider.resolve(link, dir.orEmpty()), link.name)
+ },
+ TeFunction("createPackageHierarchy") { args ->
+ val list = args.first() as List<JavadocPackagePageNode>
+ list.mapIndexed { i, p ->
+ val content = if (i + 1 == list.size) "" else ", "
+ val name = p.name
+ "<li><a href=\"$name/package-tree.html\">$name</a>$content</li>"
+ }.joinToString("\n")
+ },
+ TeFunction("renderInheritanceGraph") { args ->
+ val node = args.first() as TreeViewPage.InheritanceNode
+
+ fun drawRec(node: TreeViewPage.InheritanceNode): String =
+ "<li class=\"circle\">" + node.dri.let { dri ->
+ listOfNotNull(
+ dri.packageName,
+ dri.classNames
+ ).joinToString(".") + node.interfaces.takeUnless { node.isInterface || it.isEmpty() }
+ ?.let {
+ " implements " + it.joinToString(", ") { n ->
+ listOfNotNull(
+ n.packageName,
+ createLinkTag(n.toLink(), n.classNames.orEmpty())
+ ).joinToString(".")
+ }
+ }.orEmpty()
+ } + node.children.filterNot { it.isInterface }.takeUnless { it.isEmpty() }?.let {
+ "<ul>" + it.joinToString("\n", transform = ::drawRec) + "</ul>"
+ }.orEmpty() + "</li>"
+
+ drawRec(node)
+ },
+ Filter("length") { subject.dynamicLength() }
+ ).forEach {
+ when (it) {
+ is TeFunction -> config.register(it)
+ is Filter -> config.register(it)
+ is Tag -> config.register(it)
+ }
+ }
+ }
+
+ val config = getTemplateConfig()
+ val templateRenderer = Templates(ResourceTemplateProvider(resourceDir), config = config, cache = true)
+
+ class ResourceTemplateProvider(val basePath: String) : TemplateProvider {
+ override suspend fun get(template: String): String =
+ javaClass.classLoader.getResourceAsStream("$basePath/$template")?.bufferedReader()?.lines()?.toArray()
+ ?.joinToString("\n") ?: throw IllegalStateException("Template not found: $basePath/$template")
+ }
+} \ No newline at end of file