mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 21:11:28 +07:00
[documentation] PSI-independent HtmlChunk-based DocumentationManager#decorate
GitOrigin-RevId: 557af2aa1558b83116da6e94e31203a1e72f758c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
0ef4feb02b
commit
52898f753c
@@ -26,4 +26,4 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div><div class='bottom'><icon src='AllIcons.Nodes.PpLibFolder'> myLib</div><div class='bottom'><a href="placeholder">`genericMethod(Class<?>)` on localhost<icon src='AllIcons.Ide.External_link_arrow'></a>
|
||||
</div><div class="bottom"><icon src="AllIcons.Nodes.PpLibFolder"/> myLib</div><div class="bottom"><a href="placeholder">`genericMethod(Class<?>)` on localhost<icon src='AllIcons.Ide.External_link_arrow'></a></div>
|
||||
@@ -19,4 +19,4 @@
|
||||
<div class="block"><a href="psi_element://com.jetbrains.LinkBetweenMethods#m2()"><code>m2()</code></a></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div><div class='bottom'><icon src='AllIcons.Nodes.PpLibFolder'> myLib</div><div class='bottom'><a href="placeholder">`m1()` on localhost<icon src='AllIcons.Ide.External_link_arrow'></a>
|
||||
</div><div class="bottom"><icon src="AllIcons.Nodes.PpLibFolder"/> myLib</div><div class="bottom"><a href="placeholder">`m1()` on localhost<icon src='AllIcons.Ide.External_link_arrow'></a></div>
|
||||
@@ -24,4 +24,4 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div><div class='bottom'><icon src='AllIcons.Nodes.PpLibFolder'> myLib</div><div class='bottom'><a href="placeholder">`SimpleInterface` on localhost<icon src='AllIcons.Ide.External_link_arrow'></a>
|
||||
</div><div class="bottom"><icon src="AllIcons.Nodes.PpLibFolder"/> myLib</div><div class="bottom"><a href="placeholder">`SimpleInterface` on localhost<icon src='AllIcons.Ide.External_link_arrow'></a></div>
|
||||
@@ -32,4 +32,4 @@ extends java.lang.Object</pre>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div><div class='bottom'><icon src='AllIcons.Nodes.PpLibFolder'> myLib</div><div class='bottom'><a href="placeholder">`ClassWithRefLink` on localhost<icon src='AllIcons.Ide.External_link_arrow'></a>
|
||||
</div><div class="bottom"><icon src="AllIcons.Nodes.PpLibFolder"/> myLib</div><div class="bottom"><a href="placeholder">`ClassWithRefLink` on localhost<icon src='AllIcons.Ide.External_link_arrow'></a></div>
|
||||
@@ -26,4 +26,4 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div><div class='bottom'><icon src='AllIcons.Nodes.PpLibFolder'> myLib</div><div class='bottom'><a href="placeholder">`param()` on localhost<icon src='AllIcons.Ide.External_link_arrow'></a>
|
||||
</div><div class="bottom"><icon src="AllIcons.Nodes.PpLibFolder"/> myLib</div><div class="bottom"><a href="placeholder">`param()` on localhost<icon src='AllIcons.Ide.External_link_arrow'></a></div>
|
||||
@@ -5,4 +5,4 @@
|
||||
at least one element <tt>e</tt> such that
|
||||
<tt>(o==null ? e==null : o.equals(e))</tt>.
|
||||
|
||||
</div><table class='sections'><tr><td valign='top' class='section'><p>Overrides:</td><td valign='top'><p><a href="psi_element://java.util.Collection#contains(java.lang.Object)"><code><span style="color:#000000;">contains</span></code></a> in interface <a href="psi_element://java.util.Collection"><code><span style="color:#000000;">Collection</span></code></a></td><tr><td valign='top' class='section'><p>Params:</td><td valign='top'><span style="">o</span> – element whose presence in this list is to be tested </td><tr><td valign='top' class='section'><p>Returns:</td><td valign='top'><p><tt>true</tt> if this list contains the specified element </td><tr><td valign='top' class='section'><p>Throws:</td><td valign='top'><p><a href="psi_element://java.lang.ClassCastException"><code><span style="color:#000000;">ClassCastException</span></code></a> – if the type of the specified element is incompatible with this list (<a href="psi_element://java.util.Collection###optional-restrictions">optional</a>) <p><a href="psi_element://java.lang.NullPointerException"><code><span style="color:#000000;">NullPointerException</span></code></a> – if the specified element is null and this list does not permit null elements (<a href="psi_element://java.util.Collection###optional-restrictions">optional</a>)</td><tr><td valign='top' class='section'><p>External<br> annotations:</td><td valign='top'><p><span style="color:#808000;">@</span><a href="psi_element://org.jetbrains.annotations.Contract"><span style="color:#808000;">org.jetbrains.annotations.Contract</span></a><span style="">(</span><span style="">pure</span><span style=""> = </span><span style="color:#000080;font-weight:bold;">true</span><span style="">)</span></td></table><div class='bottom'><icon src='AllIcons.Nodes.PpLibFolder'> < java 1.7 ></div>
|
||||
</div><table class='sections'><tr><td valign='top' class='section'><p>Overrides:</td><td valign='top'><p><a href="psi_element://java.util.Collection#contains(java.lang.Object)"><code><span style="color:#000000;">contains</span></code></a> in interface <a href="psi_element://java.util.Collection"><code><span style="color:#000000;">Collection</span></code></a></td><tr><td valign='top' class='section'><p>Params:</td><td valign='top'><span style="">o</span> – element whose presence in this list is to be tested </td><tr><td valign='top' class='section'><p>Returns:</td><td valign='top'><p><tt>true</tt> if this list contains the specified element </td><tr><td valign='top' class='section'><p>Throws:</td><td valign='top'><p><a href="psi_element://java.lang.ClassCastException"><code><span style="color:#000000;">ClassCastException</span></code></a> – if the type of the specified element is incompatible with this list (<a href="psi_element://java.util.Collection###optional-restrictions">optional</a>) <p><a href="psi_element://java.lang.NullPointerException"><code><span style="color:#000000;">NullPointerException</span></code></a> – if the specified element is null and this list does not permit null elements (<a href="psi_element://java.util.Collection###optional-restrictions">optional</a>)</td><tr><td valign='top' class='section'><p>External<br> annotations:</td><td valign='top'><p><span style="color:#808000;">@</span><a href="psi_element://org.jetbrains.annotations.Contract"><span style="color:#808000;">org.jetbrains.annotations.Contract</span></a><span style="">(</span><span style="">pure</span><span style=""> = </span><span style="color:#000080;font-weight:bold;">true</span><span style="">)</span></td></table><div class="bottom"><icon src="AllIcons.Nodes.PpLibFolder"/> < java 1.7 ></div>
|
||||
@@ -270,7 +270,7 @@ class Bar {
|
||||
}
|
||||
|
||||
// Here we check that the covering module (SDK in this case) is rendered in decorated info
|
||||
assert component.decoratedText.contains("<div class='bottom'><icon src='AllIcons.Nodes.PpLibFolder'> < java 1.7 ></div>")
|
||||
assert component.decoratedText.contains('<div class="bottom"><icon src="AllIcons.Nodes.PpLibFolder"/> < java 1.7 ></div>')
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -28,4 +28,5 @@ public interface DocumentationMarkup {
|
||||
HtmlChunk.Element DEFINITION_ELEMENT = HtmlChunk.div().setClass("definition");
|
||||
HtmlChunk.Element GRAYED_ELEMENT = HtmlChunk.span().setClass("grayed");
|
||||
HtmlChunk.Element CENTERED_ELEMENT = HtmlChunk.p().setClass("centered");
|
||||
HtmlChunk.Element EXTERNAL_LINK_ICON = HtmlChunk.tag("icon").attr("src", "AllIcons.Ide.External_link_arrow");
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService;
|
||||
import com.intellij.openapi.ui.popup.JBPopup;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.text.HtmlBuilder;
|
||||
import com.intellij.openapi.util.text.HtmlChunk;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.FileStatus;
|
||||
@@ -1765,11 +1766,16 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
|
||||
@NlsSafe @Nullable String externalUrl,
|
||||
@Nullable DocumentationProvider provider
|
||||
) {
|
||||
return decorate(text, getLocationText(element), getExternalText(element, externalUrl, provider));
|
||||
}
|
||||
|
||||
@Internal
|
||||
@Contract(pure = true)
|
||||
public static @Nls String decorate(@Nls @NotNull String text, @Nullable HtmlChunk location, @Nullable HtmlChunk links) {
|
||||
text = StringUtil.replaceIgnoreCase(text, "</html>", "");
|
||||
text = StringUtil.replaceIgnoreCase(text, "</body>", "");
|
||||
text = StringUtil.replaceIgnoreCase(text, SECTIONS_START + SECTIONS_END, "");
|
||||
//noinspection HardCodedStringLiteral
|
||||
text = StringUtil.replaceIgnoreCase(text, SECTIONS_START + "<p>" + SECTIONS_END, "");
|
||||
text = StringUtil.replaceIgnoreCase(text, SECTIONS_START + "<p>" + SECTIONS_END, ""); //NON-NLS
|
||||
boolean hasContent = text.contains(CONTENT_START);
|
||||
if (!hasContent) {
|
||||
if (!text.contains(DEFINITION_START)) {
|
||||
@@ -1793,14 +1799,11 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
|
||||
if (!text.contains(DEFINITION_START)) {
|
||||
text = text.replace("class='content'", "class='content-only'");
|
||||
}
|
||||
String location = getLocationText(element);
|
||||
if (location != null) {
|
||||
//noinspection HardCodedStringLiteral
|
||||
text = text + getBottom(hasContent) + location + "</div>";
|
||||
text += getBottom(hasContent).child(location);
|
||||
}
|
||||
String links = getExternalText(element, externalUrl, provider);
|
||||
if (links != null) {
|
||||
text = text + getBottom(location != null) + links;
|
||||
text += getBottom(location != null).child(links);
|
||||
}
|
||||
//workaround for Swing html renderer not removing empty paragraphs before non-inline tags
|
||||
text = text.replaceAll("<p>\\s*(<(?:[uo]l|h\\d|p))", "$1");
|
||||
@@ -1808,7 +1811,9 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
|
||||
return text;
|
||||
}
|
||||
|
||||
private @Nls @Nullable String getExternalText(
|
||||
@RequiresReadLock
|
||||
@RequiresBackgroundThread
|
||||
private @Nullable HtmlChunk getExternalText(
|
||||
@Nullable PsiElement element,
|
||||
@NlsSafe @Nullable String externalUrl,
|
||||
@Nullable DocumentationProvider provider
|
||||
@@ -1825,34 +1830,33 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
|
||||
List<String> urls = provider.getUrlFor(element, originalElement);
|
||||
if (urls != null) {
|
||||
boolean hasBadUrl = false;
|
||||
@Nls StringBuilder result = new StringBuilder();
|
||||
var result = new HtmlBuilder();
|
||||
for (String url : urls) {
|
||||
String link = getLink(title, url);
|
||||
HtmlChunk link = getLink(title, url);
|
||||
if (link == null) {
|
||||
hasBadUrl = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result.length() > 0) result.append("<p>");
|
||||
if (!result.isEmpty()) result.append(HtmlChunk.p());
|
||||
result.append(link);
|
||||
}
|
||||
if (!hasBadUrl) return result.toString();
|
||||
if (!hasBadUrl) return result.toFragment();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
String link = getLink(title, externalUrl);
|
||||
HtmlChunk link = getLink(title, externalUrl);
|
||||
if (link != null) return link;
|
||||
}
|
||||
|
||||
String linkText = CodeInsightBundle.message("html.external.documentation.component.header", title, title == null ? 0 : 1);
|
||||
return HtmlChunk.link("external_doc", linkText)
|
||||
.child(HtmlChunk.tag("icon").attr("src", "AllIcons.Ide.External_link_arrow")).toString();
|
||||
return HtmlChunk.link("external_doc", linkText).child(EXTERNAL_LINK_ICON);
|
||||
}
|
||||
|
||||
private static @Nls String getLink(@Nls String title, @NlsSafe String url) {
|
||||
@Internal
|
||||
public static @Nullable HtmlChunk getLink(@Nls String title, @NlsSafe String url) {
|
||||
String hostname = getHostname(url);
|
||||
if (hostname == null) {
|
||||
return null;
|
||||
@@ -1864,7 +1868,7 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
|
||||
else {
|
||||
linkText = CodeInsightBundle.message("link.text.element.documentation.on.url", title, hostname);
|
||||
}
|
||||
return HtmlChunk.link(url, linkText).toString();
|
||||
return HtmlChunk.link(url, linkText);
|
||||
}
|
||||
|
||||
static boolean shouldShowExternalDocumentationLink(DocumentationProvider provider,
|
||||
@@ -1904,9 +1908,8 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
|
||||
return -1;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getBottom(boolean hasContent) {
|
||||
return "<div class='" + (hasContent ? "bottom" : "bottom-no-content") + "'>";
|
||||
private static @NotNull HtmlChunk.Element getBottom(boolean hasContent) {
|
||||
return HtmlChunk.div().setClass(hasContent ? "bottom" : "bottom-no-content");
|
||||
}
|
||||
|
||||
private static final Pattern EXTERNAL_LINK_PATTERN = Pattern.compile("(<a\\s*href=[\"']http[^>]*>)([^>]*)(</a>)");
|
||||
@@ -1917,7 +1920,9 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
|
||||
return EXTERNAL_LINK_PATTERN.matcher(text).replaceAll(EXTERNAL_LINK_REPLACEMENT);
|
||||
}
|
||||
|
||||
private static @NlsSafe String getLocationText(@Nullable PsiElement element) {
|
||||
@RequiresReadLock
|
||||
@RequiresBackgroundThread
|
||||
private static @Nullable HtmlChunk getLocationText(@Nullable PsiElement element) {
|
||||
if (element != null) {
|
||||
PsiFile file = element.getContainingFile();
|
||||
VirtualFile vfile = file == null ? null : file.getVirtualFile();
|
||||
@@ -1934,13 +1939,21 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
|
||||
|
||||
if (module != null && !ModuleType.isInternal(module)) {
|
||||
if (ModuleManager.getInstance(element.getProject()).getModules().length == 1) return null;
|
||||
return "<icon src='" + ModuleType.get(module).getId() + "'> " + module.getName().replace("<", "<");
|
||||
return HtmlChunk.fragment(
|
||||
HtmlChunk.tag("icon").attr("src", ModuleType.get(module).getId()),
|
||||
HtmlChunk.nbsp(),
|
||||
HtmlChunk.text(module.getName())
|
||||
);
|
||||
}
|
||||
else {
|
||||
List<OrderEntry> entries = fileIndex.getOrderEntriesForFile(vfile);
|
||||
for (OrderEntry order : entries) {
|
||||
if (order instanceof LibraryOrderEntry || order instanceof JdkOrderEntry) {
|
||||
return "<icon src='AllIcons.Nodes.PpLibFolder" + "'> " + order.getPresentableName().replace("<", "<");
|
||||
return HtmlChunk.fragment(
|
||||
HtmlChunk.tag("icon").attr("src", "AllIcons.Nodes.PpLibFolder"),
|
||||
HtmlChunk.nbsp(),
|
||||
HtmlChunk.text(order.getPresentableName())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user