load and render python stdlib in scientific mode

This commit is contained in:
Ekaterina Tuzova
2017-09-01 13:30:04 +03:00
parent 3c7bd8a292
commit aa9f4ff2a9
7 changed files with 110 additions and 7 deletions
+11 -2
View File
@@ -26,6 +26,15 @@
<orderEntry type="library" name="gson" level="project" />
<orderEntry type="module" module-name="xml-openapi" />
<orderEntry type="module" module-name="vcs-api" />
<orderEntry type="module-library">
<library name="org.jsoup:jsoup:1.10.3" type="repository">
<properties maven-id="org.jsoup:jsoup:1.10.3" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jsoup/jsoup/1.10.3/jsoup-1.10.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
</component>
</module>
</module>
@@ -26,6 +26,8 @@ import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.options.FontSize;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
@@ -35,6 +37,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.python.console.PythonConsoleToolWindow;
import com.jetbrains.python.documentation.PyDocumentationSettings;
import com.jetbrains.python.run.PythonConfigurationType;
import com.jetbrains.python.run.PythonRunConfiguration;
import org.jetbrains.annotations.NotNull;
@@ -78,12 +81,21 @@ public class PySciViewAction extends ToggleAction implements DumbAware {
showDocumentationToolwindow(project, element);
showDataViewAsToolwindow(project);
showCommandLineInRunConfiguration(project, true);
renderExternalDocumentation(element, true);
}
else {
hideConsoleToolwindow(project);
restoreDocumentationPopup(project);
hideDataViewer(project);
showCommandLineInRunConfiguration(project, false);
renderExternalDocumentation(element, false);
}
}
private static void renderExternalDocumentation(PsiElement element, boolean render) {
final Module module = ModuleUtilCore.findModuleForPsiElement(element);
if (module != null) {
PyDocumentationSettings.getInstance(module).setRenderExternalDocumentation(render);
}
}
@@ -22,6 +22,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.documentation.PythonDocumentationLinkProvider;
import com.jetbrains.python.documentation.PythonDocumentationProvider;
@@ -29,7 +30,6 @@ import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
import com.jetbrains.python.sdk.PythonSdkType;
@@ -544,6 +544,7 @@ public class PyStdlibDocumentationLinkProvider implements PythonDocumentationLin
@Override
public String getExternalDocumentationUrl(PsiElement element, PsiElement originalElement) {
if (PyBuiltinCache.getInstance(element).isBuiltin(element)) return null;
PsiFileSystemItem file = element instanceof PsiFileSystemItem ? (PsiFileSystemItem) element : element.getContainingFile();
if (PyNames.INIT_DOT_PY.equals(file.getName())) {
file = file.getParent();
@@ -49,7 +49,7 @@
</constraints>
<properties/>
</component>
<grid id="e7a5f" binding="myDocStringsPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="e7a5f" binding="myDocStringsPanel" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="2" column="0" row-span="2" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -82,6 +82,14 @@
<text value="Analyze Python code in docstrings"/>
</properties>
</component>
<component id="e3228" class="javax.swing.JCheckBox" binding="renderExternal">
<constraints>
<grid row="2" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Render external documentation for stdlib"/>
</properties>
</component>
</children>
</grid>
<grid id="9f040" binding="myRestPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
@@ -39,7 +39,6 @@ import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.util.FileContentUtil;
import com.intellij.util.FileContentUtilCore;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PythonFileType;
import com.jetbrains.python.ReSTService;
import com.jetbrains.python.documentation.PyDocumentationSettings;
@@ -78,6 +77,7 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable {
private JCheckBox analyzeDoctest;
private JPanel myDocStringsPanel;
private JPanel myRestPanel;
private JCheckBox renderExternal;
public PyIntegratedToolsConfigurable(@NotNull Module module) {
myModule = module;
@@ -99,6 +99,7 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable {
myWorkDir.setText(service.getWorkdir());
txtIsRst.setSelected(service.txtIsRst());
analyzeDoctest.setSelected(myDocumentationSettings.isAnalyzeDoctest());
renderExternal.setSelected(myDocumentationSettings.isRenderExternalDocumentation());
myRequirementsPathField.addBrowseFolderListener("Choose path to the package requirements file:", null, myProject,
FileChooserDescriptorFactory.createSingleLocalFileDescriptor());
myRequirementsPathField.setText(getRequirementsPath());
@@ -207,6 +208,9 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable {
if (analyzeDoctest.isSelected() != myDocumentationSettings.isAnalyzeDoctest()) {
return true;
}
if (renderExternal.isSelected() != myDocumentationSettings.isRenderExternalDocumentation()) {
return true;
}
if (!ReSTService.getInstance(myModule).getWorkdir().equals(myWorkDir.getText())) {
return true;
}
@@ -235,6 +239,7 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable {
FileContentUtil.reparseFiles(myProject, Lists.newArrayList(files), false);
}
myModel.apply();
myDocumentationSettings.setRenderExternalDocumentation(renderExternal.isSelected());
myDocumentationSettings.setFormat((DocStringFormat)myDocstringFormatComboBox.getSelectedItem());
final ReSTService reSTService = ReSTService.getInstance(myModule);
reSTService.setWorkdir(myWorkDir.getText());
@@ -271,6 +276,7 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable {
myWorkDir.setText(ReSTService.getInstance(myModule).getWorkdir());
txtIsRst.setSelected(ReSTService.getInstance(myModule).txtIsRst());
analyzeDoctest.setSelected(myDocumentationSettings.isAnalyzeDoctest());
renderExternal.setSelected(myDocumentationSettings.isRenderExternalDocumentation());
myRequirementsPathField.setText(getRequirementsPath());
}
@@ -47,6 +47,7 @@ public class PyDocumentationSettings implements PersistentStateComponent<PyDocum
@NotNull private DocStringFormat myDocStringFormat = DEFAULT_DOCSTRING_FORMAT;
private boolean myAnalyzeDoctest = true;
private boolean myRenderExternalDocumentation;
public boolean isNumpyFormat(PsiFile file) {
return isFormat(file, DocStringFormat.NUMPY);
@@ -117,6 +118,14 @@ public class PyDocumentationSettings implements PersistentStateComponent<PyDocum
myAnalyzeDoctest = analyze;
}
public boolean isRenderExternalDocumentation() {
return myRenderExternalDocumentation;
}
public void setRenderExternalDocumentation(boolean renderExternalDocumentation) {
myRenderExternalDocumentation = renderExternalDocumentation;
}
@Override
public PyDocumentationSettings getState() {
return this;
@@ -22,16 +22,20 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PythonDialectsTokenSetProvider;
import com.jetbrains.python.codeInsight.stdlib.PyStdlibDocumentationLinkProvider;
import com.jetbrains.python.console.PydevConsoleRunner;
import com.jetbrains.python.console.PydevDocumentationProvider;
import com.jetbrains.python.documentation.docstrings.DocStringUtil;
@@ -50,9 +54,14 @@ import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.List;
@@ -96,7 +105,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
summary = docString.getSummary();
}
return $(cat.toString()).add(describeDecorators(func, LSame2, ", ", LSame1)).add(describeFunction(func, LSame2, LSame1))
.toString() + "\n" + summary;
.toString() + "\n" + summary;
}
else if (element instanceof PyClass) {
final PyClass cls = (PyClass)element;
@@ -442,7 +451,56 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
@Override
public String fetchExternalDocumentation(Project project, PsiElement element, List<String> docUrls) {
return null;
final Module module = ModuleUtilCore.findModuleForPsiElement(element);
if (module != null && !PyDocumentationSettings.getInstance(module).isRenderExternalDocumentation()) return null;
return ApplicationManager.getApplication().runReadAction((Computable<String>)() -> {
PsiFileSystemItem file = element instanceof PsiFileSystemItem ? (PsiFileSystemItem)element : element.getContainingFile();
if (file == null) return null;
if (PyNames.INIT_DOT_PY.equals(file.getName())) {
file = file.getParent();
assert file != null;
}
final Sdk sdk = PyBuiltinCache.findSdkForFile(file);
if (sdk == null) {
return null;
}
final QualifiedName moduleQName = QualifiedNameFinder.findCanonicalImportPath(element, element);
if (moduleQName == null) {
return null;
}
PsiNamedElement namedElement = (element instanceof PsiNamedElement && !(element instanceof PsiFileSystemItem))
? (PsiNamedElement)element
: null;
if (namedElement instanceof PyFunction && PyNames.INIT.equals(namedElement.getName())) {
final PyClass containingClass = ((PyFunction)namedElement).getContainingClass();
if (containingClass != null) {
namedElement = containingClass;
}
}
final PyStdlibDocumentationLinkProvider stdlibDocumentationLinkProvider =
Extensions.findExtension(PythonDocumentationLinkProvider.EP_NAME, PyStdlibDocumentationLinkProvider.class);
final String url = stdlibDocumentationLinkProvider.getExternalDocumentationUrl(element, element);
if (url == null) {
return null;
}
try {
final Document document = Jsoup.parse(new URL(url), 1000);
final String elementId = namedElement != null ? moduleQName + "." + namedElement.getName() : "module-" + moduleQName;
document.select("a.headerlink").remove();
final Elements parents = document.getElementsByAttributeValue("id", elementId).parents();
if (parents.isEmpty()) {
return document.toString();
}
return parents.get(0).toString();
}
catch (MalformedURLException ignored) {
}
catch (IOException ignored) {
}
return null;
});
}
@Override