blob: 3732547c8d841b04ad5a5f286d2e24a61e41d8a0 [file] [log] [blame]
package org.jetbrains.dokka
interface ContentNode {
val textLength: Int
}
object ContentEmpty : ContentNode {
override val textLength: Int get() = 0
}
open class ContentBlock() : ContentNode {
open val children = arrayListOf<ContentNode>()
fun append(node: ContentNode) {
children.add(node)
}
fun isEmpty() = children.isEmpty()
override fun equals(other: Any?): Boolean =
other is ContentBlock && javaClass == other.javaClass && children == other.children
override fun hashCode(): Int =
children.hashCode()
override val textLength: Int
get() = children.sumBy { it.textLength }
}
class NodeRenderContent(
val node: DocumentationNode,
val mode: LanguageService.RenderMode
): ContentNode {
override val textLength: Int
get() = 0 //TODO: Clarify?
}
class LazyContentBlock(private val fillChildren: (ContentBlock) -> Unit) : ContentBlock() {
private var computed = false
override val children: ArrayList<ContentNode>
get() {
if (!computed) {
computed = true
fillChildren(this)
}
return super.children
}
override fun equals(other: Any?): Boolean {
return other is LazyContentBlock && other.fillChildren == fillChildren && super.equals(other)
}
override fun hashCode(): Int {
return super.hashCode() + 31 * fillChildren.hashCode()
}
}
enum class IdentifierKind {
TypeName,
ParameterName,
AnnotationName,
SummarizedTypeName,
Other
}
data class ContentText(val text: String) : ContentNode {
override val textLength: Int
get() = text.length
}
data class ContentKeyword(val text: String) : ContentNode {
override val textLength: Int
get() = text.length
}
data class ContentIdentifier(val text: String,
val kind: IdentifierKind = IdentifierKind.Other,
val signature: String? = null) : ContentNode {
override val textLength: Int
get() = text.length
}
data class ContentSymbol(val text: String) : ContentNode {
override val textLength: Int
get() = text.length
}
data class ContentEntity(val text: String) : ContentNode {
override val textLength: Int
get() = text.length
}
object ContentNonBreakingSpace: ContentNode {
override val textLength: Int
get() = 1
}
object ContentSoftLineBreak: ContentNode {
override val textLength: Int
get() = 0
}
object ContentIndentedSoftLineBreak: ContentNode {
override val textLength: Int
get() = 0
}
class ScriptBlock(val type: String, val src: String) : ContentBlock()
class ContentParagraph() : ContentBlock()
class ContentEmphasis() : ContentBlock()
class ContentStrong() : ContentBlock()
class ContentStrikethrough() : ContentBlock()
class ContentCode() : ContentBlock()
class ContentDescriptionList() : ContentBlock()
class ContentDescriptionTerm() : ContentBlock()
class ContentDescriptionDefinition() : ContentBlock()
class ContentTable() : ContentBlock()
class ContentTableBody() : ContentBlock()
class ContentTableRow() : ContentBlock()
class ContentTableHeader(val colspan: String? = null, val rowspan: String? = null) : ContentBlock()
class ContentTableCell(val colspan: String? = null, val rowspan: String? = null) : ContentBlock()
class ContentSpecialReference() : ContentBlock()
open class ContentBlockCode(val language: String = "") : ContentBlock()
class ContentBlockSampleCode(language: String = "kotlin", val importsBlock: ContentBlockCode = ContentBlockCode(language)) : ContentBlockCode(language)
abstract class ContentNodeLink() : ContentBlock() {
abstract val node: DocumentationNode?
}
object ContentHardLineBreak : ContentNode {
override val textLength: Int
get() = 0
}
class ContentNodeDirectLink(override val node: DocumentationNode): ContentNodeLink() {
override fun equals(other: Any?): Boolean =
super.equals(other) && other is ContentNodeDirectLink && node.name == other.node.name
override fun hashCode(): Int =
children.hashCode() * 31 + node.name.hashCode()
}
class ContentNodeLazyLink(val linkText: String, val lazyNode: () -> DocumentationNode?): ContentNodeLink() {
override val node: DocumentationNode? get() = lazyNode()
override fun equals(other: Any?): Boolean =
super.equals(other) && other is ContentNodeLazyLink && linkText == other.linkText
override fun hashCode(): Int =
children.hashCode() * 31 + linkText.hashCode()
}
class ContentExternalLink(val href : String) : ContentBlock() {
override fun equals(other: Any?): Boolean =
super.equals(other) && other is ContentExternalLink && href == other.href
override fun hashCode(): Int =
children.hashCode() * 31 + href.hashCode()
}
data class ContentBookmark(val name: String): ContentBlock()
data class ContentLocalLink(val href: String) : ContentBlock()
class ContentUnorderedList() : ContentBlock()
class ContentOrderedList() : ContentBlock()
class ContentListItem() : ContentBlock()
class ContentHeading(val level: Int) : ContentBlock()
class ContentSection(val tag: String, val subjectName: String?) : ContentBlock() {
override fun equals(other: Any?): Boolean =
super.equals(other) && other is ContentSection && tag == other.tag && subjectName == other.subjectName
override fun hashCode(): Int =
children.hashCode() * 31 * 31 + tag.hashCode() * 31 + (subjectName?.hashCode() ?: 0)
}
object ContentTags {
val Description = "Description"
val SeeAlso = "See Also"
val Return = "Return"
val Exceptions = "Exceptions"
val Parameters = "Parameters"
}
fun content(body: ContentBlock.() -> Unit): ContentBlock {
val block = ContentBlock()
block.body()
return block
}
fun ContentBlock.text(value: String) = append(ContentText(value))
fun ContentBlock.keyword(value: String) = append(ContentKeyword(value))
fun ContentBlock.symbol(value: String) = append(ContentSymbol(value))
fun ContentBlock.identifier(value: String, kind: IdentifierKind = IdentifierKind.Other, signature: String? = null) {
append(ContentIdentifier(value, kind, signature))
}
fun ContentBlock.nbsp() = append(ContentNonBreakingSpace)
fun ContentBlock.softLineBreak() = append(ContentSoftLineBreak)
fun ContentBlock.indentedSoftLineBreak() = append(ContentIndentedSoftLineBreak)
fun ContentBlock.hardLineBreak() = append(ContentHardLineBreak)
fun ContentBlock.strong(body: ContentBlock.() -> Unit) {
val strong = ContentStrong()
strong.body()
append(strong)
}
fun ContentBlock.code(body: ContentBlock.() -> Unit) {
val code = ContentCode()
code.body()
append(code)
}
fun ContentBlock.link(to: DocumentationNode, body: ContentBlock.() -> Unit) {
val block = if (to.kind == NodeKind.ExternalLink)
ContentExternalLink(to.name)
else
ContentNodeDirectLink(to)
block.body()
append(block)
}
open class Content(): ContentBlock() {
open val sections: List<ContentSection> get() = emptyList()
open val summary: ContentNode get() = ContentEmpty
open val description: ContentNode get() = ContentEmpty
fun findSectionByTag(tag: String): ContentSection? =
sections.firstOrNull { tag.equals(it.tag, ignoreCase = true) }
companion object {
val Empty = Content()
fun of(vararg child: ContentNode): Content {
val result = MutableContent()
child.forEach { result.append(it) }
return result
}
}
}
open class MutableContent() : Content() {
private val sectionList = arrayListOf<ContentSection>()
override val sections: List<ContentSection>
get() = sectionList
fun addSection(tag: String?, subjectName: String?): ContentSection {
val section = ContentSection(tag ?: "", subjectName)
sectionList.add(section)
return section
}
override val summary: ContentNode get() = children.firstOrNull() ?: ContentEmpty
override val description: ContentNode by lazy {
val descriptionNodes = children.drop(1)
if (descriptionNodes.isEmpty()) {
ContentEmpty
} else {
val result = ContentSection(ContentTags.Description, null)
result.children.addAll(descriptionNodes)
result
}
}
override fun equals(other: Any?): Boolean {
if (other !is Content)
return false
return sections == other.sections && children == other.children
}
override fun hashCode(): Int {
return sections.map { it.hashCode() }.sum()
}
override fun toString(): String {
if (sections.isEmpty())
return "<empty>"
return (listOf(summary, description) + sections).joinToString()
}
}
fun javadocSectionDisplayName(sectionName: String?): String? =
when(sectionName) {
"param" -> "Parameters"
"throws", "exception" -> ContentTags.Exceptions
else -> sectionName?.capitalize()
}