aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main
diff options
context:
space:
mode:
authorAndrzej Ratajczak <32793002+BarkingBad@users.noreply.github.com>2020-10-08 20:25:06 +0200
committerGitHub <noreply@github.com>2020-10-08 20:25:06 +0200
commit75f572b271c5959bd6fab0b51cef792fa403ea83 (patch)
tree5a3fb52df075268d8ff642cf52e6b342debcee1f /plugins/base/src/main
parent58a76b4031953355e38cb534ab02c159f7cfb726 (diff)
downloaddokka-75f572b271c5959bd6fab0b51cef792fa403ea83.tar.gz
dokka-75f572b271c5959bd6fab0b51cef792fa403ea83.tar.bz2
dokka-75f572b271c5959bd6fab0b51cef792fa403ea83.zip
Fix multiline links in javadoc and wrong linebreaking of <pre> bodies (#1518)
* Fix multiline links in javadoc * Fix wrong linebreaking of <pre> bodies * Use included static values for external links Co-authored-by: Marcin Aman <marcin.aman@gmail.com>
Diffstat (limited to 'plugins/base/src/main')
-rw-r--r--plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt73
1 files changed, 45 insertions, 28 deletions
diff --git a/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt b/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt
index 905d1898..9ef5ea38 100644
--- a/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt
+++ b/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt
@@ -41,7 +41,7 @@ class JavadocParser(
)
"throws" -> Throws(wrapTagIfNecessary(convertJavadocElements(tag.contentElements())), tag.text)
"return" -> Return(wrapTagIfNecessary(convertJavadocElements(tag.contentElements())))
- "author" -> Author(wrapTagIfNecessary(convertJavadocElements(tag.contentElements())))
+ "author" -> Author(wrapTagIfNecessary(convertJavadocElements(tag.authorContentElements()))) // Workaround: PSI returns first word after @author tag as a `DOC_TAG_VALUE_ELEMENT`, then the rest as a `DOC_COMMENT_DATA`, so for `Name Surname` we get them parted
"see" -> getSeeTagElementContent(tag).let {
See(
wrapTagIfNecessary(it.first),
@@ -140,8 +140,7 @@ class JavadocParser(
}
private fun PsiDocComment.getDescription(): Description? {
- val nonEmptyDescriptionElements = descriptionElements.filter { it.text.isNotBlank() }
- return convertJavadocElements(nonEmptyDescriptionElements).takeIf { it.isNotEmpty() }?.let {
+ return convertJavadocElements(descriptionElements.asIterable()).takeIf { it.isNotEmpty() }?.let {
Description(wrapTagIfNecessary(it))
}
}
@@ -154,30 +153,29 @@ class JavadocParser(
is PsiInlineDocTag -> convertInlineDocTag(this)
is PsiDocParamRef -> toDocumentationLinkString()
is PsiDocTagValue,
- is LeafPsiElement -> (if ((prevSibling as? PsiDocToken)?.isLeadingAsterisk() == true) text?.drop(1) else text)
- ?.takeUnless { it.isBlank() }
+ is LeafPsiElement -> text.let {
+ if ((prevSibling as? PsiDocToken)?.isLeadingAsterisk() == true) it?.drop(1) else it
+ }.let {
+ if ((nextSibling as? PsiDocToken)?.isLeadingAsterisk() == true) it?.dropLastWhile { it == ' ' } else it
+ }
else -> null
}
private fun PsiElement.toDocumentationLinkString(
- labelElement: PsiElement? = null
- ): String? =
- reference?.resolve()?.let {
- if (it !is PsiParameter) {
- val dri = DRI.from(it)
- driMap[dri.toString()] = dri
- val label = labelElement ?: defaultLabel()
- """<a data-dri=$dri>${label.text}</a>"""
- } else null
+ labelElement: List<PsiElement>? = null
+ ): String =
+ (reference?.resolve()?.takeIf { it !is PsiParameter }?.let {
+ val dri = DRI.from(it)
+ driMap[dri.toString()] = dri
+ Pair(labelElement ?: listOf(defaultLabel()), dri.toString())
+ } ?: Pair(listOf(defaultLabel()), UNRESOLVED_PSI_ELEMENT)).let { (label, dri) ->
+ """<a data-dri=$dri>${label.joinToString(" ") { it.text }}</a>"""
}
private fun convertInlineDocTag(tag: PsiInlineDocTag) = when (tag.name) {
- "link", "linkplain" -> {
- tag.referenceElement()?.toDocumentationLinkString(tag.dataElements.firstIsInstanceOrNull<PsiDocToken>())
- }
- "code", "literal" -> {
- "<code data-inline>${tag.text}</code>"
- }
+ "link", "linkplain" -> tag.referenceElement()
+ ?.toDocumentationLinkString(tag.dataElements.filterIsInstance<PsiDocToken>())
+ "code", "literal" -> "<code data-inline>${tag.text}</code>"
"index" -> "<index>${tag.children.filterIsInstance<PsiDocTagValue>().joinToString { it.text }}</index>"
else -> tag.text
}
@@ -190,12 +188,14 @@ class JavadocParser(
A(children, params = mapOf("href" to element.attr("href")))
element.hasAttr("data-dri") && driMap.containsKey(element.attr("data-dri")) ->
DocumentationLink(driMap[element.attr("data-dri")]!!, children)
- else -> Text(children = children)
+ else -> Text(body = children.filterIsInstance<Text>().joinToString { it.body })
}
}
private fun createBlock(element: Element, insidePre: Boolean = false): DocTag? {
- val children = element.childNodes().mapNotNull { convertHtmlNode(it, insidePre = insidePre || element.tagName() == "pre") }
+ val children = element.childNodes()
+ .mapNotNull { convertHtmlNode(it, insidePre = insidePre || element.tagName() == "pre") }
+
fun ifChildrenPresent(operation: () -> DocTag): DocTag? {
return if (children.isNotEmpty()) operation() else null
}
@@ -218,20 +218,33 @@ class JavadocParser(
}
private fun convertHtmlNode(node: Node, insidePre: Boolean = false): DocTag? = when (node) {
- is TextNode -> (if (insidePre) node.wholeText else node.text().takeIf { it.isNotBlank() })?.let { Text(body = it) }
+ is TextNode -> (if (insidePre) node.wholeText else node.text()
+ .takeIf { it.isNotBlank() })?.let { Text(body = it) }
is Element -> createBlock(node)
else -> null
}
override fun invoke(elements: Iterable<PsiElement>, asParagraph: Boolean): List<DocTag> =
- Jsoup.parseBodyFragment(elements.mapNotNull { it.stringify() }.joinToString("\n", prefix = if (asParagraph) "<p>" else ""))
- .body().childNodes().mapNotNull { convertHtmlNode(it) }
+ Jsoup.parseBodyFragment(elements.mapNotNull { it.stringify() }.dropWhile { it.isBlank() }
+ .dropLastWhile { it.isBlank() }.joinToString(
+ "",
+ prefix = if (asParagraph) "<p>" else "",
+ postfix = if (asParagraph) "</p>" else ""
+ )
+ ).body().childNodes().mapNotNull { convertHtmlNode(it) }
}
private fun PsiDocTag.contentElements(): List<PsiElement> =
- dataElements.mapNotNull { it.takeIf { it.text.isNotBlank() } }
+ dataElements.mapNotNull { it.takeIf { it is PsiDocToken && it.text.isNotBlank() } }
+
+ private fun PsiDocTag.authorContentElements(): List<PsiElement> = listOf(
+ dataElements[0],
+ dataElements[0].nextSibling,
+ *dataElements.drop(1).toTypedArray()
+ )
- private fun convertJavadocElements(elements: Iterable<PsiElement>, asParagraph: Boolean = true): List<DocTag> = Parse()(elements, asParagraph)
+ private fun convertJavadocElements(elements: Iterable<PsiElement>, asParagraph: Boolean = true): List<DocTag> =
+ Parse()(elements, asParagraph)
private fun PsiDocToken.isSharpToken() = tokenType.toString() == "DOC_TAG_VALUE_SHARP_TOKEN"
@@ -255,8 +268,12 @@ class JavadocParser(
private fun PsiElement.defaultLabel() = children.firstOrNull {
it is PsiDocToken && it.text.isNotBlank() && !it.isSharpToken()
- } ?: this
+ } ?: this
private fun PsiDocTag.linkElement(): PsiElement? =
valueElement ?: dataElements.firstOrNull { it !is PsiWhiteSpace }
+
+ companion object {
+ private const val UNRESOLVED_PSI_ELEMENT = "UNRESOLVED_PSI_ELEMENT"
+ }
}