Refactoring: move quick doc extraction to the corresponding responsible provider

This commit is contained in:
Dmitry Trofimov
2018-10-30 23:19:42 +01:00
parent e9071b0120
commit 6774d3fa08
4 changed files with 55 additions and 39 deletions
@@ -12,5 +12,6 @@
<orderEntry type="module" module-name="intellij.platform.lang" />
<orderEntry type="module" module-name="intellij.platform.lang.impl" />
<orderEntry type="library" name="Guava" level="project" />
<orderEntry type="library" name="jsoup" level="project" />
</component>
</module>
@@ -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<Document, String> quickDocExtractor(PsiNamedElement namedElement) {
return null;
}
}
@@ -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, String>)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<String, String> modName = getModuleName(moduleName.toString());
String modName = getModuleName(moduleName.toString());
final String pyVersion = PythonDocumentationProvider.pyVersion(sdk.getVersionString());
final Map<String, String> 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<String, String> 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<String, String> {
@@ -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<Document, String> 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;
});
}