blob: bca53f4fb92f89def8f33d434e75cf441ef9df6d [file] [log] [blame]
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +04001package org.jetbrains.dokka
2
3import java.util.LinkedHashMap
4import org.jetbrains.dokka.DocumentationNode.Kind
5
6public data class FormatLink(val text: String, val location: Location)
7
8public abstract class StructuredFormatService(val locationService: LocationService,
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +04009 val languageService: LanguageService) : FormatService {
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040010
11 abstract public fun appendBlockCode(to: StringBuilder, line: String)
12 abstract public fun appendBlockCode(to: StringBuilder, lines: Iterable<String>)
13 abstract public fun appendHeader(to: StringBuilder, text: String, level: Int = 1)
14 abstract public fun appendText(to: StringBuilder, text: String)
15 abstract public fun appendLine(to: StringBuilder, text: String)
16 public abstract fun appendLine(to: StringBuilder)
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +040017
18 public abstract fun formatLink(text: String, location: Location): String
19 public open fun formatLink(link: FormatLink): String = formatLink(link.text, link.location)
20
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040021 public abstract fun formatBold(text: String): String
22 public abstract fun formatCode(code: String): String
23 public abstract fun formatBreadcrumbs(items: Iterable<FormatLink>): String
24
25 open public fun link(from: DocumentationNode, to: DocumentationNode): FormatLink = link(from, to, extension)
26
27 open public fun link(from: DocumentationNode, to: DocumentationNode, extension: String): FormatLink {
28 return FormatLink(to.name, locationService.relativeLocation(from, to, extension))
29 }
30
31 open public fun appendDescription(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
32 val described = nodes.filter { it.doc.hasDescription }
33 if (described.any()) {
34 appendHeader(to, "Description")
35 for (node in described) {
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +040036 appendBlockCode(to, languageService.render(node))
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040037 appendLine(to, node.doc.description)
38 appendLine(to)
39 for (section in node.doc.sections) {
40 appendLine(to, formatBold(section.label))
41 appendLine(to, section.text)
42 appendLine(to)
43 }
44 }
45 }
46 }
47
48 open public fun appendSummary(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
49 val breakdownBySummary = nodes.groupByTo(LinkedHashMap()) { node ->
50 node.doc.summary
51 }
52
53 for ((summary, items) in breakdownBySummary) {
54 appendLine(to, summary)
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +040055 appendBlockCode(to, items.map { languageService.render(it) })
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040056 }
57 }
58
59 open public fun appendLocation(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
60 val breakdownByName = nodes.groupByTo(LinkedHashMap()) { node -> node.name }
61 for ((name, items) in breakdownByName) {
62 appendHeader(to, "${name}")
63 appendSummary(to, items)
64 appendDescription(to, items)
65 }
66 }
67
68 override fun appendNodes(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
69 val breakdownByLocation = nodes.groupByTo(LinkedHashMap()) { node ->
70 formatBreadcrumbs(node.path.map { link(node, it) })
71 }
72
73 for ((breadcrumbs, items) in breakdownByLocation) {
74 appendLine(to, breadcrumbs)
75 appendLine(to)
76 appendLocation(to, items)
77 }
78
79 for (node in nodes) {
80 if (node.members.any()) {
81 appendHeader(to, "Members")
82
83 appendLine(to, "| Name | Summary |")
84 appendLine(to, "|------|---------|")
85 val children = node.members.sortBy { it.name }
86 val membersMap = children.groupByTo(LinkedHashMap()) { link(node, it) }
87
88 for ((location, members) in membersMap) {
89 val mainMember = members.first()
90 val displayName = when (mainMember.kind) {
91 Kind.Constructor -> "*.init*"
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +040092 else -> languageService.renderName(mainMember).htmlEscape()
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040093 }
94
95 appendText(to, "|${formatLink(location)}|")
96
97 val breakdownBySummary = members.groupByTo(LinkedHashMap()) { it.doc.summary }
98 for ((summary, items) in breakdownBySummary) {
99 appendLine(to, summary)
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +0400100 appendBlockCode(to, items.map { formatBold("${languageService.render(it)}") })
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400101 }
102
103 appendLine(to, "|")
104 }
105 }
106
107 }
108 }
109
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +0400110 abstract public fun appendOutlineHeader(to: StringBuilder, node: DocumentationNode)
111 abstract public fun appendOutlineChildren(to: StringBuilder, nodes: Iterable<DocumentationNode>)
112
113 override public fun appendOutline(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
114 for (node in nodes) {
115 appendOutlineHeader(to, node)
116 if (node.members.any()) {
117 appendOutlineChildren(to, node.members)
118 }
119 }
120 }
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400121}