aboutsummaryrefslogtreecommitdiff
path: root/plugins/base
diff options
context:
space:
mode:
authorVadim Mishenev <vad-mishenev@yandex.ru>2023-02-24 17:44:24 +0200
committerGitHub <noreply@github.com>2023-02-24 17:44:24 +0200
commit1040288ca76e070445f1400df2fcc5a56310be28 (patch)
tree52bed40e8a320f0835540b0cd38ea1899800e395 /plugins/base
parent8d23340d1c377b8f490cdee3c2c874453d321dd8 (diff)
downloaddokka-1040288ca76e070445f1400df2fcc5a56310be28.tar.gz
dokka-1040288ca76e070445f1400df2fcc5a56310be28.tar.bz2
dokka-1040288ca76e070445f1400df2fcc5a56310be28.zip
Reorganize tabs for Classlike (#2764)
Diffstat (limited to 'plugins/base')
-rw-r--r--plugins/base/api/base.api15
-rw-r--r--plugins/base/src/main/kotlin/DokkaBase.kt5
-rw-r--r--plugins/base/src/main/kotlin/renderers/DefaultTabSortingStrategy.kt30
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt160
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt405
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/DescriptionSections.kt2
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt52
-rw-r--r--plugins/base/src/main/resources/dokka/scripts/platform-content-handler.js52
-rw-r--r--plugins/base/src/main/resources/dokka/styles/style.css10
-rw-r--r--plugins/base/src/test/kotlin/content/signatures/ConstructorsSignaturesTest.kt171
-rw-r--r--plugins/base/src/test/kotlin/enums/KotlinEnumsTest.kt2
-rw-r--r--plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt12
-rw-r--r--plugins/base/src/test/kotlin/renderers/html/CoverPageTest.kt2
-rw-r--r--plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt2
-rw-r--r--plugins/base/src/test/kotlin/renderers/html/TabbedContentTest.kt111
-rw-r--r--plugins/base/src/test/kotlin/signatures/ObviousTypeSkippingTest.kt19
-rw-r--r--plugins/base/src/test/kotlin/signatures/SignatureTest.kt4
-rw-r--r--plugins/base/src/test/kotlin/transformerBuilders/PageTransformerBuilderTest.kt17
-rw-r--r--plugins/base/src/test/kotlin/transformers/MergeImplicitExpectActualDeclarationsTest.kt10
-rw-r--r--plugins/base/src/test/kotlin/utils/contentUtils.kt95
20 files changed, 762 insertions, 414 deletions
diff --git a/plugins/base/api/base.api b/plugins/base/api/base.api
index f529b0ee..5e36f375 100644
--- a/plugins/base/api/base.api
+++ b/plugins/base/api/base.api
@@ -10,7 +10,6 @@ public final class org/jetbrains/dokka/base/DokkaBase : org/jetbrains/dokka/plug
public final fun getDefaultExternalDocumentablesProvider ()Lorg/jetbrains/dokka/plugability/Extension;
public final fun getDefaultKotlinAnalysis ()Lorg/jetbrains/dokka/plugability/Extension;
public final fun getDefaultSamplesTransformer ()Lorg/jetbrains/dokka/plugability/Extension;
- public final fun getDefaultTabSortingStrategy ()Lorg/jetbrains/dokka/plugability/Extension;
public final fun getDeprecatedDocumentableFilter ()Lorg/jetbrains/dokka/plugability/Extension;
public final fun getDescriptorToDocumentableTranslator ()Lorg/jetbrains/dokka/plugability/Extension;
public final fun getDocTagToContentConverter ()Lorg/jetbrains/dokka/plugability/Extension;
@@ -272,11 +271,6 @@ public final class org/jetbrains/dokka/base/renderers/DefaultRendererKt {
public static final fun sourceSets (Lorg/jetbrains/dokka/pages/ContentPage;)Ljava/util/Set;
}
-public final class org/jetbrains/dokka/base/renderers/DefaultTabSortingStrategy : org/jetbrains/dokka/base/renderers/TabSortingStrategy {
- public fun <init> ()V
- public fun sort (Ljava/util/Collection;)Ljava/util/List;
-}
-
public final class org/jetbrains/dokka/base/renderers/FileWriter : org/jetbrains/dokka/base/renderers/OutputWriter {
public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext;
@@ -1450,16 +1444,19 @@ public class org/jetbrains/dokka/base/translators/documentables/DefaultPageCreat
public synthetic fun <init> (Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;Lorg/jetbrains/dokka/base/transformers/pages/comments/CommentsToContentConverter;Lorg/jetbrains/dokka/base/signatures/SignatureProvider;Lorg/jetbrains/dokka/utilities/DokkaLogger;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
protected fun contentForBrief (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/model/Documentable;)V
protected fun contentForClasslikesAndEntries (Ljava/util/List;)Lorg/jetbrains/dokka/pages/ContentGroup;
+ protected fun contentForConstructors (Ljava/util/List;Ljava/util/Set;Ljava/util/Set;)Lorg/jetbrains/dokka/pages/ContentGroup;
protected fun contentForDescription (Lorg/jetbrains/dokka/model/Documentable;)Ljava/util/List;
+ protected fun contentForEntries (Ljava/util/List;Ljava/util/Set;Ljava/util/Set;)Lorg/jetbrains/dokka/pages/ContentGroup;
protected fun contentForFunction (Lorg/jetbrains/dokka/model/DFunction;)Lorg/jetbrains/dokka/pages/ContentGroup;
protected fun contentForMember (Lorg/jetbrains/dokka/model/Documentable;)Lorg/jetbrains/dokka/pages/ContentGroup;
protected fun contentForMembers (Ljava/util/List;)Lorg/jetbrains/dokka/pages/ContentGroup;
protected fun contentForModule (Lorg/jetbrains/dokka/model/DModule;)Lorg/jetbrains/dokka/pages/ContentGroup;
protected fun contentForPackage (Lorg/jetbrains/dokka/model/DPackage;)Lorg/jetbrains/dokka/pages/ContentGroup;
protected fun contentForProperty (Lorg/jetbrains/dokka/model/DProperty;)Lorg/jetbrains/dokka/pages/ContentGroup;
- protected fun contentForScope (Ljava/util/Set;Ljava/util/Set;Ljava/util/List;Ljava/util/List;Ljava/util/List;)Lorg/jetbrains/dokka/pages/ContentGroup;
- protected fun contentForScope (Lorg/jetbrains/dokka/model/WithScope;Lorg/jetbrains/dokka/links/DRI;Ljava/util/Set;)Lorg/jetbrains/dokka/pages/ContentGroup;
- protected fun contentForScopes (Ljava/util/List;Ljava/util/Set;)Lorg/jetbrains/dokka/pages/ContentGroup;
+ protected fun contentForScope (Lorg/jetbrains/dokka/model/WithScope;Lorg/jetbrains/dokka/links/DRI;Ljava/util/Set;Ljava/util/List;)Lorg/jetbrains/dokka/pages/ContentGroup;
+ public static synthetic fun contentForScope$default (Lorg/jetbrains/dokka/base/translators/documentables/DefaultPageCreator;Lorg/jetbrains/dokka/model/WithScope;Lorg/jetbrains/dokka/links/DRI;Ljava/util/Set;Ljava/util/List;ILjava/lang/Object;)Lorg/jetbrains/dokka/pages/ContentGroup;
+ protected fun contentForScopes (Ljava/util/List;Ljava/util/Set;Ljava/util/List;)Lorg/jetbrains/dokka/pages/ContentGroup;
+ public static synthetic fun contentForScopes$default (Lorg/jetbrains/dokka/base/translators/documentables/DefaultPageCreator;Ljava/util/List;Ljava/util/Set;Ljava/util/List;ILjava/lang/Object;)Lorg/jetbrains/dokka/pages/ContentGroup;
protected fun divergentBlock (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Ljava/lang/String;Ljava/util/Collection;Lorg/jetbrains/dokka/pages/ContentKind;Lorg/jetbrains/dokka/model/properties/PropertyContainer;)V
public static synthetic fun divergentBlock$default (Lorg/jetbrains/dokka/base/translators/documentables/DefaultPageCreator;Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Ljava/lang/String;Ljava/util/Collection;Lorg/jetbrains/dokka/pages/ContentKind;Lorg/jetbrains/dokka/model/properties/PropertyContainer;ILjava/lang/Object;)V
protected fun getContentBuilder ()Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder;
diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt
index 456a587b..f76eef63 100644
--- a/plugins/base/src/main/kotlin/DokkaBase.kt
+++ b/plugins/base/src/main/kotlin/DokkaBase.kt
@@ -54,6 +54,7 @@ class DokkaBase : DokkaPlugin() {
val outputWriter by extensionPoint<OutputWriter>()
val htmlPreprocessors by extensionPoint<PageTransformer>()
val kotlinAnalysis by extensionPoint<KotlinAnalysis>()
+ @Deprecated("It is not used anymore")
val tabSortingStrategy by extensionPoint<TabSortingStrategy>()
val immediateHtmlCommandConsumer by extensionPoint<ImmediateHtmlCommandConsumer>()
val externalDocumentablesProvider by extensionPoint<ExternalDocumentablesProvider>()
@@ -182,10 +183,6 @@ class DokkaBase : DokkaPlugin() {
}
}
- val defaultTabSortingStrategy by extending {
- tabSortingStrategy with DefaultTabSortingStrategy()
- }
-
val htmlRenderer by extending {
CoreExtensions.renderer providing ::HtmlRenderer
}
diff --git a/plugins/base/src/main/kotlin/renderers/DefaultTabSortingStrategy.kt b/plugins/base/src/main/kotlin/renderers/DefaultTabSortingStrategy.kt
deleted file mode 100644
index 056e0f93..00000000
--- a/plugins/base/src/main/kotlin/renderers/DefaultTabSortingStrategy.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.jetbrains.dokka.base.renderers
-
-import org.jetbrains.dokka.pages.ContentKind
-import org.jetbrains.dokka.pages.ContentNode
-import org.jetbrains.dokka.pages.Kind
-
-private val kindsOrder = listOf(
- ContentKind.Classlikes,
- ContentKind.Constructors,
- ContentKind.Functions,
- ContentKind.Properties,
- ContentKind.Extensions,
- ContentKind.Parameters,
- ContentKind.Inheritors,
- ContentKind.Source,
- ContentKind.Sample,
- ContentKind.Comment
-)
-
-class DefaultTabSortingStrategy : TabSortingStrategy {
- override fun <T: ContentNode> sort(tabs: Collection<T>): List<T> {
- val tabMap: Map<Kind, MutableList<T>> = kindsOrder.asSequence().map { it to mutableListOf<T>() }.toMap()
- val unrecognized: MutableList<T> = mutableListOf()
- tabs.forEach {
- tabMap[it.dci.kind]?.add(it) ?: unrecognized.add(it)
- }
- return tabMap.values.flatten() + unrecognized
- }
-
-}
diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
index b4d98b58..dfefbad8 100644
--- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
@@ -14,9 +14,11 @@ import org.jetbrains.dokka.base.renderers.html.innerTemplating.HtmlTemplater
import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint
import org.jetbrains.dokka.base.resolvers.local.DokkaBaseLocationProvider
import org.jetbrains.dokka.base.templating.*
+import org.jetbrains.dokka.base.transformers.documentables.CallableExtensions
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.*
import org.jetbrains.dokka.model.properties.PropertyContainer
+import org.jetbrains.dokka.model.properties.WithExtraProperties
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.pages.HtmlContent
import org.jetbrains.dokka.plugability.*
@@ -24,6 +26,7 @@ import org.jetbrains.dokka.utilities.htmlEscape
import org.jetbrains.kotlin.utils.addIfNotNull
internal const val TEMPLATE_REPLACEMENT: String = "###"
+internal const val TOGGLEABLE_CONTENT_TYPE_ATTR = "data-togglable"
open class HtmlRenderer(
context: DokkaContext
@@ -45,19 +48,102 @@ open class HtmlRenderer(
override val preprocessors = context.plugin<DokkaBase>().query { htmlPreprocessors }
- private val tabSortingStrategy = context.plugin<DokkaBase>().querySingle { tabSortingStrategy }
+ /**
+ * Tabs themselves are created in HTML plugin since, currently, only HTML format supports them.
+ * [TabbedContentType] is used to mark content that should be inside tab content.
+ * A tab can display multiple [TabbedContentType].
+ * The content style [ContentStyle.TabbedContent] is used to determine where tabs will be generated.
+ *
+ * @see TabbedContentType
+ * @see ContentStyle.TabbedContent
+ */
+ private fun createTabs(pageContext: ContentPage): List<ContentTab> {
+ return when(pageContext) {
+ is ClasslikePage -> createTabsForClasslikes(pageContext)
+ is PackagePage -> createTabsForPackage(pageContext)
+ else -> throw IllegalArgumentException("Page ${pageContext.name} cannot have tabs")
+ }
+ }
+
+ private fun createTabsForClasslikes(page: ClasslikePage): List<ContentTab> {
+ val documentables = page.documentables
+ fun List<Documentable>.shouldDocumentConstructors() = !this.any { it is DAnnotation }
+ val csEnum = documentables.filterIsInstance<DEnum>()
+ val csWithConstructor = documentables.filterIsInstance<WithConstructors>()
+ val scopes = documentables.filterIsInstance<WithScope>()
+ val constructorsToDocumented = csWithConstructor.flatMap { it.constructors }
+
+ val containsRenderableConstructors = constructorsToDocumented.isNotEmpty() && documentables.shouldDocumentConstructors()
+ val containsRenderableMembers =
+ containsRenderableConstructors || scopes.any { it.classlikes.isNotEmpty() || it.functions.isNotEmpty() || it.properties.isNotEmpty() }
+
+ @Suppress("UNCHECKED_CAST")
+ val extensions = (documentables as List<WithExtraProperties<DClasslike>>).flatMap {
+ it.extra[CallableExtensions]?.extensions
+ ?.filterIsInstance<Documentable>().orEmpty()
+ }
+ .distinctBy { it.sourceSets to it.dri } // [Documentable] has expensive equals/hashCode at the moment, see #2620
+ return listOfNotNull(
+ if(!containsRenderableMembers) null else
+ ContentTab(
+ "Members",
+ listOf(
+ BasicTabbedContentType.CONSTRUCTOR,
+ BasicTabbedContentType.TYPE,
+ BasicTabbedContentType.FUNCTION,
+ BasicTabbedContentType.PROPERTY
+ )
+ ),
+ if (extensions.isEmpty()) null else ContentTab(
+ "Members & Extensions",
+ listOf(
+ BasicTabbedContentType.CONSTRUCTOR,
+ BasicTabbedContentType.TYPE,
+ BasicTabbedContentType.FUNCTION,
+ BasicTabbedContentType.PROPERTY,
+ BasicTabbedContentType.EXTENSION_PROPERTY,
+ BasicTabbedContentType.EXTENSION_FUNCTION
+ )
+ ),
+ if(csEnum.isEmpty()) null else ContentTab(
+ "Entries",
+ listOf(
+ BasicTabbedContentType.ENTRY
+ )
+ )
+ )
+ }
+
+ private fun createTabsForPackage(page: PackagePage): List<ContentTab> {
+ val p = page.documentables.single() as DPackage
+ return listOfNotNull(
+ ContentTab(
+ "Types",
+ listOf(
+ BasicTabbedContentType.TYPE,
+ )
+ ),
+ if (p.functions.isEmpty()) null else ContentTab(
+ "Functions",
+ listOf(
+ BasicTabbedContentType.FUNCTION,
+ BasicTabbedContentType.EXTENSION_FUNCTION,
+ )
+ ),
+ if (p.properties.isEmpty()) null else ContentTab(
+ "Properties",
+ listOf(
+ BasicTabbedContentType.PROPERTY,
+ BasicTabbedContentType.EXTENSION_PROPERTY,
+ )
+ )
+ )
+ }
private fun <R> TagConsumer<R>.prepareForTemplates() =
if (context.configuration.delayTemplateSubstitution || this is ImmediateResolutionTagConsumer) this
else ImmediateResolutionTagConsumer(this, context)
- private fun <T : ContentNode> sortTabs(strategy: TabSortingStrategy, tabs: Collection<T>): List<T> {
- val sorted = strategy.sort(tabs)
- if (sorted.size != tabs.size)
- context.logger.warn("Tab sorting strategy has changed number of tabs from ${tabs.size} to ${sorted.size}")
- return sorted
- }
-
override fun FlowContent.wrapGroup(
node: ContentGroup,
pageContext: ContentPage,
@@ -66,20 +152,16 @@ open class HtmlRenderer(
val additionalClasses = node.style.joinToString(" ") { it.toString().toLowerCase() }
return when {
node.hasStyle(ContentStyle.TabbedContent) -> div(additionalClasses) {
- val secondLevel = node.children.filterIsInstance<ContentComposite>().flatMap { it.children }
- .filterIsInstance<ContentHeader>().flatMap { it.children }.filterIsInstance<ContentText>()
- val firstLevel = node.children.filterIsInstance<ContentHeader>().flatMap { it.children }
- .filterIsInstance<ContentText>()
-
- val renderable = sortTabs(tabSortingStrategy, firstLevel.union(secondLevel))
+ val contentTabs = createTabs(pageContext)
div(classes = "tabs-section") {
attributes["tabs-section"] = "tabs-section"
- renderable.forEachIndexed { index, node ->
+ contentTabs.forEachIndexed { index, contentTab ->
button(classes = "section-tab") {
if (index == 0) attributes["data-active"] = ""
- attributes["data-togglable"] = node.text
- text(node.text)
+ attributes[TOGGLEABLE_CONTENT_TYPE_ATTR] =
+ contentTab.tabbedContentTypes.joinToString(",") { it.toHtmlAttribute() }
+ text(contentTab.text)
}
}
}
@@ -104,7 +186,9 @@ open class HtmlRenderer(
span("breakable-word") { childrenCallback() }
}
node.hasStyle(TextStyle.Span) -> span { childrenCallback() }
- node.dci.kind == ContentKind.Symbol -> div("symbol $additionalClasses") { childrenCallback() }
+ node.dci.kind == ContentKind.Symbol -> div("symbol $additionalClasses") {
+ childrenCallback()
+ }
node.dci.kind == SymbolContentKind.Parameters -> {
span("parameters $additionalClasses") {
childrenCallback()
@@ -122,7 +206,9 @@ open class HtmlRenderer(
}
node.dci.kind == ContentKind.Deprecation -> div("deprecation-content") { childrenCallback() }
node.hasStyle(TextStyle.Paragraph) -> p(additionalClasses) { childrenCallback() }
- node.hasStyle(TextStyle.Block) -> div(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.hasStyle(TextStyle.Strikethrough) -> strike { childrenCallback() }
@@ -139,6 +225,10 @@ open class HtmlRenderer(
node.hasStyle(ListStyle.DescriptionDetails) -> DD(emptyMap(), consumer).visit {
this@wrapGroup.childrenCallback()
}
+ node.extra.extraTabbedContentType() != null -> div() {
+ node.extra.extraTabbedContentType()?.let { attributes[TOGGLEABLE_CONTENT_TYPE_ATTR] = it.value.toHtmlAttribute() }
+ this@wrapGroup.childrenCallback()
+ }
else -> childrenCallback()
}
}
@@ -433,6 +523,7 @@ open class HtmlRenderer(
) {
buildAnchor(contextNode)
div(classes = "table-row") {
+ contextNode.extra.extraTabbedContentType()?.let { attributes[TOGGLEABLE_CONTENT_TYPE_ATTR] = it.value.toHtmlAttribute() }
addSourceSetFilteringAttributes(contextNode)
div("main-subrow keyValue " + contextNode.style.joinToString(separator = " ")) {
buildRowHeaderLink(toRender, pageContext, sourceSetRestriction, contextNode.anchor)
@@ -786,11 +877,19 @@ open class HtmlRenderer(
content(this, page)
}
+ private fun PageNode.getDocumentableType(): String? =
+ when(this) {
+ is PackagePage -> "package"
+ is ClasslikePage -> "classlike"
+ is MemberPage -> "member"
+ else -> null
+ }
open fun buildHtml(page: PageNode, resources: List<String>, content: FlowContent.() -> Unit): String =
templater.renderFromTemplate(DokkaTemplateTypes.BASE) {
val generatedContent =
createHTML().div("main-content") {
+ page.getDocumentableType()?.let { attributes["data-page-type"] = it }
id = "content"
(page as? ContentPage)?.let {
attributes["pageIds"] = "${context.configuration.moduleName}::${page.pageId}"
@@ -851,6 +950,28 @@ open class HtmlRenderer(
private val isPartial = context.configuration.delayTemplateSubstitution
}
+private fun TabbedContentType.toHtmlAttribute(): String =
+ when(this) {
+ is BasicTabbedContentType ->
+ when(this) {
+ BasicTabbedContentType.ENTRY -> "ENTRY"
+ BasicTabbedContentType.TYPE -> "TYPE"
+ BasicTabbedContentType.CONSTRUCTOR -> "CONSTRUCTOR"
+ BasicTabbedContentType.FUNCTION -> "FUNCTION"
+ BasicTabbedContentType.PROPERTY -> "PROPERTY"
+ BasicTabbedContentType.EXTENSION_PROPERTY -> "EXTENSION_PROPERTY"
+ BasicTabbedContentType.EXTENSION_FUNCTION -> "EXTENSION_FUNCTION"
+ }
+ else -> throw IllegalStateException("Unknown TabbedContentType $this")
+ }
+
+/**
+ * Tabs for a content with [ContentStyle.TabbedContent].
+ *
+ * @see ContentStyle.TabbedContent]
+ */
+private data class ContentTab(val text: String, val tabbedContentTypes: List<TabbedContentType>)
+
fun List<SimpleAttr>.joinAttr() = joinToString(" ") { it.extraKey + "=" + it.extraValue }
private fun String.stripDiv() = drop(5).dropLast(6) // TODO: Find a way to do it without arbitrary trims
@@ -859,6 +980,7 @@ private val PageNode.isNavigable: Boolean
get() = this !is RendererSpecificPage || strategy != RenderingStrategy.DoNothing
private fun PropertyContainer<ContentNode>.extraHtmlAttributes() = allOfType<SimpleAttr>()
+private fun PropertyContainer<ContentNode>.extraTabbedContentType() = this[TabbedContentTypeExtra]
private val ContentNode.sourceSetsFilters: String
get() = sourceSets.sourceSetIDs.joinToString(" ") { it.toString() }
diff --git a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
index 6006af5b..a9c6dcca 100644
--- a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
+++ b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
@@ -18,6 +18,7 @@ import org.jetbrains.dokka.model.properties.PropertyContainer
import org.jetbrains.dokka.model.properties.WithExtraProperties
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.utilities.DokkaLogger
+import java.util.Comparator
import kotlin.reflect.KClass
internal typealias GroupedTags = Map<KClass<out TagWrapper>, List<Pair<DokkaSourceSet?, TagWrapper>>>
@@ -90,7 +91,7 @@ open class DefaultPageCreator(
}
val constructors =
- if (documentables.shouldRenderConstructors()) {
+ if (documentables.shouldDocumentConstructors()) {
documentables.flatMap { (it as? WithConstructors)?.constructors ?: emptyList() }
} else {
emptyList()
@@ -179,6 +180,22 @@ open class DefaultPageCreator(
private val WithScope.filteredProperties: List<DProperty>
get() = properties.filterNot { it.isInherited() }
+ private fun Collection<Documentable>.splitPropsAndFuns(): Pair<List<DProperty>, List<DFunction>> {
+ val first = ArrayList<DProperty>()
+ val second = ArrayList<DFunction>()
+ for (element in this) {
+ when (element) {
+ is DProperty -> first.add(element)
+ is DFunction -> second.add(element)
+ else -> throw IllegalStateException("Expected only properties or functions")
+ }
+ }
+ return Pair(first, second)
+ }
+
+ private fun <T> Collection<T>.splitInheritedExtension(dri: Set<DRI>): Pair<List<T>, List<T>> where T : org.jetbrains.dokka.model.Callable =
+ partition { it.receiver?.dri !in dri }
+
private fun <T> Collection<T>.splitInherited(): Pair<List<T>, List<T>> where T : Documentable, T : WithExtraProperties<T> =
partition { it.isInherited() }
@@ -235,14 +252,15 @@ open class DefaultPageCreator(
}
}
}
- group(styles = setOf(ContentStyle.TabbedContent)) {
+ group(styles = setOf(ContentStyle.TabbedContent), extra = mainExtra) {
+contentForScope(p, p.dri, p.sourceSets)
}
}
protected open fun contentForScopes(
scopes: List<WithScope>,
- sourceSets: Set<DokkaSourceSet>
+ sourceSets: Set<DokkaSourceSet>,
+ extensions: List<Documentable> = emptyList()
): ContentGroup {
val types = scopes.flatMap { it.classlikes } + scopes.filterIsInstance<DPackage>().flatMap { it.typealiases }
return contentForScope(
@@ -251,40 +269,59 @@ open class DefaultPageCreator(
sourceSets,
types,
scopes.flatMap { it.functions },
- scopes.flatMap { it.properties }
+ scopes.flatMap { it.properties },
+ extensions
)
}
protected open fun contentForScope(
s: WithScope,
dri: DRI,
- sourceSets: Set<DokkaSourceSet>
+ sourceSets: Set<DokkaSourceSet>,
+ extensions: List<Documentable> = emptyList()
): ContentGroup {
val types = listOf(
s.classlikes,
(s as? DPackage)?.typealiases ?: emptyList()
).flatten()
- return contentForScope(setOf(dri), sourceSets, types, s.functions, s.properties)
+ return contentForScope(setOf(dri), sourceSets, types, s.functions, s.properties, extensions)
}
- protected open fun contentForScope(
+ private fun contentForScope(
dri: Set<DRI>,
sourceSets: Set<DokkaSourceSet>,
types: List<Documentable>,
functions: List<DFunction>,
- properties: List<DProperty>
+ properties: List<DProperty>,
+ extensions: List<Documentable>
) = contentBuilder.contentFor(dri, sourceSets) {
- divergentBlock("Types", types, ContentKind.Classlikes, extra = mainExtra + SimpleAttr.header("Types"))
+ divergentBlock(
+ "Types",
+ types,
+ ContentKind.Classlikes
+ )
+ val (extensionProps, extensionFuns) = extensions.splitPropsAndFuns()
if (separateInheritedMembers) {
val (inheritedFunctions, memberFunctions) = functions.splitInherited()
val (inheritedProperties, memberProperties) = properties.splitInherited()
- propertiesBlock("Properties", memberProperties, sourceSets)
- propertiesBlock("Inherited properties", inheritedProperties, sourceSets)
- functionsBlock("Functions", memberFunctions)
- functionsBlock("Inherited functions", inheritedFunctions)
+
+ val (inheritedExtensionFunctions, extensionFunctions) = extensionFuns.splitInheritedExtension(dri)
+ val (inheritedExtensionProperties, extensionProperties) = extensionProps.splitInheritedExtension(dri)
+ propertiesBlock(
+ "Properties", memberProperties + extensionProperties
+ )
+ propertiesBlock(
+ "Inherited properties", inheritedProperties + inheritedExtensionProperties
+ )
+ functionsBlock("Functions", memberFunctions + extensionFunctions)
+ functionsBlock(
+ "Inherited functions", inheritedFunctions + inheritedExtensionFunctions
+ )
} else {
- functionsBlock("Functions", functions)
- propertiesBlock("Properties", properties, sourceSets)
+ functionsBlock("Functions", functions + extensionFuns)
+ propertiesBlock(
+ "Properties", properties + extensionProps
+ )
}
}
@@ -302,7 +339,8 @@ open class DefaultPageCreator(
val extensions = (classlikes as List<WithExtraProperties<DClasslike>>).flatMap {
it.extra[CallableExtensions]?.extensions
?.filterIsInstance<Documentable>().orEmpty()
- }.distinctBy{ it.sourceSets to it.dri} // [Documentable] has expensive equals/hashCode at the moment, see #2620
+ }
+ .distinctBy { it.sourceSets to it.dri } // [Documentable] has expensive equals/hashCode at the moment, see #2620
// Extensions are added to sourceSets since they can be placed outside the sourceSets from classlike
// Example would be an Interface in common and extension function in jvm
@@ -315,78 +353,91 @@ open class DefaultPageCreator(
}
}
}
- group(styles = setOf(ContentStyle.TabbedContent), sourceSets = mainSourcesetData + extensions.sourceSets) {
- val csWithConstructor = classlikes.filterIsInstance<WithConstructors>()
- if (csWithConstructor.isNotEmpty() && documentables.shouldRenderConstructors()) {
- val constructorsToDocumented = csWithConstructor.flatMap { it.constructors }
- multiBlock(
- "Constructors",
- 2,
- ContentKind.Constructors,
- constructorsToDocumented.groupBy { it.name }
- .map { (_, v) -> v.first().name to v },
- @Suppress("UNCHECKED_CAST")
- (csWithConstructor as List<Documentable>).sourceSets,
- needsAnchors = true,
- extra = PropertyContainer.empty<ContentNode>() + SimpleAttr.header("Constructors")
- ) { key, ds ->
- link(key, ds.first().dri, kind = ContentKind.Main, styles = setOf(ContentStyle.RowTitle))
- sourceSetDependentHint(
- ds.dri,
- ds.sourceSets,
- kind = ContentKind.SourceSetDependentHint,
- styles = emptySet(),
- extra = PropertyContainer.empty<ContentNode>()
- ) {
- ds.forEach {
- +buildSignature(it)
- contentForBrief(it)
- }
- }
- }
+ val csEnum = classlikes.filterIsInstance<DEnum>()
+ val csWithConstructor = classlikes.filterIsInstance<WithConstructors>()
+ val scopes = documentables.filterIsInstance<WithScope>()
+ val constructorsToDocumented = csWithConstructor.flatMap { it.constructors }
+
+ group(
+ styles = setOf(ContentStyle.TabbedContent),
+ sourceSets = mainSourcesetData + extensions.sourceSets,
+ extra = mainExtra
+ ) {
+ if (constructorsToDocumented.isNotEmpty() && documentables.shouldDocumentConstructors()) {
+ +contentForConstructors(constructorsToDocumented, classlikes.dri, classlikes.sourceSets)
}
- val csEnum = classlikes.filterIsInstance<DEnum>()
if (csEnum.isNotEmpty()) {
- multiBlock(
- "Entries",
- 2,
- ContentKind.Classlikes,
- csEnum.flatMap { it.entries }.groupBy { it.name }.toList(),
- csEnum.sourceSets,
- needsSorting = false,
- needsAnchors = true,
- extra = mainExtra + SimpleAttr.header("Entries"),
- styles = emptySet()
- ) { key, ds ->
- link(key, ds.first().dri)
- sourceSetDependentHint(
- ds.dri,
- ds.sourceSets,
- kind = ContentKind.SourceSetDependentHint,
- extra = PropertyContainer.empty<ContentNode>()
- ) {
- ds.forEach {
- +buildSignature(it)
- contentForBrief(it)
- }
- }
- }
+ +contentForEntries(csEnum.flatMap { it.entries }, csEnum.dri, csEnum.sourceSets)
}
- +contentForScopes(documentables.filterIsInstance<WithScope>(), documentables.sourceSets)
+ +contentForScopes(scopes, documentables.sourceSets, extensions)
+ }
+ }
+ protected open fun contentForConstructors(
+ constructorsToDocumented: List<DFunction>,
+ dri: Set<DRI>,
+ sourceSets: Set<DokkaSourceSet>
+ ) = contentBuilder.contentFor(dri, sourceSets) {
+ multiBlock(
+ "Constructors",
+ 2,
+ ContentKind.Constructors,
+ constructorsToDocumented.groupBy { it.name }
+ .map { (_, v) -> v.first().name to v },
+ @Suppress("UNCHECKED_CAST")
+ (constructorsToDocumented as List<Documentable>).sourceSets,
+ needsAnchors = true,
+ extra = PropertyContainer.empty<ContentNode>() + TabbedContentTypeExtra(
+ BasicTabbedContentType.CONSTRUCTOR
+ ),
+ ) { key, ds ->
+ link(key, ds.first().dri, kind = ContentKind.Main, styles = setOf(ContentStyle.RowTitle))
+ sourceSetDependentHint(
+ ds.dri,
+ ds.sourceSets,
+ kind = ContentKind.SourceSetDependentHint,
+ styles = emptySet(),
+ extra = PropertyContainer.empty<ContentNode>()
+ ) {
+ ds.forEach {
+ +buildSignature(it)
+ contentForBrief(it)
+ }
+ }
+ }
+ }
- divergentBlock(
- "Extensions",
- extensions,
- ContentKind.Extensions,
- extra = mainExtra + SimpleAttr.header("Extensions")
- )
+ protected open fun contentForEntries(
+ entries: List<DEnumEntry>,
+ dri: Set<DRI>,
+ sourceSets: Set<DokkaSourceSet>
+ ) = contentBuilder.contentFor(dri, sourceSets) {
+ multiBlock(
+ "Entries",
+ 2,
+ ContentKind.Classlikes,
+ entries.groupBy { it.name }.toList(),
+ entries.sourceSets,
+ needsSorting = false,
+ needsAnchors =