blob: 13af77ce7f9230822f37a643e752ee14bb068770 [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
Ilya Ryzhenkovaa59acb2014-07-15 20:05:55 +040017 public abstract fun appendTable(to: StringBuilder, body: () -> Unit)
18 public abstract fun appendTableHeader(to: StringBuilder, body: () -> Unit)
19 public abstract fun appendTableBody(to: StringBuilder, body: () -> Unit)
20 public abstract fun appendTableRow(to: StringBuilder, body: () -> Unit)
21 public abstract fun appendTableCell(to: StringBuilder, body: () -> Unit)
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +040022
Ilya Ryzhenkovaa59acb2014-07-15 20:05:55 +040023 public abstract fun formatText(text: String): String
24 public abstract fun formatLink(text: String, location: Location): String
25 public open fun formatLink(link: FormatLink): String = formatLink(formatText(link.text), link.location)
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040026 public abstract fun formatBold(text: String): String
27 public abstract fun formatCode(code: String): String
28 public abstract fun formatBreadcrumbs(items: Iterable<FormatLink>): String
29
30 open public fun link(from: DocumentationNode, to: DocumentationNode): FormatLink = link(from, to, extension)
31
32 open public fun link(from: DocumentationNode, to: DocumentationNode, extension: String): FormatLink {
33 return FormatLink(to.name, locationService.relativeLocation(from, to, extension))
34 }
35
36 open public fun appendDescription(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
37 val described = nodes.filter { it.doc.hasDescription }
38 if (described.any()) {
Ilya Ryzhenkovfb41c692014-07-15 18:23:15 +040039 val single = described.size == 1
40 appendHeader(to, "Description", 3)
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040041 for (node in described) {
Ilya Ryzhenkovfb41c692014-07-15 18:23:15 +040042 if (!single) {
43 appendBlockCode(to, languageService.render(node))
44 }
Ilya Ryzhenkovaa59acb2014-07-15 20:05:55 +040045 appendLine(to, formatText(node.doc.description))
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040046 appendLine(to)
47 for (section in node.doc.sections) {
Ilya Ryzhenkovaa59acb2014-07-15 20:05:55 +040048 appendLine(to, formatBold(formatText(section.label)))
49 appendLine(to, formatText(section.text))
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040050 appendLine(to)
51 }
52 }
53 }
54 }
55
56 open public fun appendSummary(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
57 val breakdownBySummary = nodes.groupByTo(LinkedHashMap()) { node ->
58 node.doc.summary
59 }
60
61 for ((summary, items) in breakdownBySummary) {
62 appendLine(to, summary)
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +040063 appendBlockCode(to, items.map { languageService.render(it) })
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040064 }
65 }
66
67 open public fun appendLocation(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
68 val breakdownByName = nodes.groupByTo(LinkedHashMap()) { node -> node.name }
69 for ((name, items) in breakdownByName) {
Ilya Ryzhenkovaa59acb2014-07-15 20:05:55 +040070 appendHeader(to, formatText(name))
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040071 appendSummary(to, items)
72 appendDescription(to, items)
73 }
74 }
75
76 override fun appendNodes(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
77 val breakdownByLocation = nodes.groupByTo(LinkedHashMap()) { node ->
78 formatBreadcrumbs(node.path.map { link(node, it) })
79 }
80
81 for ((breadcrumbs, items) in breakdownByLocation) {
82 appendLine(to, breadcrumbs)
83 appendLine(to)
84 appendLocation(to, items)
85 }
86
87 for (node in nodes) {
88 if (node.members.any()) {
Ilya Ryzhenkovfb41c692014-07-15 18:23:15 +040089 appendHeader(to, "Members", 3)
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040090
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040091 val children = node.members.sortBy { it.name }
92 val membersMap = children.groupByTo(LinkedHashMap()) { link(node, it) }
93
Ilya Ryzhenkovaa59acb2014-07-15 20:05:55 +040094 appendTable(to) {
95 appendTableBody(to) {
96 for ((location, members) in membersMap) {
97 appendTableRow(to) {
98 appendTableCell(to) {
99 appendText(to, formatLink(location))
100 }
101 appendTableCell(to) {
102 val breakdownBySummary = members.groupByTo(LinkedHashMap()) { it.doc.summary }
103 for ((summary, items) in breakdownBySummary) {
104 if (!summary.isEmpty()) {
105 appendText(to, formatText(summary))
106 to.append("<br/>") // TODO: hardcoded
107 }
108
109 val signatures = items.map { formatBold(formatCode("${languageService.render(it)}")) }
110 to.append(signatures.join("<br/>")) // TODO: hardcoded
111 }
112 }
113 }
Ilya Ryzhenkove8447fd2014-07-15 16:37:50 +0400114 }
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400115 }
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400116 }
117 }
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400118 }
119 }
120
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +0400121 abstract public fun appendOutlineHeader(to: StringBuilder, node: DocumentationNode)
122 abstract public fun appendOutlineChildren(to: StringBuilder, nodes: Iterable<DocumentationNode>)
123
124 override public fun appendOutline(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
125 for (node in nodes) {
126 appendOutlineHeader(to, node)
127 if (node.members.any()) {
128 appendOutlineChildren(to, node.members)
129 }
130 }
131 }
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400132}