From a89d9a8c87cbe81bdba25b660d1b1fda1d0ce8ec Mon Sep 17 00:00:00 2001 From: Paweł Marks Date: Mon, 17 Feb 2020 12:35:15 +0100 Subject: Moves location providers and output writers to base plugin --- plugins/base/src/main/kotlin/renderers/OutputWriter.kt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 plugins/base/src/main/kotlin/renderers/OutputWriter.kt (limited to 'plugins/base/src/main/kotlin/renderers/OutputWriter.kt') diff --git a/plugins/base/src/main/kotlin/renderers/OutputWriter.kt b/plugins/base/src/main/kotlin/renderers/OutputWriter.kt new file mode 100644 index 00000000..a6fda51a --- /dev/null +++ b/plugins/base/src/main/kotlin/renderers/OutputWriter.kt @@ -0,0 +1,7 @@ +package org.jetbrains.dokka.base.renderers + +interface OutputWriter { + + fun write(path: String, text: String, ext: String) + fun writeResources(pathFrom: String, pathTo: String) +} \ No newline at end of file -- cgit From 720c50fb7f4bf4ae4b4d4c406cfb958a7fba8ffb Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Mon, 6 Apr 2020 15:58:55 +0200 Subject: Adds asynchronous rendering --- core/src/main/kotlin/DokkaGenerator.kt | 11 +++- core/src/main/kotlin/renderers/Renderer.kt | 4 +- .../src/main/kotlin/renderers/DefaultRenderer.kt | 71 ++++++++++++++++++---- .../base/src/main/kotlin/renderers/FileWriter.kt | 4 +- .../base/src/main/kotlin/renderers/OutputWriter.kt | 4 +- .../src/main/kotlin/renderers/html/HtmlRenderer.kt | 14 +++-- .../base/src/test/kotlin/utils/TestOutputWriter.kt | 4 +- plugins/gfm/src/main/kotlin/GfmPlugin.kt | 9 +-- 8 files changed, 93 insertions(+), 28 deletions(-) (limited to 'plugins/base/src/main/kotlin/renderers/OutputWriter.kt') diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt index 053b4cb6..0a797769 100644 --- a/core/src/main/kotlin/DokkaGenerator.kt +++ b/core/src/main/kotlin/DokkaGenerator.kt @@ -3,6 +3,10 @@ package org.jetbrains.dokka import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiManager +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import org.jetbrains.dokka.analysis.AnalysisEnvironment import org.jetbrains.dokka.analysis.DokkaResolutionFacade import org.jetbrains.dokka.model.DModule @@ -109,7 +113,12 @@ class DokkaGenerator( context: DokkaContext ) { val renderer = context.single(CoreExtensions.renderer) - renderer.render(transformedPages) + runBlocking { + val scope = this + with(renderer) { + scope.render(transformedPages).join() + } + } } private fun createEnvironmentAndFacade(pass: DokkaConfiguration.PassConfiguration): EnvironmentAndFacade = diff --git a/core/src/main/kotlin/renderers/Renderer.kt b/core/src/main/kotlin/renderers/Renderer.kt index 10235f21..9d054503 100644 --- a/core/src/main/kotlin/renderers/Renderer.kt +++ b/core/src/main/kotlin/renderers/Renderer.kt @@ -1,7 +1,9 @@ package org.jetbrains.dokka.renderers +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job import org.jetbrains.dokka.pages.RootPageNode interface Renderer { - fun render(root: RootPageNode) + fun CoroutineScope.render(root: RootPageNode): Job } \ No newline at end of file diff --git a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt index 26c75dbf..4178e427 100644 --- a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt @@ -1,5 +1,7 @@ package org.jetbrains.dokka.base.renderers +import com.sun.jna.platform.win32.COM.Dispatch +import kotlinx.coroutines.* import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.resolvers.local.LocationProvider import org.jetbrains.dokka.pages.* @@ -22,10 +24,20 @@ abstract class DefaultRenderer( abstract fun T.buildHeader(level: Int, content: T.() -> Unit) abstract fun T.buildLink(address: String, content: T.() -> Unit) - abstract fun T.buildList(node: ContentList, pageContext: ContentPage, platformRestriction: PlatformData? = null) + abstract fun T.buildList( + node: ContentList, + pageContext: ContentPage, + platformRestriction: PlatformData? = null + ) + abstract fun T.buildNewLine() abstract fun T.buildResource(node: ContentEmbeddedResource, pageContext: ContentPage) - abstract fun T.buildTable(node: ContentTable, pageContext: ContentPage, platformRestriction: PlatformData? = null) + abstract fun T.buildTable( + node: ContentTable, + pageContext: ContentPage, + platformRestriction: PlatformData? = null + ) + abstract fun T.buildText(textNode: ContentText) abstract fun T.buildNavigation(page: PageNode) @@ -35,7 +47,11 @@ abstract class DefaultRenderer( open fun T.buildPlatformDependent(content: PlatformHintedContent, pageContext: ContentPage) = buildContentNode(content.inner, pageContext) - open fun T.buildGroup(node: ContentGroup, pageContext: ContentPage, platformRestriction: PlatformData? = null) = + open fun T.buildGroup( + node: ContentGroup, + pageContext: ContentPage, + platformRestriction: PlatformData? = null + ) = wrapGroup(node, pageContext) { node.children.forEach { it.build(this, pageContext, platformRestriction) } } open fun T.wrapGroup(node: ContentGroup, pageContext: ContentPage, childrenCallback: T.() -> Unit) = @@ -53,11 +69,19 @@ abstract class DefaultRenderer( code.forEach { it.build(this, pageContext) } } - open fun T.buildHeader(node: ContentHeader, pageContext: ContentPage, platformRestriction: PlatformData? = null) { + open fun T.buildHeader( + node: ContentHeader, + pageContext: ContentPage, + platformRestriction: PlatformData? = null + ) { buildHeader(node.level) { node.children.forEach { it.build(this, pageContext, platformRestriction) } } } - open fun ContentNode.build(builder: T, pageContext: ContentPage, platformRestriction: PlatformData? = null) = + open fun ContentNode.build( + builder: T, + pageContext: ContentPage, + platformRestriction: PlatformData? = null + ) = builder.buildContentNode(this, pageContext, platformRestriction) open fun T.buildContentNode( @@ -93,14 +117,14 @@ abstract class DefaultRenderer( page.content.build(context, page) } - open fun renderPage(page: PageNode) { + open suspend fun renderPage(page: PageNode) { val path by lazy { locationProvider.resolve(page, skipExtension = true) } when (page) { - is ContentPage -> outputWriter.write(path, buildPage(page) { c, p -> buildPageContent(c, p) }, ".html") + is ContentPage -> outputWriter.write(path, runBlocking { buildPage(page) { c, p -> buildPageContent(c, p) } }, ".html") 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.Callback -> outputWriter.write(path, strategy.instructions(this@DefaultRenderer, page), ".html") RenderingStrategy.DoNothing -> Unit } else -> throw AssertionError( @@ -109,12 +133,33 @@ abstract class DefaultRenderer( } } - open fun renderPages(root: PageNode) { - renderPage(root) - root.children.forEach { renderPages(it) } + private suspend fun CoroutineScope.renderPages(root: PageNode) { + coroutineScope { + launch(Dispatchers.IO) { renderPage(root) }.join() + root.children.forEach { + renderPages(it) + } + } } - override fun render(root: RootPageNode) { + // reimplement this as preprocessor + open suspend fun renderPackageList(root: ContentPage) = + getPackageNamesAndPlatforms(root) + .keys + .joinToString("\n") + .also { outputWriter.write("${root.name}/package-list", it, "") } + + open suspend fun getPackageNamesAndPlatforms(root: PageNode): Map> = + root.children + .map { getPackageNamesAndPlatforms(it) } + .fold(emptyMap>()) { e, acc -> acc + e } + + if (root is PackagePageNode) { + mapOf(root.name to root.platforms()) + } else { + emptyMap() + } + + protected fun renderImpl(coroutineScope: CoroutineScope, root: RootPageNode): Job = coroutineScope.launch(Dispatchers.Default) { val newRoot = preprocessors.fold(root) { acc, t -> t(acc) } locationProvider = @@ -122,6 +167,8 @@ abstract class DefaultRenderer( renderPages(newRoot) } + + override fun CoroutineScope.render(root: RootPageNode) = renderImpl(this, root) } fun ContentPage.platforms() = this.content.platforms.toList() \ No newline at end of file diff --git a/plugins/base/src/main/kotlin/renderers/FileWriter.kt b/plugins/base/src/main/kotlin/renderers/FileWriter.kt index bf2426fe..07d25eb6 100644 --- a/plugins/base/src/main/kotlin/renderers/FileWriter.kt +++ b/plugins/base/src/main/kotlin/renderers/FileWriter.kt @@ -11,7 +11,7 @@ class FileWriter(val context: DokkaContext): OutputWriter { private val jarUriPrefix = "jar:file:" private val root = File(context.configuration.outputDir).absolutePath - override fun write(path: String, text: String, ext: String) { + override suspend fun write(path: String, text: String, ext: String) { if (createdFiles.contains(path)) { context.logger.error("An attempt to write ${root}/$path several times!") return @@ -28,7 +28,7 @@ class FileWriter(val context: DokkaContext): OutputWriter { } } - override fun writeResources(pathFrom: String, pathTo: String) = + override suspend fun writeResources(pathFrom: String, pathTo: String) = if (javaClass.getResource(pathFrom).toURI().toString().startsWith(jarUriPrefix)) { copyFromJar(pathFrom, pathTo) } else { diff --git a/plugins/base/src/main/kotlin/renderers/OutputWriter.kt b/plugins/base/src/main/kotlin/renderers/OutputWriter.kt index a6fda51a..1827c7f0 100644 --- a/plugins/base/src/main/kotlin/renderers/OutputWriter.kt +++ b/plugins/base/src/main/kotlin/renderers/OutputWriter.kt @@ -2,6 +2,6 @@ package org.jetbrains.dokka.base.renderers interface OutputWriter { - fun write(path: String, text: String, ext: String) - fun writeResources(pathFrom: String, pathTo: String) + suspend fun write(path: String, text: String, ext: String) + suspend fun writeResources(pathFrom: String, pathTo: String) } \ 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 bbb5b685..a32cb715 100644 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt @@ -1,5 +1,9 @@ package org.jetbrains.dokka.base.renderers.html +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch import kotlinx.html.* import kotlinx.html.stream.createHTML import org.jetbrains.dokka.base.DokkaBase @@ -264,7 +268,7 @@ open class HtmlRenderer( } } - override fun renderPage(page: PageNode) { + override suspend fun renderPage(page: PageNode) { super.renderPage(page) if (page is ContentPage) { pageList.add( @@ -282,9 +286,11 @@ open class HtmlRenderer( text(textNode.text) } - override fun render(root: RootPageNode) { - super.render(root) - outputWriter.write("scripts/pages", "var pages = [\n${pageList.joinToString(",\n")}\n]", ".js") + override fun CoroutineScope.render(root: RootPageNode): Job { + super.renderImpl(this, root) + return launch(Dispatchers.IO) { + outputWriter.write("scripts/pages", "var pages = [\n${pageList.joinToString(",\n")}\n]", ".js") + } } private fun PageNode.root(path: String) = locationProvider.resolveRoot(this) + path diff --git a/plugins/base/src/test/kotlin/utils/TestOutputWriter.kt b/plugins/base/src/test/kotlin/utils/TestOutputWriter.kt index e2250a26..607d3ced 100644 --- a/plugins/base/src/test/kotlin/utils/TestOutputWriter.kt +++ b/plugins/base/src/test/kotlin/utils/TestOutputWriter.kt @@ -16,12 +16,12 @@ class TestOutputWriter(private val failOnOverwrite: Boolean = true): OutputWrite private val _contents = mutableMapOf() - override fun write(path: String, text: String, ext: String) { + override suspend fun write(path: String, text: String, ext: String) { val fullPath = "$path$ext" _contents.putIfAbsent(fullPath, text)?.also { if (failOnOverwrite) throw AssertionError("File $fullPath is being overwritten.") } } - override fun writeResources(pathFrom: String, pathTo: String) = write(pathTo, "*** content of $pathFrom ***", "") + override suspend fun writeResources(pathFrom: String, pathTo: String) = write(pathTo, "*** content of $pathFrom ***", "") } diff --git a/plugins/gfm/src/main/kotlin/GfmPlugin.kt b/plugins/gfm/src/main/kotlin/GfmPlugin.kt index 91b6f7b5..185dacac 100644 --- a/plugins/gfm/src/main/kotlin/GfmPlugin.kt +++ b/plugins/gfm/src/main/kotlin/GfmPlugin.kt @@ -1,5 +1,6 @@ package org.jetbrains.dokka.gfm +import kotlinx.coroutines.* import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.renderers.DefaultRenderer @@ -108,7 +109,7 @@ open class CommonmarkRenderer( override fun StringBuilder.buildPlatformDependent(content: PlatformHintedContent, pageContext: ContentPage) { val distinct = content.platforms.map { - it to "${StringBuilder().apply {buildContentNode(content.inner, pageContext, it) }.toString()}" + it to StringBuilder().apply {buildContentNode(content.inner, pageContext, it) }.toString() }.groupBy(Pair::second, Pair::first) if (distinct.size == 1) @@ -200,14 +201,14 @@ open class CommonmarkRenderer( append(to.name) } - override fun renderPage(page: PageNode) { + override suspend fun renderPage(page: PageNode) { val path by lazy { locationProvider.resolve(page, skipExtension = true) } when (page) { - is ContentPage -> outputWriter.write(path, buildPage(page) { c, p -> buildPageContent(c, p) }, ".md") + is ContentPage -> outputWriter.write(path, buildPage(page) { c, p -> runBlocking { buildPageContent(c, p) } }, ".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), ".md") + is RenderingStrategy.Callback -> outputWriter.write(path, strategy.instructions(this@CommonmarkRenderer, page), ".md") RenderingStrategy.DoNothing -> Unit } else -> throw AssertionError( -- cgit