diff options
author | Kamil Doległo <kamilok1965@interia.pl> | 2020-06-25 19:27:21 +0200 |
---|---|---|
committer | Paweł Marks <Kordyjan@users.noreply.github.com> | 2020-06-25 23:39:24 +0200 |
commit | 370bf45d2dca5fcd71f53c71386be8667157c446 (patch) | |
tree | e720a2277e042ecfa6753882f6cd7939f009dfc0 /plugins/base/src | |
parent | e5daeb9fe276887de95af4995ec53db2b4f407d4 (diff) | |
download | dokka-370bf45d2dca5fcd71f53c71386be8667157c446.tar.gz dokka-370bf45d2dca5fcd71f53c71386be8667157c446.tar.bz2 dokka-370bf45d2dca5fcd71f53c71386be8667157c446.zip |
Make samples runnable
Diffstat (limited to 'plugins/base/src')
8 files changed, 104 insertions, 75 deletions
diff --git a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt index a946aa6f..09d6cad1 100644 --- a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt @@ -74,8 +74,8 @@ abstract class DefaultRenderer<T>( nodes.forEach { it.build(this, pageContext, sourceSetRestriction) } } - open fun T.buildCode(code: List<ContentNode>, language: String, pageContext: ContentPage) { - code.forEach { it.build(this, pageContext) } + open fun T.buildCode(code: ContentCode, pageContext: ContentPage) { + code.children.forEach { it.build(this, pageContext) } } open fun T.buildHeader( @@ -102,7 +102,7 @@ abstract class DefaultRenderer<T>( when (node) { is ContentText -> buildText(node) is ContentHeader -> buildHeader(node, pageContext, sourceSetRestriction) - is ContentCode -> buildCode(node.children, node.language, pageContext) + is ContentCode -> buildCode(node, pageContext) is ContentDRILink -> buildLink(locationProvider.resolve(node.address, node.sourceSets.toList(), pageContext)) { buildLinkText(node.children, pageContext, sourceSetRestriction) @@ -172,4 +172,4 @@ abstract class DefaultRenderer<T>( } } -fun ContentPage.platforms() = this.content.sourceSets.toList()
\ No newline at end of file +fun ContentPage.sourceSets() = this.content.sourceSets
\ 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 ee6f1e1f..d56ab50c 100644 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt @@ -540,23 +540,11 @@ open class HtmlRenderer( a(href = address, block = content) override fun FlowContent.buildCode( - code: List<ContentNode>, - language: String, + code: ContentCode, pageContext: ContentPage ) { - span(classes = "code") { - val iterator = code.iterator() - while (iterator.hasNext()) { - val element = iterator.next() - +(when (element) { - is ContentText -> element.text - is ContentBreakLine -> "\n" - else -> run { context.logger.error("Cannot cast $element as ContentText!"); "" } - }) - if (iterator.hasNext()) { - buildNewLine() - } - } + code(code.style.joinToString(" ") { it.toString().toLowerCase() }) { + code.children.forEach { buildContentNode(it, pageContext) } } } @@ -658,15 +646,20 @@ open class HtmlRenderer( head { meta(name = "viewport", content = "width=device-width, initial-scale=1", charset = "UTF-8") title(page.name) - with(resources) { - filter { it.substringBefore('?').substringAfterLast('.') == "css" } - .forEach { link(rel = LinkRel.stylesheet, href = resolveLink(it, page)) } - filter { it.substringBefore('?').substringAfterLast('.') == "js" } - .forEach { - script(type = ScriptType.textJavaScript, src = resolveLink(it, page)) { - async = true - } + resources.forEach { + when { + it.substringBefore('?').substringAfterLast('.') == "css" -> link( + rel = LinkRel.stylesheet, + href = resolveLink(it, page) + ) + it.substringBefore('?').substringAfterLast('.') == "js" -> script( + type = ScriptType.textJavaScript, + src = resolveLink(it, page) + ) { + async = true } + else -> unsafe { +it } + } } script { unsafe { +"""var pathToRoot = "${locationProvider.resolveRoot(page)}";""" } } } diff --git a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt index eb563dbd..8fe2a6c8 100644 --- a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt +++ b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt @@ -25,7 +25,7 @@ class NavigationPage(val root: NavigationNode) : RendererSpecificPage { id = navId attributes["pageId"] = node.dri.toString() div("overview") { - buildLink(node.dri, node.sourceSets) { +node.name } + buildLink(node.dri, node.sourceSets.toList()) { +node.name } if (node.children.isNotEmpty()) { span("navButton") { onClick = """document.getElementById("$navId").classList.toggle("hidden");""" @@ -41,7 +41,7 @@ class NavigationPage(val root: NavigationNode) : RendererSpecificPage { class NavigationNode( val name: String, val dri: DRI, - val sourceSets: List<DokkaSourceSet>, + val sourceSets: Set<DokkaSourceSet>, val children: List<NavigationNode> ) diff --git a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt index af0525d7..2f7c8ee1 100644 --- a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt +++ b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt @@ -4,7 +4,7 @@ import kotlinx.html.h1 import kotlinx.html.id import kotlinx.html.table import kotlinx.html.tbody -import org.jetbrains.dokka.base.renderers.platforms +import org.jetbrains.dokka.base.renderers.sourceSets import org.jetbrains.dokka.model.DEnum import org.jetbrains.dokka.model.DEnumEntry import org.jetbrains.dokka.pages.* @@ -45,16 +45,17 @@ object NavigationPageInstaller : PageTransformer { NavigationNode( page.name, page.dri.first(), - page.platforms(), + page.sourceSets(), page.navigableChildren() ) private fun ContentPage.navigableChildren(): List<NavigationNode> { - if(this !is ClasslikePageNode){ + if (this !is ClasslikePageNode) { return children.filterIsInstance<ContentPage>() .map { visit(it) } - } else if(documentable is DEnum) { - return children.filter { it is ContentPage && it.documentable is DEnumEntry }.map { visit(it as ContentPage) } + } else if (documentable is DEnum) { + return children.filter { it is ContentPage && it.documentable is DEnumEntry } + .map { visit(it as ContentPage) } } return emptyList() @@ -84,18 +85,20 @@ object StyleAndScriptsAppender : PageTransformer { } } -class SourcesetDependencyAppender(val context: DokkaContext) : PageTransformer{ +class SourcesetDependencyAppender(val context: DokkaContext) : PageTransformer { override fun invoke(input: RootPageNode): RootPageNode { val dependenciesMap = context.configuration.sourceSets.map { it.sourceSetID to it.dependentSourceSets }.toMap() - fun createDependenciesJson() : String = "sourceset_dependencies = '{${ - dependenciesMap.entries.joinToString(", ") { - "\"${it.key}\": [${it.value.joinToString(","){ - "\"$it\"" - }}]" - } + + fun createDependenciesJson(): String = "sourceset_dependencies = '{${ + dependenciesMap.entries.joinToString(", ") { + "\"${it.key}\": [${it.value.joinToString(",") { + "\"$it\"" + }}]" + } }}'" + val deps = RendererSpecificResourcePage( name = "scripts/sourceset_dependencies.js", children = emptyList(), @@ -106,4 +109,4 @@ class SourcesetDependencyAppender(val context: DokkaContext) : PageTransformer{ children = input.children + deps ) } -}
\ No newline at end of file +} diff --git a/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt b/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt index a40f2f53..b39715a7 100644 --- a/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt @@ -1,24 +1,24 @@ package org.jetbrains.dokka.base.transformers.pages.samples import com.intellij.psi.PsiElement +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.Platform import org.jetbrains.dokka.analysis.AnalysisEnvironment import org.jetbrains.dokka.analysis.DokkaMessageCollector import org.jetbrains.dokka.analysis.DokkaResolutionFacade import org.jetbrains.dokka.analysis.EnvironmentAndFacade -import org.jetbrains.dokka.base.renderers.platforms +import org.jetbrains.dokka.base.renderers.sourceSets import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.model.doc.Sample import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.pages.PageTransformer -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.idea.kdoc.resolveKDocSampleLink +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils +import org.jetbrains.kotlin.utils.PathUtil import java.io.File abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer { @@ -27,13 +27,17 @@ abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer { abstract fun processImports(psiElement: PsiElement): String final override fun invoke(input: RootPageNode): RootPageNode { - val analysis = setUpAnalysis(context) + val kotlinPlaygroundScript = + "<script src=\"https://unpkg.com/kotlin-playground@1\" data-selector=\"code.runnablesample\"></script>" return input.transformContentPagesTree { page -> page.documentable?.documentation?.entries?.fold(page) { acc, entry -> entry.value.children.filterIsInstance<Sample>().fold(acc) { acc, sample -> - acc.modified(content = acc.content.addSample(page, entry.key, sample.name, analysis)) + acc.modified( + content = acc.content.addSample(page, entry.key, sample.name, analysis), + embeddedResources = acc.embeddedResources + kotlinPlaygroundScript + ) } } ?: page } @@ -66,22 +70,32 @@ abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer { ?: return this.also { context.logger.warn("Cannot resolve facade for platform ${platform.moduleName}") } val psiElement = fqNameToPsiElement(facade, fqName) ?: return this.also { context.logger.warn("Cannot find PsiElement corresponding to $fqName") } - val imports = processImports(psiElement) // TODO: Process somehow imports. Maybe just attach them at the top of each body + val imports = + processImports(psiElement) val body = processBody(psiElement) - val node = contentCode(contentPage.platforms(), contentPage.dri, body, "kotlin") + val node = contentCode(contentPage.sourceSets(), contentPage.dri, createSampleBody(imports, body), "kotlin") return dfs(fqName, node) } + protected open fun createSampleBody(imports: String, body: String) = + """ |$imports + |fun main() { + | //sampleStart + | $body + | //sampleEnd + |}""".trimMargin() + private fun ContentNode.dfs(fqName: String, node: ContentCode): ContentNode { return when (this) { is ContentHeader -> copy(children.map { it.dfs(fqName, node) }) - is ContentDivergentGroup -> copy(children.map { it.dfs(fqName, node) } as List<ContentDivergentInstance>) + is ContentDivergentGroup -> @Suppress("UNCHECKED_CAST") copy(children.map { + it.dfs(fqName, node) + } as List<ContentDivergentInstance>) is ContentDivergentInstance -> copy( before.let { it?.dfs(fqName, node) }, divergent.dfs(fqName, node), - after.let { it?.dfs(fqName, node) } - ) + after.let { it?.dfs(fqName, node) }) is ContentCode -> copy(children.map { it.dfs(fqName, node) }) is ContentDRILink -> copy(children.map { it.dfs(fqName, node) }) is ContentResolvedLink -> copy(children.map { it.dfs(fqName, node) }) @@ -109,21 +123,28 @@ abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer { return DescriptorToSourceUtils.descriptorToDeclaration(symbol) } - private fun contentCode(sourceSets: List<DokkaSourceSet>, dri: Set<DRI>, content: String, language: String) = + private fun contentCode( + sourceSets: Set<DokkaSourceSet>, + dri: Set<DRI>, + content: String, + language: String, + styles: Set<Style> = emptySet(), + extra: PropertyContainer<ContentNode> = PropertyContainer.empty() + ) = ContentCode( children = listOf( ContentText( text = content, - dci = DCI(dri, ContentKind.BriefComment), - sourceSets = sourceSets.toSet(), + dci = DCI(dri, ContentKind.Sample), + sourceSets = sourceSets, style = emptySet(), extra = PropertyContainer.empty() ) ), language = language, - extra = PropertyContainer.empty(), - dci = DCI(dri, ContentKind.Source), - sourceSets = sourceSets.toSet(), - style = emptySet() + dci = DCI(dri, ContentKind.Sample), + sourceSets = sourceSets, + style = styles + ContentStyle.RunnableSample + TextStyle.Monospace, + extra = extra ) }
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt index fec986a9..eb2989db 100644 --- a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt +++ b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt @@ -75,7 +75,7 @@ open class DefaultPageCreator( sourceSetDependentHint( m.dri, m.sourceSets.toSet(), - kind = ContentKind.SourceSetDependantHint, + kind = ContentKind.SourceSetDependentHint, styles = setOf(TextStyle.UnderCoverText) ) { +contentForDescription(m) @@ -97,7 +97,7 @@ open class DefaultPageCreator( sourceSetDependentHint( p.dri, p.sourceSets.toSet(), - kind = ContentKind.SourceSetDependantHint, + kind = ContentKind.SourceSetDependentHint, styles = setOf(TextStyle.UnderCoverText) ) { +contentForDescription(p) @@ -135,7 +135,7 @@ open class DefaultPageCreator( extra = mainExtra + SimpleAttr.header("Properties") ) { link(it.name, it.dri, kind = ContentKind.Main) - sourceSetDependentHint(it.dri, it.sourceSets.toSet(), kind = ContentKind.SourceSetDependantHint) { + sourceSetDependentHint(it.dri, it.sourceSets.toSet(), kind = ContentKind.SourceSetDependentHint) { contentForBrief(it) +buildSignature(it) } @@ -204,7 +204,7 @@ open class DefaultPageCreator( sourceSetDependentHint( it.dri, it.sourceSets.toSet(), - kind = ContentKind.SourceSetDependantHint, + kind = ContentKind.SourceSetDependentHint, styles = emptySet() ) { contentForBrief(it) @@ -224,7 +224,7 @@ open class DefaultPageCreator( styles = emptySet() ) { link(it.name, it.dri) - sourceSetDependentHint(it.dri, it.sourceSets.toSet(), kind = ContentKind.SourceSetDependantHint) { + sourceSetDependentHint(it.dri, it.sourceSets.toSet(), kind = ContentKind.SourceSetDependentHint) { contentForBrief(it) +buildSignature(it) } @@ -319,7 +319,7 @@ open class DefaultPageCreator( extra = mainExtra + SimpleAttr.header("Parameters"), styles = setOf(ContentStyle.WithExtraAttributes) ) { - sourceSetDependentHint(sourceSets = platforms.toSet(), kind = ContentKind.SourceSetDependantHint) { + sourceSetDependentHint(sourceSets = platforms.toSet(), kind = ContentKind.SourceSetDependentHint) { val receiver = tags.withTypeUnnamed<Receiver>() val params = tags.withTypeNamed<Param>() table(kind = ContentKind.Parameters) { @@ -360,7 +360,7 @@ open class DefaultPageCreator( extra = mainExtra + SimpleAttr.header("See also"), styles = setOf(ContentStyle.WithExtraAttributes) ) { - sourceSetDependentHint(sourceSets = platforms.toSet(), kind = ContentKind.SourceSetDependantHint) { + sourceSetDependentHint(sourceSets = platforms.toSet(), kind = ContentKind.SourceSetDependentHint) { val seeAlsoTags = tags.withTypeNamed<See>() table(kind = ContentKind.Sample) { platforms.flatMap { platform -> @@ -395,15 +395,15 @@ open class DefaultPageCreator( header(2, "Samples") group( extra = mainExtra + SimpleAttr.header("Samples"), - styles = setOf(ContentStyle.WithExtraAttributes) + styles = emptySet() ) { - sourceSetDependentHint(sourceSets = platforms.toSet(), kind = ContentKind.SourceSetDependantHint) { + sourceSetDependentHint(sourceSets = platforms.toSet(), kind = ContentKind.SourceSetDependentHint) { platforms.map { platformData -> val content = samples.filter { it.value.isEmpty() || platformData in it.value } group( sourceSets = setOf(platformData), kind = ContentKind.Sample, - styles = setOf(TextStyle.Monospace) + styles = setOf(TextStyle.Monospace, ContentStyle.RunnableSample) ) { content.forEach { text(it.key) diff --git a/plugins/base/src/main/resources/dokka/styles/style.css b/plugins/base/src/main/resources/dokka/styles/style.css index 4acf6cb2..1ccd9cbc 100644 --- a/plugins/base/src/main/resources/dokka/styles/style.css +++ b/plugins/base/src/main/resources/dokka/styles/style.css @@ -27,7 +27,7 @@ color: var(--hover-link-color) } -.tabs-section-body > *:not([data-active]){ +.tabs-section-body > *:not([data-active]) { display: none; } @@ -212,6 +212,10 @@ font-family: monospace; } +code.paragraph { + display: block; +} + .overview > .navButton { height: 100%; align-items: center; @@ -692,6 +696,7 @@ footer { [data-filterable-current=''] { display: none !important; } + .platform-selector:not([data-active]) { border: 1px solid #DADFE6; background-color: transparent; diff --git a/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt b/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt index c2596ba3..191df066 100644 --- a/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt +++ b/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt @@ -94,7 +94,8 @@ class LinkableContentTest : AbstractCoreTest() { testFromData(configuration) { renderingStage = { rootPageNode, dokkaContext -> - val newRoot = SourceLinksTransformer(dokkaContext, + val newRoot = SourceLinksTransformer( + dokkaContext, PageContentBuilder( dokkaContext.single(dokkaContext.plugin<DokkaBase>().commentsToContentConverter), dokkaContext.single(dokkaContext.plugin<DokkaBase>().signatureProvider), @@ -109,7 +110,8 @@ class LinkableContentTest : AbstractCoreTest() { val name = it.name.substringBefore("Class") val crl = it.safeAs<ClasslikePageNode>()?.content?.safeAs<ContentGroup>()?.children?.last() ?.safeAs<ContentGroup>()?.children?.last()?.safeAs<ContentGroup>()?.children?.lastOrNull() - ?.safeAs<ContentTable>()?.children?.singleOrNull()?.safeAs<ContentGroup>()?.children?.singleOrNull().safeAs<ContentResolvedLink>() + ?.safeAs<ContentTable>()?.children?.singleOrNull() + ?.safeAs<ContentGroup>()?.children?.singleOrNull().safeAs<ContentResolvedLink>() Assertions.assertEquals( "https://github.com/user/repo/tree/master/src/${name.toLowerCase()}Main/kotlin/${name}Class.kt#L3", crl?.address @@ -166,7 +168,12 @@ class LinkableContentTest : AbstractCoreTest() { .cast<ContentGroup>().children.single() .cast<ContentCode>().children.single().cast<ContentText>().text Assertions.assertEquals( - "${name}Class().printWithExclamation(\"Hi, $name\")", + """|import p2.${name}Class + |fun main() { + | //sampleStart + | ${name}Class().printWithExclamation("Hi, $name") + | //sampleEnd + |}""".trimMargin(), text ) } @@ -175,7 +182,7 @@ class LinkableContentTest : AbstractCoreTest() { } @Test - fun `Documenting return type for a function in inner class with generic parent`(){ + fun `Documenting return type for a function in inner class with generic parent`() { testInline( """ |/src/main/kotlin/test/source.kt |