From a9538f2f49e15b04340215d8d670557ced6f132d Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 27 Feb 2015 16:40:08 +0100 Subject: use JSoup to convert HTML markup in javadoc to content tree --- .idea/libraries/jsoup.xml | 11 +++++ dokka.iml | 1 + lib/jsoup-1.8.1-sources.jar | Bin 0 -> 124882 bytes lib/jsoup-1.8.1.jar | Bin 0 -> 300844 bytes src/Formats/MarkdownFormatService.kt | 4 +- src/Java/JavaDocumentationBuilder.kt | 80 +++++++++++++++++++++++++++------- test/data/format/javaDeprecated.html | 2 +- test/data/format/javaLinkTag.html | 3 +- test/data/format/javadocHtml.java | 16 +++++++ test/data/format/javadocHtml.md | 20 +++++++++ test/src/format/MarkdownFormatTest.kt | 6 +++ 11 files changed, 121 insertions(+), 22 deletions(-) create mode 100644 .idea/libraries/jsoup.xml create mode 100644 lib/jsoup-1.8.1-sources.jar create mode 100644 lib/jsoup-1.8.1.jar create mode 100644 test/data/format/javadocHtml.java create mode 100644 test/data/format/javadocHtml.md diff --git a/.idea/libraries/jsoup.xml b/.idea/libraries/jsoup.xml new file mode 100644 index 00000000..9e4803f4 --- /dev/null +++ b/.idea/libraries/jsoup.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/dokka.iml b/dokka.iml index b0393b73..6808178d 100644 --- a/dokka.iml +++ b/dokka.iml @@ -14,5 +14,6 @@ + \ No newline at end of file diff --git a/lib/jsoup-1.8.1-sources.jar b/lib/jsoup-1.8.1-sources.jar new file mode 100644 index 00000000..3b7aea4a Binary files /dev/null and b/lib/jsoup-1.8.1-sources.jar differ diff --git a/lib/jsoup-1.8.1.jar b/lib/jsoup-1.8.1.jar new file mode 100644 index 00000000..ae717d45 Binary files /dev/null and b/lib/jsoup-1.8.1.jar differ diff --git a/src/Formats/MarkdownFormatService.kt b/src/Formats/MarkdownFormatService.kt index cc7d7170..8809fa96 100644 --- a/src/Formats/MarkdownFormatService.kt +++ b/src/Formats/MarkdownFormatService.kt @@ -27,9 +27,7 @@ public open class MarkdownFormatService(locationService: LocationService, return "`$code`" } - override public fun formatList(text: String): String { - return text - } + override public fun formatList(text: String): String = text + "\n" override fun formatListItem(text: String): String { return "* $text" diff --git a/src/Java/JavaDocumentationBuilder.kt b/src/Java/JavaDocumentationBuilder.kt index 8183df8f..8a5d8fb9 100644 --- a/src/Java/JavaDocumentationBuilder.kt +++ b/src/Java/JavaDocumentationBuilder.kt @@ -6,6 +6,10 @@ import com.intellij.psi.javadoc.PsiDocTag import com.intellij.psi.javadoc.PsiDocTagValue import com.intellij.psi.javadoc.PsiInlineDocTag import org.jetbrains.dokka.DocumentationNode.Kind +import org.jsoup.Jsoup +import org.jsoup.nodes.Element +import org.jsoup.nodes.Node +import org.jsoup.nodes.TextNode public class JavaDocumentationBuilder(private val options: DocumentationOptions, private val refGraph: NodeReferenceGraph) { @@ -46,21 +50,65 @@ public class JavaDocumentationBuilder(private val options: DocumentationOptions, } private fun ContentBlock.convertJavadocElements(elements: Iterable) { + val htmlBuilder = StringBuilder() elements.forEach { if (it is PsiInlineDocTag) { - append(convertInlineDocTag(it)) + htmlBuilder.append(convertInlineDocTag(it)) } else { - val text = if (isEmpty()) it.getText().trimLeading() else it.getText() - append(ContentText(text)) + htmlBuilder.append(it.getText()) } } + val doc = Jsoup.parse(htmlBuilder.toString().trimLeading()) + doc.body().childNodes().forEach { + convertHtmlNode(it) + } + } + + private fun ContentBlock.convertHtmlNode(node: Node) { + if (node is TextNode) { + append(ContentText(node.text())) + } else if (node is Element) { + val childBlock = createBlock(node) + node.childNodes().forEach { + childBlock.convertHtmlNode(it) + } + append(childBlock) + } + } + + private fun createBlock(element: Element): ContentBlock = when(element.tagName()) { + "p" -> ContentParagraph() + "b", "strong" -> ContentStrong() + "i", "em" -> ContentEmphasis() + "s", "del" -> ContentStrikethrough() + "code" -> ContentCode() + "pre" -> ContentBlockCode() + "ul" -> ContentList() + "li" -> ContentListItem() + "a" -> createLink(element) + else -> ContentBlock() + } + + private fun createLink(element: Element): ContentBlock { + val href = element.attr("href") + if (href != null) { + if (href.startsWith("##")) { + val signature = href.substring(2) + return ContentNodeLazyLink(signature, {() -> refGraph.lookup(signature)}) + } else { + return ContentExternalLink(href) + } + } else { + return ContentBlock() + } } private fun MutableContent.convertSeeTag(tag: PsiDocTag) { val seeSection = findSectionByTag("See Also") ?: addSection("See Also", null) - val linkNode = resolveLink(tag.getValueElement()) + val linkSignature = resolveLink(tag.getValueElement()) val text = ContentText(tag.getValueElement()!!.getText()) - if (linkNode != null) { + if (linkSignature != null) { + val linkNode = ContentNodeLazyLink(tag.getValueElement()!!.getText(), {() -> refGraph.lookup(linkSignature)}) linkNode.append(text) seeSection.append(linkNode) } else { @@ -70,23 +118,23 @@ public class JavaDocumentationBuilder(private val options: DocumentationOptions, private fun convertInlineDocTag(tag: PsiInlineDocTag) = when (tag.getName()) { "link", "linkplain" -> { - val link = resolveLink(tag.getValueElement()) - if (link != null) { - link.append(ContentText(tag.getValueElement()!!.getText())) - link + val valueElement = tag.getValueElement() + val linkSignature = resolveLink(valueElement) + if (linkSignature != null) { + val link = "${valueElement!!.getText().htmlEscape()}" + if (tag.getName() == "link") "$link" else link + } + else { + valueElement!!.getText() } - else ContentText(tag.getValueElement()!!.getText()) } - else -> ContentText(tag.getText()) + else -> tag.getText() } - private fun resolveLink(valueElement: PsiDocTagValue?): ContentBlock? { + private fun resolveLink(valueElement: PsiDocTagValue?): String? { val target = valueElement?.getReference()?.resolve() if (target != null) { - val signature = getSignature(target) - if (signature != null) { - return ContentNodeLazyLink(valueElement!!.getText(), {() -> refGraph.lookup(signature)}) - } + return getSignature(target) } return null } diff --git a/test/data/format/javaDeprecated.html b/test/data/format/javaDeprecated.html index ca818bb7..f9376bf5 100644 --- a/test/data/format/javaDeprecated.html +++ b/test/data/format/javaDeprecated.html @@ -7,7 +7,7 @@

foo

public open fun foo(): Unit
-Deprecated: use#bar instead

+Deprecated: use#bar instead



diff --git a/test/data/format/javaLinkTag.html b/test/data/format/javaLinkTag.html index d6ced4ce..af63710d 100644 --- a/test/data/format/javaLinkTag.html +++ b/test/data/format/javaLinkTag.html @@ -7,8 +7,7 @@

Foo

open class Foo
-

Call #bar() to do the job. -

+

Call #bar() to do the job.



Functions

diff --git a/test/data/format/javadocHtml.java b/test/data/format/javadocHtml.java new file mode 100644 index 00000000..bcb2cf91 --- /dev/null +++ b/test/data/format/javadocHtml.java @@ -0,0 +1,16 @@ +package test; + +/** + * Bold + * Strong + * Italic + * Emphasized + *

Paragraph

+ * Strikethrough + * Deleted + * Code + *
Block code
+ *
  • List Item
+ */ +public class C { +} diff --git a/test/data/format/javadocHtml.md b/test/data/format/javadocHtml.md new file mode 100644 index 00000000..303b102c --- /dev/null +++ b/test/data/format/javadocHtml.md @@ -0,0 +1,20 @@ +[test](test/index) / [test](test/test/index) / [C](test/test/-c) + + +# C + +`public open class C` + +**Bold** **Strong** *Italic* *Emphasized* +Paragraph + + ~~Strikethrough~~ ~~Deleted~~ `Code` +``` +Block code +``` + + * List Item + + + + diff --git a/test/src/format/MarkdownFormatTest.kt b/test/src/format/MarkdownFormatTest.kt index 4b207b75..7253ddb4 100644 --- a/test/src/format/MarkdownFormatTest.kt +++ b/test/src/format/MarkdownFormatTest.kt @@ -118,4 +118,10 @@ public class MarkdownFormatTest { markdownService.appendNodes(tempLocation, output, model.members.single().members) } } + + Test fun javadocHtml() { + verifyOutput("test/data/format/javadocHtml.java", ".md") { model, output -> + markdownService.appendNodes(tempLocation, output, model.members.single().members) + } + } } -- cgit