Merge remote-tracking branch 'origin/master'

This commit is contained in:
Roman Ivanov
2017-09-01 18:56:00 +07:00
25 changed files with 642 additions and 27 deletions
@@ -146,8 +146,9 @@ public class LiveVariablesAnalyzer {
BitSet set = result.get(instruction);
if (set != null) {
set.or(liveVars);
return set;
} else {
return (BitSet)set.clone();
}
else if (!liveVars.isEmpty()) {
result.put((FinishElementInstruction)instruction, (BitSet)liveVars.clone());
}
}
@@ -47,7 +47,6 @@ import java.awt.*;
public abstract class DockablePopupManager<T extends JComponent & Disposable> {
protected ToolWindow myToolWindow;
private boolean myAutoUpdateDocumentation = PropertiesComponent.getInstance().isTrueValue(getAutoUpdateEnabledProperty());
private Runnable myAutoUpdateRequest;
@NotNull protected final Project myProject;
@@ -119,7 +118,7 @@ public abstract class DockablePopupManager<T extends JComponent & Disposable> {
new UiNotifyConnector(component, new Activatable() {
@Override
public void showNotify() {
restartAutoUpdate(myAutoUpdateDocumentation);
restartAutoUpdate(PropertiesComponent.getInstance().getBoolean(getAutoUpdateEnabledProperty()));
}
@Override
@@ -144,13 +143,12 @@ public abstract class DockablePopupManager<T extends JComponent & Disposable> {
AllIcons.General.AutoscrollFromSource) {
@Override
public boolean isSelected(AnActionEvent e) {
return myAutoUpdateDocumentation;
return PropertiesComponent.getInstance().getBoolean(getAutoUpdateEnabledProperty());
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
PropertiesComponent.getInstance().setValue(getAutoUpdateEnabledProperty(), state);
myAutoUpdateDocumentation = state;
restartAutoUpdate(state);
}
};
@@ -222,7 +220,7 @@ public abstract class DockablePopupManager<T extends JComponent & Disposable> {
}
protected void restorePopupBehavior() {
public void restorePopupBehavior() {
if (myToolWindow != null) {
PropertiesComponent.getInstance().setValue(getShowInToolWindowProperty(), Boolean.FALSE.toString());
ToolWindowManagerEx toolWindowManagerEx = ToolWindowManagerEx.getInstanceEx(myProject);
@@ -104,7 +104,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
private SmartPsiElementPointer myElement;
private long myModificationCount;
private static final String QUICK_DOC_FONT_SIZE_PROPERTY = "quick.doc.font.size";
public static final String QUICK_DOC_FONT_SIZE_PROPERTY = "quick.doc.font.size";
private final Stack<Context> myBackStack = new Stack<>();
private final Stack<Context> myForwardStack = new Stack<>();
@@ -145,7 +145,7 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
}
@Override
protected void restorePopupBehavior() {
public void restorePopupBehavior() {
if (myPreviouslyFocused != null) {
IdeFocusManager.getInstance(myProject).requestFocus(myPreviouslyFocused, true);
}
@@ -72,7 +72,10 @@ public class DocumentSettingsManager extends FileDocumentManagerAdapter {
private <T> void applyConfigValueToUserData(VirtualFile file, Key<T> userDataKey, String editorConfigKey,
String configValue, Map<String, T> configMap) {
if (configValue.isEmpty()) return;
if (configValue.isEmpty()) {
file.putUserData(userDataKey, null);
return;
}
final T data = configMap.get(configValue);
if (data == null) {
+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>
@@ -809,6 +809,10 @@
<keyboard-shortcut keymap="NetBeans 6.5" first-keystroke="ctrl alt E" replace-all="true"/>
</action>
<action id="PyRunFileInConsole" class="com.jetbrains.python.actions.PyRunFileInConsoleAction">
<add-to-group group-id="EditorPopupMenu" anchor="after" relative-to-action="ExecuteInPyConsoleAction"/>
</action>
<action id="NewPythonFile" class="com.jetbrains.python.actions.CreatePythonFileAction">
<add-to-group group-id="NewGroup" anchor="before" relative-to-action="NewXml"/>
</action>
@@ -860,6 +864,10 @@
<add-to-group group-id="DebugMainMenu" relative-to-action="StepInto" anchor="after"/>
<add-to-group group-id="XDebugger.ToolWindow.TopToolbar" relative-to-action="StepInto" anchor="after"/>
</action>
<action id="PySciView" class="com.jetbrains.python.actions.PySciViewAction">
<add-to-group group-id="ViewMenu" anchor="before" relative-to-action="ToggleFullScreenGroup"/>
</action>
</actions>
<extensions defaultExtensionNs="com.intellij.spellchecker">
@@ -867,6 +875,12 @@
<bundledDictionaryProvider implementation="com.jetbrains.python.spellchecker.PythonBundledDictionaryProvider"/>
</extensions>
<project-components>
<component>
<implementation-class>com.jetbrains.python.actions.PySciProjectComponent</implementation-class>
</component>
</project-components>
<application-components>
<component>
<implementation-class>com.jetbrains.python.testing.VFSTestFrameworkListener</implementation-class>
@@ -0,0 +1,73 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.actions;
import com.intellij.execution.ExecutionManager;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.actions.ConfigurationFromContext;
import com.intellij.execution.actions.RunConfigurationProducer;
import com.intellij.execution.executors.DefaultRunExecutor;
import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.run.PythonRunConfigurationParams;
import com.jetbrains.python.run.PythonRunConfigurationProducer;
import org.jetbrains.annotations.NotNull;
public class PyRunFileInConsoleAction extends AnAction implements DumbAware {
public PyRunFileInConsoleAction() {
super("Run File in Console");
}
@Override
public void update(@NotNull AnActionEvent e) {
super.update(e);
final Project project = e.getProject();
final PsiFile psiFile = CommonDataKeys.PSI_FILE.getData(e.getDataContext());
final Presentation presentation = e.getPresentation();
presentation.setEnabledAndVisible(project != null && psiFile instanceof PyFile);
}
@Override
public void actionPerformed(AnActionEvent e) {
final PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext());
if (file == null) return;
final Project project = e.getProject();
if (project == null) return;
final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext());
final ConfigurationFromContext fromContext =
RunConfigurationProducer.getInstance(PythonRunConfigurationProducer.class).createConfigurationFromContext(context);
if (fromContext == null) return;
final RunnerAndConfigurationSettings settings = fromContext.getConfigurationSettings();
final PythonRunConfigurationParams configuration = (PythonRunConfigurationParams)settings.getConfiguration();
configuration.setShowCommandLineAfterwards(true);
RunManager runManager = RunManager.getInstance(project);
runManager.setTemporaryConfiguration(settings);
runManager.setSelectedConfiguration(settings);
ExecutionEnvironmentBuilder builder = ExecutionEnvironmentBuilder.createOrNull(DefaultRunExecutor.getRunExecutorInstance(), settings);
if (builder != null) {
ExecutionManager.getInstance(project).restartRunProfile(builder.build());
}
}
}
@@ -0,0 +1,158 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.actions;
import com.intellij.codeInsight.documentation.DocumentationManager;
import com.intellij.ide.DataManager;
import com.intellij.notification.NotificationDisplayType;
import com.intellij.notification.NotificationGroup;
import com.intellij.notification.NotificationListener;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
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.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiManager;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.python.packaging.PyPackage;
import com.jetbrains.python.packaging.PyPackageUtil;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import static com.intellij.codeInsight.documentation.DocumentationComponent.COLOR_KEY;
import static com.jetbrains.python.actions.PySciViewAction.ACTION_ID;
@State(name = "PySciProjectComponent", storages = @Storage("other.xml"))
public class PySciProjectComponent extends AbstractProjectComponent implements PersistentStateComponent<PySciProjectComponent.State> {
private static final NotificationGroup BALLOON_NOTIFICATIONS = new NotificationGroup("Python Scientific View Advertiser",
NotificationDisplayType.STICKY_BALLOON,
false);
private State myState = new State();
protected PySciProjectComponent(Project project) {
super(project);
}
public static PySciProjectComponent getInstance(Project project) {
return project.getComponent(PySciProjectComponent.class);
}
public void useSciView(boolean useSciView) {
myState.PY_SCI_VIEW = useSciView;
}
public boolean useSciView() {
return myState.PY_SCI_VIEW;
}
@Override
public void projectOpened() {
if (myState.PY_SCI_VIEW) {
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(() -> {
EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
scheme.setColor(COLOR_KEY, UIUtil.getEditorPaneBackground());
final PsiDirectory directory = PsiManager.getInstance(myProject).findDirectory(myProject.getBaseDir());
if (directory != null) {
DocumentationManager.getInstance(myProject).showJavaDocInfo(directory, directory);
}
});
}
else if (!myState.PY_SCI_VIEW_SUGGESTED) {
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(() -> {
final PsiDirectory directory = PsiManager.getInstance(myProject).findDirectory(myProject.getBaseDir());
if (directory != null) {
final Module module = ModuleUtilCore.findModuleForPsiElement(directory);
if (module != null) {
final Sdk sdk = PythonSdkType.findPythonSdk(module);
if (sdk != null) {
final List<PyPackage> packages = PyPackageUtil.refreshAndGetPackagesModally(sdk);
final PyPackage numpy = PyPackageUtil.findPackage(packages, "numpy");
if (numpy != null) {
showInspectionAdvertisement(myProject);
}
}
}
}
});
}
}
private void showInspectionAdvertisement(@NotNull Project project) {
final String msg = "Your source code imports the 'numpy' package." +
"<br/>Would you like to enable Scientific View?<br/>" +
"<a href=\"#yes\">Yes</a>&nbsp;&nbsp;<a href=\"#no\">No</a>";
showSingletonNotification(project, msg, NotificationType.INFORMATION, (notification, event) -> {
myState.PY_SCI_VIEW_SUGGESTED = true;
final boolean enabled = "#yes".equals(event.getDescription());
if (enabled) {
final AnAction action = ActionManager.getInstance().getAction(ACTION_ID);
if (action instanceof PySciViewAction) {
final AnActionEvent anActionEvent = AnActionEvent.createFromDataContext(
ActionPlaces.UNKNOWN, null, DataManager.getInstance().getDataContextFromFocus().getResult());
((PySciViewAction)action).setSelected(anActionEvent, true);
}
}
});
}
private static void showSingletonNotification(@NotNull Project project,
@NotNull String htmlContent,
@NotNull NotificationType type,
@NotNull NotificationListener listener) {
BALLOON_NOTIFICATIONS.createNotification("Scientific View", htmlContent, type, (notification, event) -> {
try {
listener.hyperlinkUpdate(notification, event);
}
finally {
notification.expire();
}
}).notify(project);
}
@Nullable
@Override
public PySciProjectComponent.State getState() {
return myState;
}
@Override
public void loadState(PySciProjectComponent.State state) {
myState.PY_SCI_VIEW = state.PY_SCI_VIEW;
myState.PY_SCI_VIEW_SUGGESTED = state.PY_SCI_VIEW_SUGGESTED;
}
public static class State {
public boolean PY_SCI_VIEW = false;
public boolean PY_SCI_VIEW_SUGGESTED = false;
}
}
@@ -0,0 +1,213 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.actions;
import com.intellij.codeInsight.documentation.DocumentationManager;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
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;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.wm.*;
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;
import java.awt.*;
import static com.intellij.codeInsight.documentation.DocumentationComponent.COLOR_KEY;
import static com.intellij.codeInsight.documentation.DocumentationComponent.QUICK_DOC_FONT_SIZE_PROPERTY;
import static com.jetbrains.python.debugger.containerview.PyDataView.DATA_VIEWER_ID;
public class PySciViewAction extends ToggleAction implements DumbAware {
private static final String TEXT_SCI_VIEW = "Scientific Mode";
private boolean wasConsoleVisible = false;
private ToolWindowType myDocumentationType = ToolWindowType.FLOATING;
private boolean myDocumentationAutoHide = true;
public static final String ACTION_ID = "PySciView";
private ToolWindowType myDataViewType = ToolWindowType.FLOATING;
private Color myDocumentationBackgroundColor = EditorColorsManager.getInstance().getGlobalScheme().getColor(COLOR_KEY);
public PySciViewAction() {
super(TEXT_SCI_VIEW);
}
@Override
public boolean isSelected(AnActionEvent e) {
return e.getProject() != null && PySciProjectComponent.getInstance(e.getProject()).useSciView();
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
final Project project = e.getProject();
if (project == null) return;
PySciProjectComponent.getInstance(project).useSciView(state);
final PsiElement element = getPsiElement(e, project);
if (state) {
showConsoleToolwindow(project);
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);
}
}
private static void showCommandLineInRunConfiguration(Project project, boolean show) {
final RunnerAndConfigurationSettings template =
RunManager.getInstance(project).getConfigurationTemplate(PythonConfigurationType.getInstance().getFactory());
final RunConfiguration configuration = template.getConfiguration();
if (configuration instanceof PythonRunConfiguration) {
((PythonRunConfiguration)configuration).setShowCommandLineAfterwards(show);
}
}
private void showConsoleToolwindow(@NotNull final Project project) {
final ToolWindow consoleToolWindow = PythonConsoleToolWindow.getInstance(project).getToolWindow();
wasConsoleVisible = consoleToolWindow.isVisible();
consoleToolWindow.show(null);
}
private void hideConsoleToolwindow(@NotNull final Project project) {
if (!wasConsoleVisible) {
PythonConsoleToolWindow.getInstance(project).getToolWindow().hide(null);
}
}
private void showDocumentationToolwindow(Project project, PsiElement element) {
final String showInToolWindowProperty = DocumentationManager.getInstance(project).getShowInToolWindowProperty();
EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
myDocumentationBackgroundColor = scheme.getColor(COLOR_KEY);
scheme.setColor(COLOR_KEY, UIUtil.getEditorPaneBackground());
PropertiesComponent.getInstance().setValue(showInToolWindowProperty, true);
PropertiesComponent.getInstance().setValue(DocumentationManager.getInstance(project).getAutoUpdateEnabledProperty(), true);
if (element != null) {
DocumentationManager.getInstance(project).showJavaDocInfo(element, element);
}
setDocFontSize();
final ToolWindow window = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.DOCUMENTATION);
if (window != null) {
window.setAnchor(ToolWindowAnchor.RIGHT, null);
myDocumentationType = window.getType();
myDocumentationAutoHide = window.isAutoHide();
window.setType(ToolWindowType.DOCKED, null);
window.setAutoHide(false);
}
}
private static void setDocFontSize() {
EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
final int editorFontSize = scheme.getEditorFontSize();
final FontSize[] values = FontSize.values();
FontSize fontSize = FontSize.MEDIUM;
for (FontSize value : values) {
if (value.getSize() > editorFontSize) {
break;
}
fontSize = value;
}
PropertiesComponent.getInstance().setValue(QUICK_DOC_FONT_SIZE_PROPERTY, String.valueOf(fontSize.toString()));
}
private void restoreDocumentationPopup(Project project) {
PropertiesComponent.getInstance().setValue(DocumentationManager.getInstance(project).getAutoUpdateEnabledProperty(), false);
EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
scheme.setColor(COLOR_KEY, myDocumentationBackgroundColor);
final ToolWindow window = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.DOCUMENTATION);
if (window != null) {
window.setType(myDocumentationType, null);
window.setAutoHide(myDocumentationAutoHide);
DocumentationManager.getInstance(project).restorePopupBehavior();
final JBPopup hint = DocumentationManager.getInstance(project).getDocInfoHint();
if (hint != null) {
hint.cancel();
}
}
}
private void showDataViewAsToolwindow(@NotNull final Project project) {
ToolWindow dataViewToolWindow = ToolWindowManager.getInstance(project).getToolWindow(DATA_VIEWER_ID);
myDataViewType = dataViewToolWindow.getType();
dataViewToolWindow.setType(ToolWindowType.DOCKED, null);
dataViewToolWindow.setAutoHide(false);
dataViewToolWindow.setShowStripeButton(true);
}
private void hideDataViewer(Project project) {
final ToolWindow dataViewer = ToolWindowManager.getInstance(project).getToolWindow(DATA_VIEWER_ID);
dataViewer.setType(myDataViewType, null);
dataViewer.setAutoHide(true);
dataViewer.setShowStripeButton(false);
}
private static PsiElement getPsiElement(AnActionEvent e, Project project) {
PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(e.getDataContext());
if (element == null) {
element = CommonDataKeys.PSI_FILE.getData(e.getDataContext());
}
if (element == null) {
element = PsiManager.getInstance(project).findDirectory(project.getBaseDir());
}
return element;
}
@Override
public void update(@NotNull AnActionEvent e) {
super.update(e);
final Project project = e.getProject();
final Presentation presentation = e.getPresentation();
presentation.setEnabledAndVisible(project != null);
}
}
@@ -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());
}
@@ -95,6 +95,7 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable
private XStandaloneVariablesView mySplitView;
private ActionCallback myInitialized = new ActionCallback();
private boolean isShowVars = true;
public PythonConsoleView(final Project project, final String title, final Sdk sdk) {
super(project, title, PythonLanguage.getInstance());
@@ -115,6 +116,10 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable
public void setConsoleCommunication(final ConsoleCommunication communication) {
getFile().putCopyableUserData(PydevConsoleRunner.CONSOLE_KEY, communication);
if (isShowVars && communication instanceof PydevConsoleCommunication) {
showVariables((PydevConsoleCommunication)communication);
}
}
private PyConsoleStartFolding createConsoleFolding() {
@@ -491,4 +496,12 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable
public void initialized() {
myInitialized.setDone();
}
public void setShowVars(boolean showVars) {
isShowVars = showVars;
}
public boolean isShowVars() {
return isShowVars;
}
}
@@ -26,16 +26,15 @@ import com.jetbrains.python.console.PythonConsoleView
* Created by Yuli Fiterman on 9/18/2016.
*/
class ShowVarsAction(private val consoleView: PythonConsoleView, private val consoleComm: PydevConsoleCommunication) : ToggleAction("Show Variables", "Shows active console variables", AllIcons.Debugger.Watches), DumbAware {
private var mySelected = false
override fun isSelected(e: AnActionEvent): Boolean {
return mySelected
return consoleView.isShowVars
}
override fun setSelected(e: AnActionEvent, state: Boolean) {
mySelected = state
consoleView.isShowVars = state
if (mySelected) {
if (state) {
consoleView.showVariables(consoleComm)
}
else {
@@ -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,22 @@ 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.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
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 +56,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 +107,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 +453,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
@@ -489,9 +549,27 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
public PsiElement getCustomDocumentationElement(@NotNull Editor editor,
@NotNull PsiFile file,
@Nullable PsiElement contextElement) {
if (contextElement != null &&
PythonDialectsTokenSetProvider.INSTANCE.getKeywordTokens().contains(contextElement.getNode().getElementType())) {
return contextElement;
if (contextElement != null) {
final IElementType elementType = contextElement.getNode().getElementType();
if (PythonDialectsTokenSetProvider.INSTANCE.getKeywordTokens().contains(elementType)) {
return contextElement;
}
if (PyTokenTypes.LPAR == elementType || PyTokenTypes.RPAR == elementType) {
final PyCallExpression expression = PsiTreeUtil.getParentOfType(contextElement, PyCallExpression.class);
if (expression != null) {
final PyExpression callee = expression.getCallee();
if (callee != null) {
final PsiReference reference = callee.getReference();
if (reference != null) {
return reference.resolve();
}
}
}
}
if (PyTokenTypes.DOCSTRING == elementType) {
final PyDocStringOwner docstringOwner = PsiTreeUtil.getParentOfType(contextElement, PyDocStringOwner.class);
if (docstringOwner != null) return docstringOwner;
}
}
return super.getCustomDocumentationElement(editor, file, contextElement);
}
@@ -588,6 +588,10 @@ public class PyTargetExpressionImpl extends PyBaseElementImpl<PyTargetExpression
}
}
}
final PyImportElement importElement = PsiTreeUtil.getParentOfType(this, PyImportElement.class);
if (importElement != null) {
return importElement.getImportReferenceExpression();
}
return null;
}
@@ -19,11 +19,9 @@ import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.*;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizerUtil;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.io.FileUtil;
@@ -0,0 +1 @@
<html><body><code>def <b>foo</b>()<br>Inferred&nbsp;type:&nbsp;()&nbsp;-&gt;&nbsp;None<br><br>Doc&nbsp;of&nbsp;foo.</code></body></html>
+6
View File
@@ -0,0 +1,6 @@
# directly in function
def foo():
"<the_doc>Doc of foo."
pass
foo(<the_ref>)
+1 -1
View File
@@ -1 +1 @@
<html><body><code>def <b>len</b>(o:&nbsp;Sized)<br>Inferred&nbsp;type:&nbsp;(o:&nbsp;Sized)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#int">int</a><br><br><br>len(object)&nbsp;-&gt;&nbsp;integer<br><br>Return&nbsp;the&nbsp;number&nbsp;of&nbsp;items&nbsp;of&nbsp;a&nbsp;sequence&nbsp;or&nbsp;collection.<br></code><br><b>External documentation:</b><br><a href="http://docs.python.org/2.7 Mock SDK/library/__builtin__.html#__builtin__.len">http://docs.python.org/2.7 Mock SDK/library/__builtin__.html#__builtin__.len</a></body></html>
<html><body><code>def <b>len</b>(o:&nbsp;Sized)<br>Inferred&nbsp;type:&nbsp;(o:&nbsp;Sized)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#int">int</a><br><br><br>len(object)&nbsp;-&gt;&nbsp;integer<br><br>Return&nbsp;the&nbsp;number&nbsp;of&nbsp;items&nbsp;of&nbsp;a&nbsp;sequence&nbsp;or&nbsp;collection.<br></code></body></html>
+1
View File
@@ -0,0 +1 @@
<html><body><code>def <b>foo</b>()<br>Inferred&nbsp;type:&nbsp;()&nbsp;-&gt;&nbsp;None<br><br>Doc&nbsp;of&nbsp;foo.</code></body></html>
+6
View File
@@ -0,0 +1,6 @@
# directly in function
def foo():
"<the_doc>Doc of <the_ref>foo."
pass
foo()
@@ -292,6 +292,22 @@ public class PyQuickDocTest extends LightMarkedTestCase {
checkHTMLOnly();
}
public void testArgumentList() {
Map<String, PsiElement> marks = loadTest();
final PsiElement originalElement = marks.get("<the_ref>");
final PsiElement element = myProvider.getCustomDocumentationElement(myFixture.getEditor(), myFile, originalElement);
checkByHTML(myProvider.generateDoc(element, originalElement));
}
public void testDocstring() {
Map<String, PsiElement> marks = loadTest();
final PsiElement originalElement = marks.get("<the_ref>");
final PsiElement element = myProvider.getCustomDocumentationElement(myFixture.getEditor(), myFile, originalElement);
checkByHTML(myProvider.generateDoc(element, originalElement));
}
public void testReferenceToMethodQualifiedWithInstance() {
checkHTMLOnly();
}