From 018af7d18f50b0677a31714e29744ac2d8713c4f Mon Sep 17 00:00:00 2001 From: Vadim Mishenev Date: Fri, 29 Jul 2022 23:20:02 +0300 Subject: [PATCH] Move source links into signature (#2476) --- core/api/core.api | 1 + core/src/main/kotlin/pages/ContentNodes.kt | 3 +- plugins/base/api/base.api | 4 - .../kotlin/renderers/html/HtmlRenderer.kt | 1 + .../sourcelinks/SourceLinksTransformer.kt | 121 +++++++----------- .../src/main/resources/dokka/styles/style.css | 10 ++ .../src/test/kotlin/enums/JavaEnumsTest.kt | 2 +- .../src/test/kotlin/enums/KotlinEnumsTest.kt | 2 +- .../linkableContent/LinkableContentTest.kt | 7 +- 9 files changed, 66 insertions(+), 85 deletions(-) diff --git a/core/api/core.api b/core/api/core.api index ffb963050e..9f290fbd50 100644 --- a/core/api/core.api +++ b/core/api/core.api @@ -4280,6 +4280,7 @@ public final class org/jetbrains/dokka/pages/TextStyle : java/lang/Enum, org/jet public static final field Breakable Lorg/jetbrains/dokka/pages/TextStyle; public static final field BreakableAfter Lorg/jetbrains/dokka/pages/TextStyle; public static final field Cover Lorg/jetbrains/dokka/pages/TextStyle; + public static final field FloatingRight Lorg/jetbrains/dokka/pages/TextStyle; public static final field Indented Lorg/jetbrains/dokka/pages/TextStyle; public static final field InlineComment Lorg/jetbrains/dokka/pages/TextStyle; public static final field Italic Lorg/jetbrains/dokka/pages/TextStyle; diff --git a/core/src/main/kotlin/pages/ContentNodes.kt b/core/src/main/kotlin/pages/ContentNodes.kt index 59364af93e..07ff115903 100644 --- a/core/src/main/kotlin/pages/ContentNodes.kt +++ b/core/src/main/kotlin/pages/ContentNodes.kt @@ -383,7 +383,8 @@ enum class TokenStyle : Style { enum class TextStyle : Style { Bold, Italic, Strong, Strikethrough, Paragraph, - Block, Span, Monospace, Indented, Cover, UnderCoverText, BreakableAfter, Breakable, InlineComment, Quotation + Block, Span, Monospace, Indented, Cover, UnderCoverText, BreakableAfter, Breakable, InlineComment, Quotation, + FloatingRight } enum class ContentStyle : Style { diff --git a/plugins/base/api/base.api b/plugins/base/api/base.api index bf5dcff727..4e1185d2d7 100644 --- a/plugins/base/api/base.api +++ b/plugins/base/api/base.api @@ -1350,10 +1350,6 @@ public final class org/jetbrains/dokka/base/transformers/pages/sourcelinks/Sourc public fun invoke (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RootPageNode; } -public final class org/jetbrains/dokka/base/transformers/pages/sourcelinks/SourceLinksTransformerKt { - public static final fun hasTabbedContent (Lorg/jetbrains/dokka/pages/ContentGroup;)Z -} - public abstract interface class org/jetbrains/dokka/base/transformers/pages/tags/CustomTagContentProvider { public abstract fun contentForBrief (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/model/doc/CustomTagWrapper;)V public abstract fun contentForDescription (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/model/doc/CustomTagWrapper;)V diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt index 9f5682876c..a28fcd0477 100644 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt @@ -128,6 +128,7 @@ open class HtmlRenderer( node.hasStyle(TextStyle.Paragraph) -> p(additionalClasses) { childrenCallback() } node.hasStyle(TextStyle.Block) -> div(additionalClasses) { childrenCallback() } node.hasStyle(TextStyle.Quotation) -> blockQuote(additionalClasses) { childrenCallback() } + node.hasStyle(TextStyle.FloatingRight) -> span("clearfix") { span("floating-right") { childrenCallback() } } node.isAnchorable -> buildAnchor( node.anchor!!, node.anchorLabel!!, diff --git a/plugins/base/src/main/kotlin/transformers/pages/sourcelinks/SourceLinksTransformer.kt b/plugins/base/src/main/kotlin/transformers/pages/sourcelinks/SourceLinksTransformer.kt index 50add45199..385cd335ea 100644 --- a/plugins/base/src/main/kotlin/transformers/pages/sourcelinks/SourceLinksTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/pages/sourcelinks/SourceLinksTransformer.kt @@ -7,11 +7,9 @@ import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.analysis.DescriptorDocumentableSource import org.jetbrains.dokka.analysis.PsiDocumentableSource import org.jetbrains.dokka.base.DokkaBase -import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder -import org.jetbrains.dokka.model.DocumentableSource -import org.jetbrains.dokka.model.WithSources -import org.jetbrains.dokka.model.toDisplaySourceSets +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.* import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin @@ -20,6 +18,7 @@ import org.jetbrains.dokka.transformers.pages.PageTransformer import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.utils.addToStdlib.cast +import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty import java.io.File class SourceLinksTransformer(val context: DokkaContext) : PageTransformer { @@ -35,15 +34,17 @@ class SourceLinksTransformer(val context: DokkaContext) : PageTransformer { if (sourceLinks.isEmpty()) { return input } - return input.transformContentPagesTree { node -> + return input.transformContentPagesTree { node -> when (node) { - is WithDocumentables -> - node.documentables + is WithDocumentables -> { + val sources = node.documentables .filterIsInstance() - .flatMap { resolveSources(sourceLinks, it) } - .takeIf { it.isNotEmpty() } - ?.let { node.addSourcesContent(it) } - ?: node + .associate { (it as Documentable).dri to resolveSources(sourceLinks, it) } + if (sources.isNotEmpty()) + node.modified(content = transformContent(node.content, sources)) + else + node + } else -> node } } @@ -66,39 +67,6 @@ class SourceLinksTransformer(val context: DokkaContext) : PageTransformer { } } - private fun ContentPage.addSourcesContent(sources: List>) = builder - .buildSourcesContent(this, sources) - .let { - this.modified( - content = this.content.addTable(it) - ) - } - - private fun PageContentBuilder.buildSourcesContent( - node: ContentPage, - sources: List> - ): ContentGroup { - val documentables = (node as? WithDocumentables)?.documentables.orEmpty() - return contentFor( - node.dri, - documentables.flatMap { it.sourceSets }.toSet() - ) { - header(2, "Sources", kind = ContentKind.Source) - +ContentTable( - header = emptyList(), - children = sources.map { - buildGroup(node.dri, setOf(it.first), kind = ContentKind.Source, extra = mainExtra + SymbolAnchorHint(it.second, ContentKind.Source)) { - link("${it.first.displayName} source", it.second) - } - }, - dci = DCI(node.dri, ContentKind.Source), - sourceSets = documentables.flatMap { it.sourceSets }.toDisplaySourceSets(), - style = emptySet(), - extra = mainExtra + SimpleAttr.header("Sources") - ) - } - } - private fun DocumentableSource.toLink(sourceLink: SourceLink): String { val sourcePath = File(this.path).invariantSeparatorsPath val sourceLinkPath = File(sourceLink.path).invariantSeparatorsPath @@ -117,33 +85,6 @@ class SourceLinksTransformer(val context: DokkaContext) : PageTransformer { "${lineNumber ?: 1}" } - private fun ContentNode.addTable(table: ContentGroup): ContentNode = - when (this) { - is ContentGroup -> { - if (hasTabbedContent()) { - copy( - children = children.map { - if (it.hasStyle(ContentStyle.TabbedContent) && it is ContentGroup) { - it.copy(children = it.children + table) - } else { - it - } - } - ) - } else { - copy(children = children + table) - } - - } - else -> ContentGroup( - children = listOf(this, table), - extra = this.extra, - sourceSets = this.sourceSets, - dci = this.dci, - style = this.style - ) - } - private fun PsiElement.lineNumber(): Int? { // synthetic and some light methods might return null val textRange = textRange ?: return null @@ -152,6 +93,40 @@ class SourceLinksTransformer(val context: DokkaContext) : PageTransformer { // IJ uses 0-based line-numbers; external source browsers use 1-based return doc?.getLineNumber(textRange.startOffset)?.plus(1) } + + private fun ContentNode.signatureGroupOrNull() = + (this as? ContentGroup)?.takeIf { it.dci.kind == ContentKind.Symbol } + + private fun transformContent( + contentNode: ContentNode, sources: Map>> + ): ContentNode = + contentNode.signatureGroupOrNull()?.let { sg -> + sources[sg.dci.dri.singleOrNull()]?.let { sourceLinks -> + sourceLinks.filter { it.first.sourceSetID in sg.sourceSets.sourceSetIDs }.ifNotEmpty { + sg.copy(children = sg.children + sourceLinks.map { + buildContentLink( + sg.dci.dri.first(), + it.first, + it.second + ) + }) + } + } + } ?: when (contentNode) { + is ContentComposite -> contentNode.transformChildren { transformContent(it, sources) } + else -> contentNode + } + + private fun buildContentLink(dri: DRI, sourceSet: DokkaSourceSet, link: String) = builder.contentFor( + dri, + setOf(sourceSet), + ContentKind.Source, + setOf(TextStyle.FloatingRight) + ) { + text("(") + link("source", link) + text(")") + } } data class SourceLink(val path: String, val url: String, val lineSuffix: String?, val sourceSetData: DokkaSourceSet) { @@ -161,6 +136,4 @@ data class SourceLink(val path: String, val url: String, val lineSuffix: String? sourceLinkDefinition.remoteLineSuffix, sourceSetData ) -} - -fun ContentGroup.hasTabbedContent(): Boolean = children.any { it.hasStyle(ContentStyle.TabbedContent) } +} \ No newline at end of file diff --git a/plugins/base/src/main/resources/dokka/styles/style.css b/plugins/base/src/main/resources/dokka/styles/style.css index 6a9d2a87c6..5b1e95e6fd 100644 --- a/plugins/base/src/main/resources/dokka/styles/style.css +++ b/plugins/base/src/main/resources/dokka/styles/style.css @@ -1256,3 +1256,13 @@ div.runnablesample { display: none; } } +.clearfix::after { + content: ' '; + clear: both; + display: block; + height: 0; +} + +.floating-right { + float: right; +} diff --git a/plugins/base/src/test/kotlin/enums/JavaEnumsTest.kt b/plugins/base/src/test/kotlin/enums/JavaEnumsTest.kt index 939163ca01..20805a7c5c 100644 --- a/plugins/base/src/test/kotlin/enums/JavaEnumsTest.kt +++ b/plugins/base/src/test/kotlin/enums/JavaEnumsTest.kt @@ -56,7 +56,7 @@ class JavaEnumsTest : BaseAbstractTest() { ) { renderingStage = { _, _ -> val enumPage = writerPlugin.writer.renderedContent("root/testpackage/-java-enum/index.html") - val sourceLink = enumPage.select("div[data-togglable=Sources]") + val sourceLink = enumPage.select(".symbol .floating-right") .select("a[href]") .attr("href") diff --git a/plugins/base/src/test/kotlin/enums/KotlinEnumsTest.kt b/plugins/base/src/test/kotlin/enums/KotlinEnumsTest.kt index f527b87ce5..1fd33f6f71 100644 --- a/plugins/base/src/test/kotlin/enums/KotlinEnumsTest.kt +++ b/plugins/base/src/test/kotlin/enums/KotlinEnumsTest.kt @@ -407,7 +407,7 @@ class KotlinEnumsTest : BaseAbstractTest() { ) { renderingStage = { _, _ -> val sourceLink = writerPlugin.writer.renderedContent("root/testpackage/-kotlin-enum/index.html") - .select("div[data-togglable=Sources]") + .select(".symbol .floating-right") .select("a[href]") .attr("href") diff --git a/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt b/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt index 1a4bb33081..fadc8e836e 100644 --- a/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt +++ b/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test +import utils.assertNotNull import java.net.URL import java.nio.file.Paths @@ -131,10 +132,8 @@ class LinkableContentTest : BaseAbstractTest() { Assertions.assertEquals(2, packageChildren.size) packageChildren.forEach { val name = it.name.substringBefore("Class") - val crl = it.safeAs()?.content?.safeAs()?.children?.last() - ?.safeAs()?.children?.last()?.safeAs()?.children?.lastOrNull() - ?.safeAs()?.children?.singleOrNull() - ?.safeAs()?.children?.singleOrNull().safeAs() + val signature = it.safeAs()?.content?.dfs { it is ContentGroup && it.dci.kind == ContentKind.Symbol }.assertNotNull("signature") + val crl = signature.children.last().children[1].safeAs() Assertions.assertEquals( "https://github.com/user/repo/tree/master/src/${name.toLowerCase()}Main/kotlin/${name}Class.kt#L3", crl?.address