aboutsummaryrefslogtreecommitdiff
path: root/src/Kotlin/KotlinLanguageService.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/Kotlin/KotlinLanguageService.kt')
-rw-r--r--src/Kotlin/KotlinLanguageService.kt229
1 files changed, 229 insertions, 0 deletions
diff --git a/src/Kotlin/KotlinLanguageService.kt b/src/Kotlin/KotlinLanguageService.kt
new file mode 100644
index 00000000..80467914
--- /dev/null
+++ b/src/Kotlin/KotlinLanguageService.kt
@@ -0,0 +1,229 @@
+package org.jetbrains.dokka
+
+import org.jetbrains.dokka.symbol
+import org.jetbrains.dokka.text
+import org.jetbrains.dokka.identifier
+import org.jetbrains.dokka.link
+import org.jetbrains.dokka.keyword
+import org.jetbrains.dokka.LanguageService
+import org.jetbrains.dokka.DocumentationNode
+import org.jetbrains.dokka.ContentNode
+import org.jetbrains.dokka
+import org.jetbrains.dokka.ContentText
+
+class KotlinLanguageService : LanguageService {
+ override fun render(node: DocumentationNode): ContentNode {
+ return dokka.content {
+ when (node.kind) {
+ DocumentationNode.Kind.Package -> renderPackage(node)
+ DocumentationNode.Kind.Class,
+ DocumentationNode.Kind.Interface,
+ DocumentationNode.Kind.Enum,
+ DocumentationNode.Kind.EnumItem,
+ DocumentationNode.Kind.Object -> renderClass(node)
+
+ DocumentationNode.Kind.TypeParameter -> renderTypeParameter(node)
+ DocumentationNode.Kind.Type,
+ DocumentationNode.Kind.UpperBound -> renderType(node)
+
+ DocumentationNode.Kind.Modifier -> renderModifier(node)
+ DocumentationNode.Kind.Constructor,
+ DocumentationNode.Kind.Function -> renderFunction(node)
+ DocumentationNode.Kind.Property -> renderProperty(node)
+ else -> ContentText("${node.kind}: ${node.name}")
+ }
+ }
+ }
+
+ override fun renderName(node: DocumentationNode): String {
+ return when (node.kind) {
+ DocumentationNode.Kind.Constructor -> node.owner!!.name
+ else -> node.name
+ }
+ }
+
+ private fun ContentNode.renderPackage(node: DocumentationNode) {
+ keyword("package")
+ text(" ")
+ identifier(node.name)
+ }
+
+ private fun ContentNode.renderList(nodes: List<DocumentationNode>, separator: String = ", ", renderItem: (DocumentationNode) -> Unit) {
+ if (nodes.none())
+ return
+ renderItem(nodes.first())
+ nodes.drop(1).forEach {
+ symbol(separator)
+ renderItem(it)
+ }
+ }
+
+ private fun ContentNode.renderLinked(node: DocumentationNode, body: ContentNode.(DocumentationNode)->Unit) {
+ val to = node.links.firstOrNull()
+ if (to == null)
+ body(node)
+ else
+ link(to) {
+ body(node)
+ }
+ }
+
+ private fun ContentNode.renderType(node: DocumentationNode) {
+ val typeArguments = node.details(DocumentationNode.Kind.Type)
+ if (node.name == "Function${typeArguments.count() - 1}") {
+ // lambda
+ symbol("(")
+ renderList(typeArguments.take(typeArguments.size - 1)) {
+ renderType(it)
+ }
+ symbol(")")
+ text(" ")
+ symbol("->")
+ text(" ")
+ renderType(typeArguments.last())
+ return
+ }
+ if (node.name == "ExtensionFunction${typeArguments.count() - 2}") {
+ // extension lambda
+ renderType(typeArguments.first())
+ symbol(".")
+ symbol("(")
+ renderList(typeArguments.drop(1).take(typeArguments.size - 2)) {
+ renderType(it)
+ }
+ symbol(")")
+ text(" ")
+ symbol("->")
+ text(" ")
+ renderType(typeArguments.last())
+ return
+ }
+ renderLinked(node) { identifier(it.name) }
+ if (typeArguments.any()) {
+ symbol("<")
+ renderList(typeArguments) {
+ renderType(it)
+ }
+ symbol(">")
+ }
+ }
+
+ private fun ContentNode.renderModifier(node: DocumentationNode) {
+ when (node.name) {
+ "final", "internal" -> {
+ }
+ else -> keyword(node.name)
+ }
+ }
+
+ private fun ContentNode.renderTypeParameter(node: DocumentationNode) {
+ val constraints = node.details(DocumentationNode.Kind.UpperBound)
+ identifier(node.name)
+ if (constraints.any()) {
+ symbol(" : ")
+ renderList(constraints) {
+ renderType(it)
+ }
+ }
+ }
+
+ private fun ContentNode.renderParameter(node: DocumentationNode) {
+ identifier(node.name)
+ symbol(": ")
+ val parameterType = node.detail(DocumentationNode.Kind.Type)
+ renderType(parameterType)
+ }
+
+ private fun ContentNode.renderTypeParametersForNode(node: DocumentationNode) {
+ val typeParameters = node.details(DocumentationNode.Kind.TypeParameter)
+ if (typeParameters.any()) {
+ symbol("<")
+ renderList(typeParameters) {
+ renderType(it)
+ }
+ symbol("> ")
+ }
+ }
+
+ private fun ContentNode.renderSupertypesForNode(node: DocumentationNode) {
+ val supertypes = node.details(DocumentationNode.Kind.Supertype)
+ if (supertypes.any()) {
+ symbol(" : ")
+ renderList(supertypes) {
+ renderType(it)
+ }
+ }
+ }
+
+ private fun ContentNode.renderModifiersForNode(node: DocumentationNode) {
+ val modifiers = node.details(DocumentationNode.Kind.Modifier)
+ for (it in modifiers) {
+ if (node.kind == org.jetbrains.dokka.DocumentationNode.Kind.Interface && it.name == "abstract")
+ continue
+ renderModifier(it)
+ text(" ")
+ }
+ }
+
+ private fun ContentNode.renderClass(node: DocumentationNode) {
+ renderModifiersForNode(node)
+ when (node.kind) {
+ DocumentationNode.Kind.Class -> keyword("class ")
+ DocumentationNode.Kind.Interface -> keyword("trait ")
+ DocumentationNode.Kind.Enum -> keyword("enum class ")
+ DocumentationNode.Kind.EnumItem -> keyword("enum val ")
+ DocumentationNode.Kind.Object -> keyword("object ")
+ else -> throw IllegalArgumentException("Node $node is not a class-like object")
+ }
+
+ identifier(node.name)
+ renderTypeParametersForNode(node)
+ renderSupertypesForNode(node)
+ }
+
+ private fun ContentNode.renderFunction(node: DocumentationNode) {
+ renderModifiersForNode(node)
+ when (node.kind) {
+ DocumentationNode.Kind.Constructor -> identifier(node.owner!!.name)
+ DocumentationNode.Kind.Function -> keyword("fun ")
+ else -> throw IllegalArgumentException("Node $node is not a function-like object")
+ }
+ renderTypeParametersForNode(node)
+ val receiver = node.details(DocumentationNode.Kind.Receiver).singleOrNull()
+ if (receiver != null) {
+ renderType(receiver.detail(DocumentationNode.Kind.Type))
+ symbol(".")
+ }
+
+ if (node.kind != org.jetbrains.dokka.DocumentationNode.Kind.Constructor)
+ identifier(node.name)
+
+ symbol("(")
+ renderList(node.details(DocumentationNode.Kind.Parameter)) {
+ renderParameter(it)
+ }
+ symbol(")")
+ if (node.kind != org.jetbrains.dokka.DocumentationNode.Kind.Constructor) {
+ symbol(": ")
+ renderType(node.detail(DocumentationNode.Kind.Type))
+ }
+ }
+
+ private fun ContentNode.renderProperty(node: DocumentationNode) {
+ renderModifiersForNode(node)
+ when (node.kind) {
+ DocumentationNode.Kind.Property -> keyword("val ")
+ else -> throw IllegalArgumentException("Node $node is not a property")
+ }
+ renderTypeParametersForNode(node)
+ val receiver = node.details(DocumentationNode.Kind.Receiver).singleOrNull()
+ if (receiver != null) {
+ renderType(receiver.detail(DocumentationNode.Kind.Type))
+ symbol(".")
+ }
+
+ identifier(node.name)
+ symbol(": ")
+ renderType(node.detail(DocumentationNode.Kind.Type))
+ }
+} \ No newline at end of file