diff --git a/python/openapi/intellij.python.community.iml b/python/openapi/intellij.python.community.iml index 98ec21c89d51..e111859d7cc8 100644 --- a/python/openapi/intellij.python.community.iml +++ b/python/openapi/intellij.python.community.iml @@ -12,5 +12,6 @@ + \ No newline at end of file diff --git a/python/openapi/src/com/jetbrains/python/documentation/PythonDocumentationLinkProvider.java b/python/openapi/src/com/jetbrains/python/documentation/PythonDocumentationLinkProvider.java index ee49e67b2af6..f4fb137eddc8 100644 --- a/python/openapi/src/com/jetbrains/python/documentation/PythonDocumentationLinkProvider.java +++ b/python/openapi/src/com/jetbrains/python/documentation/PythonDocumentationLinkProvider.java @@ -18,7 +18,11 @@ package com.jetbrains.python.documentation; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNamedElement; import org.jetbrains.annotations.Nullable; +import org.jsoup.nodes.Document; + +import java.util.function.Function; /** * @author yole @@ -39,4 +43,9 @@ public interface PythonDocumentationLinkProvider { default String getExternalDocumentationRoot(Sdk sdk) { return ""; } + + @Nullable + default Function quickDocExtractor(PsiNamedElement namedElement) { + return null; + } } diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibDocumentationLinkProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibDocumentationLinkProvider.java index 3932849e7e16..c84b6afefb73 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibDocumentationLinkProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibDocumentationLinkProvider.java @@ -17,7 +17,6 @@ package com.jetbrains.python.codeInsight.stdlib; import com.google.common.collect.ImmutableMap; import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; @@ -32,8 +31,12 @@ import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.resolve.QualifiedNameFinder; import com.jetbrains.python.sdk.PythonSdkType; +import org.jetbrains.annotations.Nullable; +import org.jsoup.nodes.Document; +import org.jsoup.select.Elements; import java.util.Map; +import java.util.function.Function; /** * @author yole @@ -984,15 +987,35 @@ public class PyStdlibDocumentationLinkProvider implements PythonDocumentationLin return urlBuilder.toString(); } + @Nullable + @Override + public Function quickDocExtractor(PsiNamedElement namedElement) { + return (Function)document -> { + final String moduleName = getModuleNameForDocumentationUrl(namedElement, namedElement); + + final String elementId = namedElement != null ? moduleName + "." + namedElement.getName() : "module-" + moduleName; + document.select("a.headerlink").remove(); + final Elements parents = document.getElementsByAttributeValue("id", elementId).parents(); + if (parents.isEmpty()) { + final Elements moduleElement = document.getElementsByAttributeValue("id", "module-" + moduleName); + if (moduleElement != null) { + return moduleElement.toString(); + } + return document.toString(); + } + return parents.get(0).toString(); + }; + } + private String getStdlibUrlFor(PsiElement element, QualifiedName moduleName, Sdk sdk) { StringBuilder urlBuilder = new StringBuilder(getExternalDocumentationRoot(sdk)); - Pair modName = getModuleName(moduleName.toString()); + String modName = getModuleName(moduleName.toString()); final String pyVersion = PythonDocumentationProvider.pyVersion(sdk.getVersionString()); final Map moduleToWebpageName = pyVersion != null && pyVersion.startsWith("3") ? py3LibraryModulesToWebpageName : py2LibraryModulesToWebpageName; - final String webpageName = moduleToWebpageName.get(modName.first); + final String webpageName = moduleToWebpageName.get(modName); final boolean isBuiltin = "__builtin__".equals(webpageName) || "builtins".equals(webpageName); final String className = element instanceof PyFunction && ((PyFunction)element).getContainingClass() != null ? @@ -1009,20 +1032,18 @@ public class PyStdlibDocumentationLinkProvider implements PythonDocumentationLin if (webpageName2 != null && element instanceof PsiNamedElement && !(element instanceof PyFile)) { urlBuilder.append('#'); if (!isBuiltin) { - urlBuilder.append(modName.second).append("."); + urlBuilder.append(modName).append("."); } urlBuilder.append(qName); } return urlBuilder.toString(); } - private static Pair getModuleName(String qname) { - String moduleName = qname; + private static String getModuleName(String qname) { if (qname.equals("ntpath") || qname.equals("posixpath")) { qname = "os.path"; } else if (qname.equals("genericpath")) { qname = "os.path"; - moduleName = qname; } else if (qname.equals("nt")) { qname = "os"; @@ -1034,13 +1055,13 @@ public class PyStdlibDocumentationLinkProvider implements PythonDocumentationLin qname = "xml.parsers.expat"; } - return Pair.create(qname, moduleName); + return qname; } public String getModuleNameForDocumentationUrl(PsiElement element, PsiElement originalElement) { QualifiedName qName = QualifiedNameFinder.findCanonicalImportPath(element, originalElement); - return qName != null? getModuleName(qName.toString()).second : ""; + return qName != null? getModuleName(qName.toString()) : ""; } private static final class MyBuilder extends ImmutableMap.Builder { diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index 99a180014763..b7822df19936 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -631,43 +631,28 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i namedElement = containingClass; } } - final PyStdlibDocumentationLinkProvider stdlibDocumentationLinkProvider = - PythonDocumentationLinkProvider.EP_NAME.findExtensionOrFail(PyStdlibDocumentationLinkProvider.class); + for (final PythonDocumentationLinkProvider documentationLinkProvider : + PythonDocumentationLinkProvider.EP_NAME.getExtensionList()) { - String url = null; + Function quickDocExtractor = documentationLinkProvider.quickDocExtractor(namedElement); - if (docUrls.size()>0) { - url = docUrls.get(0); - } else { - url = stdlibDocumentationLinkProvider.getExternalDocumentationUrl(element, element); - } - - if (url == null) { - return null; - } - - final String moduleName = stdlibDocumentationLinkProvider.getModuleNameForDocumentationUrl(element, element); - - try { - final Document document = Jsoup.parse(new URL(url), 1000); - final String elementId = namedElement != null ? moduleName + "." + namedElement.getName() : "module-" + moduleName; - document.select("a.headerlink").remove(); - final Elements parents = document.getElementsByAttributeValue("id", elementId).parents(); - if (parents.isEmpty()) { - final Elements moduleElement = document.getElementsByAttributeValue("id", "module-" + moduleName); - if (moduleElement != null) { - return moduleElement.toString(); + if (quickDocExtractor != null) { + for (String url : docUrls) { + try { + final Document document = Jsoup.parse(new URL(url), 1000); + String quickDoc = quickDocExtractor.apply(document); + if (StringUtil.isNotEmpty(quickDoc)) { + return quickDoc; + } + } + catch (IOException e) { + } } - return document.toString(); } - return parents.get(0).toString(); - } - catch (MalformedURLException ignored) { - } - catch (IOException ignored) { } + return null; }); }