diff options
author | Ignat Beresnev <ignat.beresnev@jetbrains.com> | 2022-07-29 14:32:24 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-29 14:32:24 +0200 |
commit | 7a875ee7d20b67725debd4c2c9e1f93e1889c302 (patch) | |
tree | 075210f83e5e5a7679194ba8c88dc426dead0777 /plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt | |
parent | 26dde5b201b3c7e66212b07ddef333a3e340022a (diff) | |
download | dokka-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.kt | 90 |
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() + } + } +} |