diff --git a/java/java-tests/testData/codeInsight/javadocIG/documentationForJdkClassWithReferencesToClassesFromJavaLang.html b/java/java-tests/testData/codeInsight/javadocIG/documentationForJdkClassWithReferencesToClassesFromJavaLang.html index da70d09ea0f8..a30470ade126 100644 --- a/java/java-tests/testData/codeInsight/javadocIG/documentationForJdkClassWithReferencesToClassesFromJavaLang.html +++ b/java/java-tests/testData/codeInsight/javadocIG/documentationForJdkClassWithReferencesToClassesFromJavaLang.html @@ -5,4 +5,4 @@ at least one element e such that (o==null ? e==null : o.equals(e)). -

Overrides:

contains in interface Collection

Params:

o – element whose presence in this list is to be tested

Returns:

true if this list contains the specified element

Throws:

ClassCastException – if the type of the specified element is incompatible with this list (optional)

NullPointerException – if the specified element is null and this list does not permit null elements (optional)

 < java 1.7 >
\ No newline at end of file +

Overrides:

contains in interface Collection

Params:

o – element whose presence in this list is to be tested

Returns:

true if this list contains the specified element

Throws:

ClassCastException – if the type of the specified element is incompatible with this list (optional)

NullPointerException – if the specified element is null and this list does not permit null elements (optional)

 < java 1.7 >
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/javadocIG/documentationForUncheckedExceptionsInSupers.html b/java/java-tests/testData/codeInsight/javadocIG/documentationForUncheckedExceptionsInSupers.html index 6b6a9928942c..3f34edf1a2c9 100644 --- a/java/java-tests/testData/codeInsight/javadocIG/documentationForUncheckedExceptionsInSupers.html +++ b/java/java-tests/testData/codeInsight/javadocIG/documentationForUncheckedExceptionsInSupers.html @@ -6,4 +6,4 @@ contains at least one element e such that (o==null ? e==null : o.equals(e)). -

Overrides:

contains in interface Collection
contains in interface I

Params:

o – element whose presence in this collection is to be tested

Returns:

true if this collection contains the specified element

Throws:

NullPointerException – before if the specified element is null and this collection does not permit null elements (optional) after

IOException

\ No newline at end of file +

Overrides:

contains in interface Collection
contains in interface I

Params:

o – element whose presence in this collection is to be tested

Returns:

true if this collection contains the specified element

Throws:

NullPointerException – before if the specified element is null and this collection does not permit null elements (optional) after

IOException

\ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/documentation/render/JavaDocRenderTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/documentation/render/JavaDocRenderTest.java index 2146665c85af..f086be94b85f 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/documentation/render/JavaDocRenderTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/documentation/render/JavaDocRenderTest.java @@ -109,8 +109,8 @@ public class JavaDocRenderTest extends AbstractEditorTest { * @author bar */ class C {}""", true); - verifyItem(15, 52,"

" + - "

Author:

foo, bar

"); + verifyItem(15, 52,"" + + "

Author:

foo, bar

"); } public void testDocumentStart() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationHtmlUtil.kt b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationHtmlUtil.kt index 6d7d352ac081..2e45f6fa4776 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationHtmlUtil.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationHtmlUtil.kt @@ -7,11 +7,14 @@ import com.intellij.openapi.module.UnknownModuleType import com.intellij.ui.ColorUtil import com.intellij.ui.components.JBHtmlPaneStyleConfiguration import com.intellij.ui.scale.JBUIScale.scale +import com.intellij.util.SmartList import com.intellij.util.ui.JBUI import com.intellij.util.ui.StyleSheetUtil import com.intellij.util.ui.UIUtil import org.intellij.lang.annotations.Language import org.jetbrains.annotations.ApiStatus +import org.jsoup.nodes.* +import java.util.* import java.util.function.Function import javax.swing.Icon import javax.swing.text.html.StyleSheet @@ -98,4 +101,49 @@ object DocumentationHtmlUtil { """.trimIndent() return StyleSheetUtil.loadStyleSheet(result) } + + @JvmStatic + internal fun addExternalLinkIcons(document: Document) { + document.select("a").forEach { a -> + if (a.attribute("href")?.value?.startsWith("http") == true) { + Element("icon").attr("src", "AllIcons.Ide.External_link_arrow") + .appendTo(a) + } + } + } + + @JvmStatic + internal fun addParagraphsIfNeeded(document: Document, selector: String) { + document.select(selector).forEach { element -> + var child = element.firstChild() + val toWrap = SmartList() + while (child != null && !isBlockElement(child)) { + if (child !is Comment) { + toWrap.add(child); + } + child = child.nextSibling(); + } + if (!toWrap.isEmpty() && !toWrap.all { n -> n is TextNode && n.isBlank }) { + val para = Element("p"); + para.insertChildren(0, toWrap); + element.insertChildren(0, para); + } + } + } + + private fun isBlockElement(node: Node): Boolean { + if (node is Element) { + val tagName = node.tagName().lowercase(Locale.US) + return tagName == "p" + || tagName == "div" + || tagName == "pre" + || tagName == "table" + || tagName == "blockquote" + || tagName == "ol" + || tagName == "ul" + || tagName == "dl" + || (tagName.startsWith("h") && tagName.length == 2 && Character.isDigit(tagName[1])) + } + return false + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java index c82553351629..d67ec46c0dd8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java @@ -84,10 +84,7 @@ import org.jetbrains.annotations.*; import org.jetbrains.concurrency.CancellablePromise; import org.jetbrains.concurrency.Promises; import org.jsoup.Jsoup; -import org.jsoup.nodes.Comment; import org.jsoup.nodes.Element; -import org.jsoup.nodes.Node; -import org.jsoup.nodes.TextNode; import javax.swing.*; import java.awt.*; @@ -107,7 +104,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.regex.Pattern; import static com.intellij.lang.documentation.DocumentationMarkup.*; @@ -1948,14 +1944,14 @@ public class DocumentationManager extends DockablePopupManager { var nextSibling = div.nextElementSibling(); if (nextSibling == null) { return; } if (nextSibling.hasClass(CLASS_DEFINITION) - || nextSibling.hasClass(CLASS_CONTENT) + || (nextSibling.hasClass(CLASS_CONTENT) && !div.hasClass(CLASS_SECTIONS)) || (div.hasClass(CLASS_DEFINITION) && ( nextSibling.hasClass(CLASS_SECTIONS) @@ -1966,44 +1962,11 @@ public class DocumentationManager extends DockablePopupManager { - var child = div.firstChild(); - var toWrap = new SmartList(); - while (child != null && !isBlockElement(child)) { - if (!(child instanceof Comment)) { - toWrap.add(child); - } - child = child.nextSibling(); - } - if (!toWrap.isEmpty() - && !ContainerUtil.all(toWrap, n -> n instanceof TextNode textNode && textNode.isBlank()) - ) { - var para = new Element("p"); - para.insertChildren(0, toWrap); - div.insertChildren(0, para); - } - } - ); - + DocumentationHtmlUtil.addParagraphsIfNeeded$intellij_platform_lang_impl( + document, "." + CLASS_CONTENT + ", table." + CLASS_SECTIONS + " td[valign=top]"); + DocumentationHtmlUtil.addExternalLinkIcons$intellij_platform_lang_impl(document); document.outputSettings().prettyPrint(false); - return addExternalLinksIcon(document.html()); - } - - private static boolean isBlockElement(Node node) { - if (node instanceof Element element) { - var tagName = element.tagName(); - return tagName.equals("p") - || tagName.equals("div") - || tagName.equals("pre") - || tagName.equals("table") - || tagName.equals("blockquote") - || tagName.equals("ol") - || tagName.equals("ul") - || tagName.equals("dl") - || (tagName.startsWith("h") && tagName.length() == 2 && Character.isDigit(tagName.charAt(1))); - } - return false; + return document.html(); } private static @NlsSafe @NotNull String replaceIgnoreQuotesType(@NotNull String text, @@ -2136,11 +2099,4 @@ public class DocumentationManager extends DockablePopupManager]*>)([^>]*)()"); - private static final @NlsSafe String EXTERNAL_LINK_REPLACEMENT = "$1$2$3"; - - @Contract(pure = true) - public static String addExternalLinksIcon(String text) { - return EXTERNAL_LINK_PATTERN.matcher(text).replaceAll(EXTERNAL_LINK_REPLACEMENT); - } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/render/DocRenderPassFactory.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/render/DocRenderPassFactory.java index 2a1efa8c0d16..46f071a737b7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/render/DocRenderPassFactory.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/render/DocRenderPassFactory.java @@ -3,7 +3,7 @@ package com.intellij.codeInsight.documentation.render; import com.intellij.codeHighlighting.*; import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.codeInsight.documentation.DocumentationManager; +import com.intellij.codeInsight.documentation.DocumentationHtmlUtil; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.progress.ProgressIndicator; @@ -20,12 +20,14 @@ import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jsoup.Jsoup; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import static com.intellij.codeInsight.documentation.render.InlineDocumentationImplKt.inlineDocumentationItems; +import static com.intellij.lang.documentation.DocumentationMarkup.CLASS_SECTIONS; public final class DocRenderPassFactory implements TextEditorHighlightingPassFactoryRegistrar, TextEditorHighlightingPassFactory, DumbAware { private static final Key MODIFICATION_STAMP = Key.create("doc.render.modification.stamp"); @@ -113,7 +115,12 @@ public final class DocRenderPassFactory implements TextEditorHighlightingPassFac } private static String preProcess(String text) { - return DocumentationManager.addExternalLinksIcon(text); + var document = Jsoup.parse(text); + DocumentationHtmlUtil.addParagraphsIfNeeded$intellij_platform_lang_impl( + document, "table." + CLASS_SECTIONS + " td[valign=top]"); + DocumentationHtmlUtil.addExternalLinkIcons$intellij_platform_lang_impl(document); + document.outputSettings().prettyPrint(false); + return document.html(); } public static void applyItemsToRender(@NotNull Editor editor,