diff options
Diffstat (limited to 'src/Formats')
| -rw-r--r-- | src/Formats/FormatService.kt | 2 | ||||
| -rw-r--r-- | src/Formats/HtmlFormatService.kt | 12 | ||||
| -rw-r--r-- | src/Formats/JekyllFormatService.kt | 2 | ||||
| -rw-r--r-- | src/Formats/KotlinWebsiteFormatService.kt | 35 | ||||
| -rw-r--r-- | src/Formats/OutlineService.kt | 4 | ||||
| -rw-r--r-- | src/Formats/StructuredFormatService.kt | 200 |
6 files changed, 160 insertions, 95 deletions
diff --git a/src/Formats/FormatService.kt b/src/Formats/FormatService.kt index 93470a4c..7e66a6b7 100644 --- a/src/Formats/FormatService.kt +++ b/src/Formats/FormatService.kt @@ -17,4 +17,4 @@ public interface FormatService { } /** Format content to [String] using specified [location] */ -fun FormatService.format(location: Location, nodes: Iterable<DocumentationNode>): String = StringBuilder { appendNodes(location, this, nodes) }.toString() +fun FormatService.format(location: Location, nodes: Iterable<DocumentationNode>): String = StringBuilder().apply { appendNodes(location, this, nodes) }.toString() diff --git a/src/Formats/HtmlFormatService.kt b/src/Formats/HtmlFormatService.kt index 5dcd432b..e810ef7f 100644 --- a/src/Formats/HtmlFormatService.kt +++ b/src/Formats/HtmlFormatService.kt @@ -114,13 +114,13 @@ public open class HtmlFormatService @Inject constructor(@Named("folders") locati override fun appendNodes(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) { templateService.appendHeader(to, getPageTitle(nodes)) - super<StructuredFormatService>.appendNodes(location, to, nodes) + super.appendNodes(location, to, nodes) templateService.appendFooter(to) } override fun appendOutline(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) { templateService.appendHeader(to, "Module Contents") - super<OutlineFormatService>.appendOutline(location, to, nodes) + super.appendOutline(location, to, nodes) templateService.appendFooter(to) } @@ -146,16 +146,16 @@ public open class HtmlFormatService @Inject constructor(@Named("folders") locati fun getPageTitle(nodes: Iterable<DocumentationNode>): String? { val breakdownByLocation = nodes.groupBy { node -> formatPageTitle(node) } - return breakdownByLocation.keySet().singleOrNull() + return breakdownByLocation.keys.singleOrNull() } fun formatPageTitle(node: DocumentationNode): String { val path = node.path - if (path.size() == 1) { + if (path.size == 1) { return path.first().name } - val qualifiedName = path.drop(1).map { it.name }.filter { it.length() > 0 }.join(".") - if (qualifiedName.length() == 0 && path.size() == 2) { + val qualifiedName = node.qualifiedName() + if (qualifiedName.length == 0 && path.size == 2) { return path.first().name + " / root package" } return path.first().name + " / " + qualifiedName diff --git a/src/Formats/JekyllFormatService.kt b/src/Formats/JekyllFormatService.kt index 113f229f..75684ac2 100644 --- a/src/Formats/JekyllFormatService.kt +++ b/src/Formats/JekyllFormatService.kt @@ -11,7 +11,7 @@ public open class JekyllFormatService @Inject constructor(locationService: Locat appendFrontMatter(nodes, to) to.appendln("---") to.appendln("") - super<MarkdownFormatService>.appendNodes(location, to, nodes) + super.appendNodes(location, to, nodes) } protected open fun appendFrontMatter(nodes: Iterable<DocumentationNode>, to: StringBuilder) { diff --git a/src/Formats/KotlinWebsiteFormatService.kt b/src/Formats/KotlinWebsiteFormatService.kt index 8fbebaae..25491cb3 100644 --- a/src/Formats/KotlinWebsiteFormatService.kt +++ b/src/Formats/KotlinWebsiteFormatService.kt @@ -5,6 +5,7 @@ import com.google.inject.Inject public class KotlinWebsiteFormatService @Inject constructor(locationService: LocationService, signatureGenerator: LanguageService) : JekyllFormatService(locationService, signatureGenerator) { + private var needHardLineBreaks = false override fun appendFrontMatter(nodes: Iterable<DocumentationNode>, to: StringBuilder) { super.appendFrontMatter(nodes, to) @@ -23,16 +24,27 @@ public class KotlinWebsiteFormatService @Inject constructor(locationService: Loc return "" } - override public fun formatCode(code: String): String = if (code.length() > 0) "<code>$code</code>" else "" + override public fun formatCode(code: String): String = if (code.length > 0) "<code>$code</code>" else "" override fun formatStrikethrough(text: String): String = "<s>$text</s>" - override fun appendAsSignature(to: StringBuilder, block: () -> Unit) { - val oldLength = to.length() - block() - if (to.length() > oldLength) { - to.append("<br/>") // since we've used HTML to format the signature, add an HTML line break following it + override fun appendAsSignature(to: StringBuilder, node: ContentNode, block: () -> Unit) { + val contentLength = node.textLength + if (contentLength == 0) return + to.append("<div class=\"signature\">") + needHardLineBreaks = contentLength >= 62 + try { + block() + } finally { + needHardLineBreaks = false } + to.append("</div>") + } + + override fun appendAsOverloadGroup(to: StringBuilder, block: () -> Unit) { + to.append("<div class=\"overload-group\">\n") + block() + to.append("</div>\n") } override fun formatLink(text: String, href: String): String { @@ -91,8 +103,19 @@ public class KotlinWebsiteFormatService @Inject constructor(locationService: Loc return "<span class=\"${identifierClassName(kind)}\">${formatText(text)}</span>" } + override fun formatSoftLineBreak(): String = if (needHardLineBreaks) + "<br/>" + else + "" + + override fun formatIndentedSoftLineBreak(): String = if (needHardLineBreaks) + "<br/> " + else + "" + private fun identifierClassName(kind: IdentifierKind) = when(kind) { IdentifierKind.ParameterName -> "parameterName" + IdentifierKind.SummarizedTypeName -> "summarizedTypeName" else -> "identifier" } } diff --git a/src/Formats/OutlineService.kt b/src/Formats/OutlineService.kt index 6c7e882e..6626cf51 100644 --- a/src/Formats/OutlineService.kt +++ b/src/Formats/OutlineService.kt @@ -16,7 +16,7 @@ public interface OutlineFormatService { for (node in nodes) { appendOutlineHeader(location, node, to) if (node.members.any()) { - val sortedMembers = node.members.sortBy { it.name } + val sortedMembers = node.members.sortedBy { it.name } appendOutlineLevel(to) { appendOutline(location, to, sortedMembers) } @@ -25,5 +25,5 @@ public interface OutlineFormatService { } fun formatOutline(location: Location, nodes: Iterable<DocumentationNode>): String = - StringBuilder { appendOutline(location, this, nodes) }.toString() + StringBuilder().apply { appendOutline(location, this, nodes) }.toString() } diff --git a/src/Formats/StructuredFormatService.kt b/src/Formats/StructuredFormatService.kt index 1c2e5338..41ffc61d 100644 --- a/src/Formats/StructuredFormatService.kt +++ b/src/Formats/StructuredFormatService.kt @@ -1,62 +1,66 @@ package org.jetbrains.dokka -import java.util.LinkedHashMap import org.jetbrains.dokka.LanguageService.RenderMode +import java.util.* -public data class FormatLink(val text: String, val href: String) +data class FormatLink(val text: String, val href: String) enum class ListKind { Ordered, Unordered } -public abstract class StructuredFormatService(locationService: LocationService, +abstract class StructuredFormatService(locationService: LocationService, val languageService: LanguageService, override val extension: String) : FormatService { val locationService: LocationService = locationService.withExtension(extension) - abstract public fun appendBlockCode(to: StringBuilder, line: String, language: String) - abstract public fun appendHeader(to: StringBuilder, text: String, level: Int = 1) - abstract public fun appendParagraph(to: StringBuilder, text: String) - abstract public fun appendLine(to: StringBuilder, text: String) - public abstract fun appendLine(to: StringBuilder) - public abstract fun appendAnchor(to: StringBuilder, anchor: String) - - public abstract fun appendTable(to: StringBuilder, body: () -> Unit) - public abstract fun appendTableHeader(to: StringBuilder, body: () -> Unit) - public abstract fun appendTableBody(to: StringBuilder, body: () -> Unit) - public abstract fun appendTableRow(to: StringBuilder, body: () -> Unit) - public abstract fun appendTableCell(to: StringBuilder, body: () -> Unit) - - public abstract fun formatText(text: String): String - public abstract fun formatSymbol(text: String): String - public abstract fun formatKeyword(text: String): String - public abstract fun formatIdentifier(text: String, kind: IdentifierKind): String - public fun formatEntity(text: String): String = text - public abstract fun formatLink(text: String, href: String): String - public open fun formatLink(link: FormatLink): String = formatLink(formatText(link.text), link.href) - public abstract fun formatStrong(text: String): String - public abstract fun formatStrikethrough(text: String): String - public abstract fun formatEmphasis(text: String): String - public abstract fun formatCode(code: String): String - public abstract fun formatUnorderedList(text: String): String - public abstract fun formatOrderedList(text: String): String - public abstract fun formatListItem(text: String, kind: ListKind): String - public abstract fun formatBreadcrumbs(items: Iterable<FormatLink>): String - public abstract fun formatNonBreakingSpace(): String + abstract fun appendBlockCode(to: StringBuilder, line: String, language: String) + abstract fun appendHeader(to: StringBuilder, text: String, level: Int = 1) + abstract fun appendParagraph(to: StringBuilder, text: String) + abstract fun appendLine(to: StringBuilder, text: String) + abstract fun appendLine(to: StringBuilder) + abstract fun appendAnchor(to: StringBuilder, anchor: String) + + abstract fun appendTable(to: StringBuilder, body: () -> Unit) + abstract fun appendTableHeader(to: StringBuilder, body: () -> Unit) + abstract fun appendTableBody(to: StringBuilder, body: () -> Unit) + abstract fun appendTableRow(to: StringBuilder, body: () -> Unit) + abstract fun appendTableCell(to: StringBuilder, body: () -> Unit) + + abstract fun formatText(text: String): String + abstract fun formatSymbol(text: String): String + abstract fun formatKeyword(text: String): String + abstract fun formatIdentifier(text: String, kind: IdentifierKind): String + fun formatEntity(text: String): String = text + abstract fun formatLink(text: String, href: String): String + open fun formatLink(link: FormatLink): String = formatLink(formatText(link.text), link.href) + abstract fun formatStrong(text: String): String + abstract fun formatStrikethrough(text: String): String + abstract fun formatEmphasis(text: String): String + abstract fun formatCode(code: String): String + abstract fun formatUnorderedList(text: String): String + abstract fun formatOrderedList(text: String): String + abstract fun formatListItem(text: String, kind: ListKind): String + abstract fun formatBreadcrumbs(items: Iterable<FormatLink>): String + abstract fun formatNonBreakingSpace(): String + open fun formatSoftLineBreak(): String = "" + open fun formatIndentedSoftLineBreak(): String = "" open fun formatText(location: Location, nodes: Iterable<ContentNode>, listKind: ListKind = ListKind.Unordered): String { - return nodes.map { formatText(location, it, listKind) }.join("") + return nodes.map { formatText(location, it, listKind) }.joinToString("") } open fun formatText(location: Location, content: ContentNode, listKind: ListKind = ListKind.Unordered): String { - return StringBuilder { + return StringBuilder().apply { when (content) { is ContentText -> append(formatText(content.text)) is ContentSymbol -> append(formatSymbol(content.text)) is ContentKeyword -> append(formatKeyword(content.text)) is ContentIdentifier -> append(formatIdentifier(content.text, content.kind)) is ContentNonBreakingSpace -> append(formatNonBreakingSpace()) + is ContentSoftLineBreak -> append(formatSoftLineBreak()) + is ContentIndentedSoftLineBreak -> append(formatIndentedSoftLineBreak()) is ContentEntity -> append(formatEntity(content.text)) is ContentStrong -> append(formatStrong(formatText(location, content.children))) is ContentStrikethrough -> append(formatStrikethrough(formatText(location, content.children))) @@ -92,9 +96,9 @@ public abstract class StructuredFormatService(locationService: LocationService, }.toString() } - open public fun link(from: DocumentationNode, to: DocumentationNode): FormatLink = link(from, to, extension) + open fun link(from: DocumentationNode, to: DocumentationNode): FormatLink = link(from, to, extension) - open public fun link(from: DocumentationNode, to: DocumentationNode, extension: String): FormatLink { + open fun link(from: DocumentationNode, to: DocumentationNode, extension: String): FormatLink { return FormatLink(to.name, locationService.relativePathToLocation(from, to)) } @@ -110,41 +114,47 @@ public abstract class StructuredFormatService(locationService: LocationService, val breakdownBySummary = overloads.groupByTo(LinkedHashMap()) { node -> node.content } for ((summary, items) in breakdownBySummary) { - items.forEach { - appendAsSignature(to) { - to.append(formatCode(formatText(location, languageService.render(it)))) - it.appendSourceLink(to) + appendAsOverloadGroup(to) { + items.forEach { + val rendered = languageService.render(it) + appendAsSignature(to, rendered) { + to.append(formatCode(formatText(location, rendered))) + it.appendSourceLink(to) + } + it.appendOverrides(to) + it.appendDeprecation(location, to) } - it.appendOverrides(to) - it.appendDeprecation(location, to) - } - // All items have exactly the same documentation, so we can use any item to render it - val item = items.first() - item.details(DocumentationNode.Kind.OverloadGroupNote).forEach { - to.append(formatText(location, it.content)) + // All items have exactly the same documentation, so we can use any item to render it + val item = items.first() + item.details(DocumentationNode.Kind.OverloadGroupNote).forEach { + to.append(formatText(location, it.content)) + } + to.append(formatText(location, item.content.summary)) + appendDescription(location, to, item) + appendLine(to) + appendLine(to) } - to.append(formatText(location, item.content.summary)) - appendDescription(location, to, item) - appendLine(to) - appendLine(to) } } private fun DocumentationNode.isModuleOrPackage(): Boolean = kind == DocumentationNode.Kind.Module || kind == DocumentationNode.Kind.Package - protected open fun appendAsSignature(to: StringBuilder, block: () -> Unit) { + protected open fun appendAsSignature(to: StringBuilder, node: ContentNode, block: () -> Unit) { + block() + } + + protected open fun appendAsOverloadGroup(to: StringBuilder, block: () -> Unit) { block() } fun appendDescription(location: Location, to: StringBuilder, node: DocumentationNode) { if (node.content.description != ContentEmpty) { - appendHeader(to, ContentTags.Description, 3) appendLine(to, formatText(location, node.content.description)) appendLine(to) } node.content.getSectionsWithSubjects().forEach { - appendSectionWithSubject(it.getKey(), location, it.getValue(), to) + appendSectionWithSubject(it.key, location, it.value, to) } for (section in node.content.sections.filter { it.subjectName == null }) { @@ -221,11 +231,11 @@ public abstract class StructuredFormatService(locationService: LocationService, } } - private fun StructuredFormatService.appendSection(location: Location, caption: String, nodes: List<DocumentationNode>, node: DocumentationNode, to: StringBuilder) { + private fun appendSection(location: Location, caption: String, nodes: List<DocumentationNode>, node: DocumentationNode, to: StringBuilder) { if (nodes.any()) { appendHeader(to, caption, 3) - val children = nodes.sortBy { it.name } + val children = nodes.sortedBy { it.name } val membersMap = children.groupBy { link(node, it) } appendTable(to) { @@ -238,24 +248,7 @@ public abstract class StructuredFormatService(locationService: LocationService, appendTableCell(to) { val breakdownBySummary = members.groupBy { formatText(location, it.summary) } for ((summary, items) in breakdownBySummary) { - val signatureTexts = items map { signature -> - val signatureText = languageService.render(signature, RenderMode.SUMMARY) - if (signatureText is ContentBlock && signatureText.isEmpty()) { - "" - } else { - val signatureAsCode = ContentCode() - signatureAsCode.append(signatureText) - formatText(location, signatureAsCode) - } - } - signatureTexts.subList(0, signatureTexts.size()-1).forEach { - appendAsSignature(to) { - appendLine(to, it) - } - } - appendAsSignature(to) { - to.append(signatureTexts.last()) - } + appendSummarySignatures(items, location, to) if (!summary.isEmpty()) { to.append(summary) } @@ -268,6 +261,35 @@ public abstract class StructuredFormatService(locationService: LocationService, } } + private fun appendSummarySignatures(items: List<DocumentationNode>, location: Location, to: StringBuilder) { + val summarySignature = languageService.summarizeSignatures(items) + if (summarySignature != null) { + appendAsSignature(to, summarySignature) { + appendLine(to, summarySignature.signatureToText(location)) + } + return + } + val renderedSignatures = items.map { languageService.render(it, RenderMode.SUMMARY) } + renderedSignatures.subList(0, renderedSignatures.size - 1).forEach { + appendAsSignature(to, it) { + appendLine(to, it.signatureToText(location)) + } + } + appendAsSignature(to, renderedSignatures.last()) { + to.append(renderedSignatures.last().signatureToText(location)) + } + } + + private fun ContentNode.signatureToText(location: Location): String { + return if (this is ContentBlock && this.isEmpty()) { + "" + } else { + val signatureAsCode = ContentCode() + signatureAsCode.append(this) + formatText(location, signatureAsCode) + } + } + override fun appendNodes(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) { val breakdownByLocation = nodes.groupBy { node -> formatBreadcrumbs(node.path.filterNot { it.name.isEmpty() }.map { link(node, it) }) @@ -295,12 +317,14 @@ public abstract class StructuredFormatService(locationService: LocationService, DocumentationNode.Kind.AnnotationClass) }, node, to) appendSection(location, "Extensions for External Classes", node.members(DocumentationNode.Kind.ExternalClass), node, to) + appendSection(location, "Enum Values", node.members(DocumentationNode.Kind.EnumItem), node, to) appendSection(location, "Constructors", node.members(DocumentationNode.Kind.Constructor), node, to) appendSection(location, "Properties", node.members(DocumentationNode.Kind.Property), node, to) + appendSection(location, "Inherited Properties", node.inheritedMembers(DocumentationNode.Kind.Property), node, to) appendSection(location, "Functions", node.members(DocumentationNode.Kind.Function), node, to) + appendSection(location, "Inherited Functions", node.inheritedMembers(DocumentationNode.Kind.Function), node, to) appendSection(location, "Companion Object Properties", node.members(DocumentationNode.Kind.CompanionObjectProperty), node, to) appendSection(location, "Companion Object Functions", node.members(DocumentationNode.Kind.CompanionObjectFunction), node, to) - appendSection(location, "Enum Values", node.members(DocumentationNode.Kind.EnumItem), node, to) appendSection(location, "Other members", node.members.filter { it.kind !in setOf( DocumentationNode.Kind.Class, @@ -318,14 +342,32 @@ public abstract class StructuredFormatService(locationService: LocationService, DocumentationNode.Kind.EnumItem ) }, node, to) - appendSection(location, "Extension Properties", node.extensions.filter { it.kind == DocumentationNode.Kind.Property }, node, to) - appendSection(location, "Extension Functions", node.extensions.filter { it.kind == DocumentationNode.Kind.Function }, node, to) - appendSection(location, "Companion Object Extension Properties", node.extensions.filter { it.kind == DocumentationNode.Kind.CompanionObjectProperty }, node, to) - appendSection(location, "Companion Object Extension Functions", node.extensions.filter { it.kind == DocumentationNode.Kind.CompanionObjectFunction }, node, to) + + val allExtensions = collectAllExtensions(node) + appendSection(location, "Extension Properties", allExtensions.filter { it.kind == DocumentationNode.Kind.Property }, node, to) + appendSection(location, "Extension Functions", allExtensions.filter { it.kind == DocumentationNode.Kind.Function }, node, to) + appendSection(location, "Companion Object Extension Properties", allExtensions.filter { it.kind == DocumentationNode.Kind.CompanionObjectProperty }, node, to) + appendSection(location, "Companion Object Extension Functions", allExtensions.filter { it.kind == DocumentationNode.Kind.CompanionObjectFunction }, node, to) appendSection(location, "Inheritors", node.inheritors.filter { it.kind != DocumentationNode.Kind.EnumItem }, node, to) appendSection(location, "Links", node.links, node, to) } } + + private fun collectAllExtensions(node: DocumentationNode): Collection<DocumentationNode> { + val result = LinkedHashSet<DocumentationNode>() + val visited = hashSetOf<DocumentationNode>() + + fun collect(node: DocumentationNode) { + if (!visited.add(node)) return + result.addAll(node.extensions) + node.references(DocumentationReference.Kind.Superclass).forEach { collect(it.to) } + } + + collect(node) + + return result + + } }
\ No newline at end of file |
