aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt
diff options
context:
space:
mode:
authorIgnat Beresnev <ignat.beresnev@jetbrains.com>2022-07-29 14:32:24 +0200
committerGitHub <noreply@github.com>2022-07-29 14:32:24 +0200
commit7a875ee7d20b67725debd4c2c9e1f93e1889c302 (patch)
tree075210f83e5e5a7679194ba8c88dc426dead0777 /plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt
parent26dde5b201b3c7e66212b07ddef333a3e340022a (diff)
downloaddokka-7a875ee7d20b67725debd4c2c9e1f93e1889c302.tar.gz
dokka-7a875ee7d20b67725debd4c2c9e1f93e1889c302.tar.bz2
dokka-7a875ee7d20b67725debd4c2c9e1f93e1889c302.zip
Add member icons to navigation menu (#2578)
Diffstat (limited to 'plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt')
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt90
1 files changed, 90 insertions, 0 deletions
diff --git a/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt b/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt
new file mode 100644
index 00000000..647ba687
--- /dev/null
+++ b/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt
@@ -0,0 +1,90 @@
+package org.jetbrains.dokka.base.renderers.html
+
+import org.jetbrains.dokka.base.renderers.sourceSets
+import org.jetbrains.dokka.base.transformers.documentables.isException
+import org.jetbrains.dokka.base.translators.documentables.DocumentableLanguage
+import org.jetbrains.dokka.base.translators.documentables.documentableLanguage
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.pages.*
+
+abstract class NavigationDataProvider {
+ open fun navigableChildren(input: RootPageNode): NavigationNode = input.withDescendants()
+ .first { it is ModulePage || it is MultimoduleRootPage }.let { visit(it as ContentPage) }
+
+ open fun visit(page: ContentPage): NavigationNode =
+ NavigationNode(
+ name = page.displayableName(),
+ dri = page.dri.first(),
+ sourceSets = page.sourceSets(),
+ icon = chooseNavigationIcon(page),
+ children = page.navigableChildren()
+ )
+
+ /**
+ * Parenthesis is applied in 1 case:
+ * - page only contains functions (therefore documentable from this page is [DFunction])
+ */
+ private fun ContentPage.displayableName(): String =
+ if (this is WithDocumentables && documentables.all { it is DFunction }) {
+ "$name()"
+ } else {
+ name
+ }
+
+ private fun chooseNavigationIcon(contentPage: ContentPage): NavigationNodeIcon? {
+ return if (contentPage is WithDocumentables) {
+ val documentable = contentPage.documentables.firstOrNull()
+ val isJava = documentable?.hasAnyJavaSources() ?: false
+
+ when (documentable) {
+ is DClass -> when {
+ documentable.isException -> NavigationNodeIcon.EXCEPTION
+ documentable.isAbstract() -> {
+ if (isJava) NavigationNodeIcon.ABSTRACT_CLASS else NavigationNodeIcon.ABSTRACT_CLASS_KT
+ }
+ else -> if (isJava) NavigationNodeIcon.CLASS else NavigationNodeIcon.CLASS_KT
+ }
+ is DFunction -> NavigationNodeIcon.FUNCTION
+ is DProperty -> {
+ val isVar = documentable.extra[IsVar] != null
+ if (isVar) NavigationNodeIcon.VAR else NavigationNodeIcon.VAL
+ }
+ is DInterface -> if (isJava) NavigationNodeIcon.INTERFACE else NavigationNodeIcon.INTERFACE_KT
+ is DEnum,
+ is DEnumEntry -> if (isJava) NavigationNodeIcon.ENUM_CLASS else NavigationNodeIcon.ENUM_CLASS_KT
+ is DAnnotation -> {
+ if (isJava) NavigationNodeIcon.ANNOTATION_CLASS else NavigationNodeIcon.ANNOTATION_CLASS_KT
+ }
+ is DObject -> NavigationNodeIcon.OBJECT
+ else -> null
+ }
+ } else {
+ null
+ }
+ }
+
+ private fun Documentable.hasAnyJavaSources(): Boolean {
+ val withSources = this as? WithSources ?: return false
+ return this.sourceSets.any { withSources.documentableLanguage(it) == DocumentableLanguage.JAVA }
+ }
+
+ private fun DClass.isAbstract(): Boolean {
+ return modifier.values.all { it is KotlinModifier.Abstract || it is JavaModifier.Abstract }
+ }
+
+ private fun ContentPage.navigableChildren(): List<NavigationNode> {
+ return if (this !is ClasslikePageNode) {
+ children
+ .filterIsInstance<ContentPage>()
+ .map { visit(it) }
+ .sortedBy { it.name.toLowerCase() }
+ } else if (documentables.any { it is DEnum }) {
+ // no sorting for enum entries, should be the same as in source code
+ children
+ .filter { child -> child is WithDocumentables && child.documentables.any { it is DEnumEntry } }
+ .map { visit(it as ContentPage) }
+ } else {
+ emptyList()
+ }
+ }
+}