blob: 87115f8bb757c6f4e720ad0e606c65b4ebff7a20 [file] [log] [blame]
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +04001package org.jetbrains.dokka
2
3import java.util.LinkedHashMap
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +04004
5public data class FormatLink(val text: String, val location: Location)
6
7public abstract class StructuredFormatService(val locationService: LocationService,
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +04008 val languageService: LanguageService) : FormatService {
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +04009
10 abstract public fun appendBlockCode(to: StringBuilder, line: String)
11 abstract public fun appendBlockCode(to: StringBuilder, lines: Iterable<String>)
12 abstract public fun appendHeader(to: StringBuilder, text: String, level: Int = 1)
13 abstract public fun appendText(to: StringBuilder, text: String)
14 abstract public fun appendLine(to: StringBuilder, text: String)
15 public abstract fun appendLine(to: StringBuilder)
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +040016
17 public abstract fun formatLink(text: String, location: Location): String
Ilya Ryzhenkove8447fd2014-07-15 16:37:50 +040018 public open fun formatLink(link: FormatLink): String = formatLink(link.text, link.location)
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +040019
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040020 public abstract fun formatBold(text: String): String
21 public abstract fun formatCode(code: String): String
22 public abstract fun formatBreadcrumbs(items: Iterable<FormatLink>): String
23
24 open public fun link(from: DocumentationNode, to: DocumentationNode): FormatLink = link(from, to, extension)
25
26 open public fun link(from: DocumentationNode, to: DocumentationNode, extension: String): FormatLink {
27 return FormatLink(to.name, locationService.relativeLocation(from, to, extension))
28 }
29
30 open public fun appendDescription(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
31 val described = nodes.filter { it.doc.hasDescription }
32 if (described.any()) {
Ilya Ryzhenkovfb41c692014-07-15 18:23:15 +040033 val single = described.size == 1
34 appendHeader(to, "Description", 3)
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040035 for (node in described) {
Ilya Ryzhenkovfb41c692014-07-15 18:23:15 +040036 if (!single) {
37 appendBlockCode(to, languageService.render(node))
38 }
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040039 appendLine(to, node.doc.description)
40 appendLine(to)
41 for (section in node.doc.sections) {
42 appendLine(to, formatBold(section.label))
43 appendLine(to, section.text)
44 appendLine(to)
45 }
46 }
47 }
48 }
49
50 open public fun appendSummary(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
51 val breakdownBySummary = nodes.groupByTo(LinkedHashMap()) { node ->
52 node.doc.summary
53 }
54
55 for ((summary, items) in breakdownBySummary) {
56 appendLine(to, summary)
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +040057 appendBlockCode(to, items.map { languageService.render(it) })
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040058 }
59 }
60
61 open public fun appendLocation(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
62 val breakdownByName = nodes.groupByTo(LinkedHashMap()) { node -> node.name }
63 for ((name, items) in breakdownByName) {
64 appendHeader(to, "${name}")
65 appendSummary(to, items)
66 appendDescription(to, items)
67 }
68 }
69
70 override fun appendNodes(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
71 val breakdownByLocation = nodes.groupByTo(LinkedHashMap()) { node ->
72 formatBreadcrumbs(node.path.map { link(node, it) })
73 }
74
75 for ((breadcrumbs, items) in breakdownByLocation) {
76 appendLine(to, breadcrumbs)
77 appendLine(to)
78 appendLocation(to, items)
79 }
80
81 for (node in nodes) {
82 if (node.members.any()) {
Ilya Ryzhenkovfb41c692014-07-15 18:23:15 +040083 appendHeader(to, "Members", 3)
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040084
Ilya Ryzhenkove8447fd2014-07-15 16:37:50 +040085 appendLine(to, "| Name | Summary |") // TODO: hardcoded
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040086 appendLine(to, "|------|---------|")
87 val children = node.members.sortBy { it.name }
88 val membersMap = children.groupByTo(LinkedHashMap()) { link(node, it) }
89
90 for ((location, members) in membersMap) {
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040091 appendText(to, "|${formatLink(location)}|")
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040092 val breakdownBySummary = members.groupByTo(LinkedHashMap()) { it.doc.summary }
93 for ((summary, items) in breakdownBySummary) {
Ilya Ryzhenkove8447fd2014-07-15 16:37:50 +040094 if (!summary.isEmpty()) {
95 appendText(to, summary)
Ilya Ryzhenkovfb41c692014-07-15 18:23:15 +040096 to.append("<br/>") // TODO: hardcoded
Ilya Ryzhenkove8447fd2014-07-15 16:37:50 +040097 }
98
99 val signatures = items.map { formatBold(formatCode("${languageService.render(it)}")) }
Ilya Ryzhenkovfb41c692014-07-15 18:23:15 +0400100 to.append(signatures.join("<br/>")) // TODO: hardcoded
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 Ryzhenkovfb41c692014-07-15 18:23:15 +0400121 public abstract fun formatText(text: String): String
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400122}