From ff193191d39ad8aa18fad5678f2cb9dc25e07682 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Tue, 22 Aug 2017 21:05:35 +0300 Subject: [PATCH 01/14] action to switch to scientific view in pycharm - part of PY-23595 - documentation docked on the right - documentation is auto updated from source - data view as toolwindow is shown only in scientific view - console is opened - restore scientific view after restart --- .../documentation/DockablePopupManager.java | 8 +- .../documentation/DocumentationManager.java | 2 +- python/src/META-INF/python-core-common.xml | 10 ++ .../python/actions/PySciProjectComponent.java | 151 ++++++++++++++++++ .../python/actions/PySciViewAction.java | 151 ++++++++++++++++++ .../python/console/PythonConsoleView.java | 13 ++ .../python/console/actions/ShowVarsAction.kt | 7 +- 7 files changed, 332 insertions(+), 10 deletions(-) create mode 100644 python/src/com/jetbrains/python/actions/PySciProjectComponent.java create mode 100644 python/src/com/jetbrains/python/actions/PySciViewAction.java diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DockablePopupManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DockablePopupManager.java index 5881498247f7..f0cdd35e6ffd 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DockablePopupManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DockablePopupManager.java @@ -47,7 +47,6 @@ import java.awt.*; public abstract class DockablePopupManager { 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 { 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 { 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 { } - protected void restorePopupBehavior() { + public void restorePopupBehavior() { if (myToolWindow != null) { PropertiesComponent.getInstance().setValue(getShowInToolWindowProperty(), Boolean.FALSE.toString()); ToolWindowManagerEx toolWindowManagerEx = ToolWindowManagerEx.getInstanceEx(myProject); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java index 4943255ec236..a00286221c87 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java @@ -145,7 +145,7 @@ public class DocumentationManager extends DockablePopupManager + + + + @@ -867,6 +871,12 @@ + + + com.jetbrains.python.actions.PySciProjectComponent + + + com.jetbrains.python.testing.VFSTestFrameworkListener diff --git a/python/src/com/jetbrains/python/actions/PySciProjectComponent.java b/python/src/com/jetbrains/python/actions/PySciProjectComponent.java new file mode 100644 index 000000000000..38d8ff0b95c9 --- /dev/null +++ b/python/src/com/jetbrains/python/actions/PySciProjectComponent.java @@ -0,0 +1,151 @@ +/* + * 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.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.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.jetbrains.python.actions.PySciViewAction.ACTION_ID; + +@State(name = "PySciProjectComponent", storages = @Storage("other.xml")) +public class PySciProjectComponent extends AbstractProjectComponent implements PersistentStateComponent { + 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(() -> { + 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 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." + + "
Would you like to enable Scientific View?
" + + "Yes  No"; + 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; + } +} diff --git a/python/src/com/jetbrains/python/actions/PySciViewAction.java b/python/src/com/jetbrains/python/actions/PySciViewAction.java new file mode 100644 index 000000000000..a885cbf09895 --- /dev/null +++ b/python/src/com/jetbrains/python/actions/PySciViewAction.java @@ -0,0 +1,151 @@ +/* + * 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.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.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.jetbrains.python.console.PythonConsoleToolWindow; +import org.jetbrains.annotations.NotNull; + +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; + + 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); + } + else { + hideConsoleToolwindow(project); + restoreDocumentationPopup(project); + hideDataViewer(project); + } + } + + 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(); + + PropertiesComponent.getInstance().setValue(showInToolWindowProperty, true); + PropertiesComponent.getInstance().setValue(DocumentationManager.getInstance(project).getAutoUpdateEnabledProperty(), true); + + if (element != null) { + DocumentationManager.getInstance(project).showJavaDocInfo(element, element); + } + 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 void restoreDocumentationPopup(Project project) { + PropertiesComponent.getInstance().setValue(DocumentationManager.getInstance(project).getAutoUpdateEnabledProperty(), false); + + 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.setShowStripeButton(true); + } + + private void hideDataViewer(Project project) { + final ToolWindow dataViewer = ToolWindowManager.getInstance(project).getToolWindow(DATA_VIEWER_ID); + dataViewer.setType(myDataViewType, null); + 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); + } +} diff --git a/python/src/com/jetbrains/python/console/PythonConsoleView.java b/python/src/com/jetbrains/python/console/PythonConsoleView.java index c84deff5f118..10c6fe539502 100644 --- a/python/src/com/jetbrains/python/console/PythonConsoleView.java +++ b/python/src/com/jetbrains/python/console/PythonConsoleView.java @@ -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; + } } diff --git a/python/src/com/jetbrains/python/console/actions/ShowVarsAction.kt b/python/src/com/jetbrains/python/console/actions/ShowVarsAction.kt index 5485784d8110..a1bdc155040c 100644 --- a/python/src/com/jetbrains/python/console/actions/ShowVarsAction.kt +++ b/python/src/com/jetbrains/python/console/actions/ShowVarsAction.kt @@ -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 { From df4dd29135789842e565c9b34526f3ba1a35de4f Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Tue, 22 Aug 2017 21:10:26 +0300 Subject: [PATCH 02/14] proper color for documentation background --- .../python/actions/PySciProjectComponent.java | 7 +++++++ .../jetbrains/python/actions/PySciViewAction.java | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/python/src/com/jetbrains/python/actions/PySciProjectComponent.java b/python/src/com/jetbrains/python/actions/PySciProjectComponent.java index 38d8ff0b95c9..206e892da398 100644 --- a/python/src/com/jetbrains/python/actions/PySciProjectComponent.java +++ b/python/src/com/jetbrains/python/actions/PySciProjectComponent.java @@ -29,6 +29,8 @@ 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; @@ -36,6 +38,7 @@ 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; @@ -44,6 +47,7 @@ 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")) @@ -73,6 +77,9 @@ public class PySciProjectComponent extends AbstractProjectComponent implements P 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); diff --git a/python/src/com/jetbrains/python/actions/PySciViewAction.java b/python/src/com/jetbrains/python/actions/PySciViewAction.java index a885cbf09895..0fc149ae3727 100644 --- a/python/src/com/jetbrains/python/actions/PySciViewAction.java +++ b/python/src/com/jetbrains/python/actions/PySciViewAction.java @@ -21,15 +21,21 @@ 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.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 org.jetbrains.annotations.NotNull; +import java.awt.*; + +import static com.intellij.codeInsight.documentation.DocumentationComponent.COLOR_KEY; import static com.jetbrains.python.debugger.containerview.PyDataView.DATA_VIEWER_ID; public class PySciViewAction extends ToggleAction implements DumbAware { @@ -41,6 +47,7 @@ public class PySciViewAction extends ToggleAction implements DumbAware { public static final String ACTION_ID = "PySciView"; private ToolWindowType myDataViewType = ToolWindowType.FLOATING; + private Color myDocumentationBackgroundColor; public PySciViewAction() { super(TEXT_SCI_VIEW); @@ -86,6 +93,10 @@ public class PySciViewAction extends ToggleAction implements DumbAware { 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); @@ -104,6 +115,8 @@ public class PySciViewAction extends ToggleAction implements DumbAware { 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) { From 236c97fcf0ff67b007aa748970ce04628cdae56d Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Tue, 22 Aug 2017 21:11:04 +0300 Subject: [PATCH 03/14] do not autohide data view toolwindow in sci mode --- python/src/com/jetbrains/python/actions/PySciViewAction.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/actions/PySciViewAction.java b/python/src/com/jetbrains/python/actions/PySciViewAction.java index 0fc149ae3727..c131e911af75 100644 --- a/python/src/com/jetbrains/python/actions/PySciViewAction.java +++ b/python/src/com/jetbrains/python/actions/PySciViewAction.java @@ -47,7 +47,7 @@ public class PySciViewAction extends ToggleAction implements DumbAware { public static final String ACTION_ID = "PySciView"; private ToolWindowType myDataViewType = ToolWindowType.FLOATING; - private Color myDocumentationBackgroundColor; + private Color myDocumentationBackgroundColor = EditorColorsManager.getInstance().getGlobalScheme().getColor(COLOR_KEY); public PySciViewAction() { super(TEXT_SCI_VIEW); @@ -134,12 +134,14 @@ public class PySciViewAction extends ToggleAction implements DumbAware { 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); } From 696e1f3530bd08874d2cf076b486621276d9e90f Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Tue, 22 Aug 2017 21:11:33 +0300 Subject: [PATCH 04/14] set nearest font size for the documentation toolwindow --- .../documentation/DocumentationComponent.java | 2 +- .../python/actions/PySciViewAction.java | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java index 0e695ee8c1ca..df91737f02f5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java @@ -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 myBackStack = new Stack<>(); private final Stack myForwardStack = new Stack<>(); diff --git a/python/src/com/jetbrains/python/actions/PySciViewAction.java b/python/src/com/jetbrains/python/actions/PySciViewAction.java index c131e911af75..7e2273719dff 100644 --- a/python/src/com/jetbrains/python/actions/PySciViewAction.java +++ b/python/src/com/jetbrains/python/actions/PySciViewAction.java @@ -23,6 +23,7 @@ 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.options.FontSize; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopup; @@ -36,6 +37,7 @@ 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 { @@ -103,6 +105,8 @@ public class PySciViewAction extends ToggleAction implements DumbAware { 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); @@ -113,6 +117,21 @@ public class PySciViewAction extends ToggleAction implements DumbAware { } } + 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(); From 50376fdaf3c14d2bc24d8279c02817c247cc60ad Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Tue, 22 Aug 2017 21:11:57 +0300 Subject: [PATCH 05/14] turn on/off show command line afterwards in scientific mode --- .../python/actions/PySciViewAction.java | 16 ++++++++++++++++ .../python/run/PythonRunConfiguration.java | 2 -- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/python/src/com/jetbrains/python/actions/PySciViewAction.java b/python/src/com/jetbrains/python/actions/PySciViewAction.java index 7e2273719dff..eb900f63169c 100644 --- a/python/src/com/jetbrains/python/actions/PySciViewAction.java +++ b/python/src/com/jetbrains/python/actions/PySciViewAction.java @@ -16,6 +16,9 @@ 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; @@ -32,6 +35,8 @@ 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.run.PythonConfigurationType; +import com.jetbrains.python.run.PythonRunConfiguration; import org.jetbrains.annotations.NotNull; import java.awt.*; @@ -72,11 +77,22 @@ public class PySciViewAction extends ToggleAction implements DumbAware { showConsoleToolwindow(project); showDocumentationToolwindow(project, element); showDataViewAsToolwindow(project); + showCommandLineInRunConfiguration(project, true); } else { hideConsoleToolwindow(project); restoreDocumentationPopup(project); hideDataViewer(project); + showCommandLineInRunConfiguration(project, false); + } + } + + 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); } } diff --git a/python/src/com/jetbrains/python/run/PythonRunConfiguration.java b/python/src/com/jetbrains/python/run/PythonRunConfiguration.java index 0a86309dd5cd..ca1d42f6a9a1 100644 --- a/python/src/com/jetbrains/python/run/PythonRunConfiguration.java +++ b/python/src/com/jetbrains/python/run/PythonRunConfiguration.java @@ -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; From 3c7bd8a29285acb903bdda07810f457b651c7614 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 23 Aug 2017 14:03:04 +0300 Subject: [PATCH 06/14] add run file in console action for python --- python/src/META-INF/python-core-common.xml | 4 + .../actions/PyRunFileInConsoleAction.java | 73 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 python/src/com/jetbrains/python/actions/PyRunFileInConsoleAction.java diff --git a/python/src/META-INF/python-core-common.xml b/python/src/META-INF/python-core-common.xml index 921f601e99b6..6b1921eb801c 100644 --- a/python/src/META-INF/python-core-common.xml +++ b/python/src/META-INF/python-core-common.xml @@ -809,6 +809,10 @@ + + + + diff --git a/python/src/com/jetbrains/python/actions/PyRunFileInConsoleAction.java b/python/src/com/jetbrains/python/actions/PyRunFileInConsoleAction.java new file mode 100644 index 000000000000..d0817b6a0fd2 --- /dev/null +++ b/python/src/com/jetbrains/python/actions/PyRunFileInConsoleAction.java @@ -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()); + } + } +} From aa9f4ff2a98b073848113a63fd0299b5effc39b6 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Wed, 30 Aug 2017 18:31:57 +0300 Subject: [PATCH 07/14] load and render python stdlib in scientific mode --- python/python-community.iml | 13 +++- .../python/actions/PySciViewAction.java | 12 ++++ .../PyStdlibDocumentationLinkProvider.java | 3 +- .../PyIntegratedToolsConfigurable.form | 10 ++- .../PyIntegratedToolsConfigurable.java | 8 ++- .../PyDocumentationSettings.java | 9 +++ .../PythonDocumentationProvider.java | 62 ++++++++++++++++++- 7 files changed, 110 insertions(+), 7 deletions(-) diff --git a/python/python-community.iml b/python/python-community.iml index b5f980a97e1a..a1d6fc61d2b9 100644 --- a/python/python-community.iml +++ b/python/python-community.iml @@ -26,6 +26,15 @@ + + + + + + + + + +
- - + \ No newline at end of file diff --git a/python/src/com/jetbrains/python/actions/PySciViewAction.java b/python/src/com/jetbrains/python/actions/PySciViewAction.java index eb900f63169c..33364d0ee0b0 100644 --- a/python/src/com/jetbrains/python/actions/PySciViewAction.java +++ b/python/src/com/jetbrains/python/actions/PySciViewAction.java @@ -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); } } diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibDocumentationLinkProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibDocumentationLinkProvider.java index e982087327e5..9325337c3ecc 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibDocumentationLinkProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibDocumentationLinkProvider.java @@ -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(); diff --git a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form index 5aacd414fb03..50e117174f63 100644 --- a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form +++ b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form @@ -49,7 +49,7 @@ - + @@ -82,6 +82,14 @@ + + + + + + + + diff --git a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java index dc3d88ca5cd3..c519eda530ce 100644 --- a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java +++ b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java @@ -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()); } diff --git a/python/src/com/jetbrains/python/documentation/PyDocumentationSettings.java b/python/src/com/jetbrains/python/documentation/PyDocumentationSettings.java index fd43b67011b1..9e21a47b6c43 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocumentationSettings.java +++ b/python/src/com/jetbrains/python/documentation/PyDocumentationSettings.java @@ -47,6 +47,7 @@ public class PyDocumentationSettings implements PersistentStateComponent docUrls) { - return null; + final Module module = ModuleUtilCore.findModuleForPsiElement(element); + if (module != null && !PyDocumentationSettings.getInstance(module).isRenderExternalDocumentation()) return null; + return ApplicationManager.getApplication().runReadAction((Computable)() -> { + 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 From bbf700400bbf88a1892472f191a970021cfce857 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 31 Aug 2017 12:28:25 +0300 Subject: [PATCH 08/14] build python function description with better attributes --- .../jetbrains/python/documentation/PyDocumentationBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java index 45bf3783cef2..8f38aff20ce2 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java @@ -79,7 +79,7 @@ public class PyDocumentationBuilder { myBody = new ChainIterable<>(); myEpilog = new ChainIterable<>(); - myResult.add(myProlog).addWith(TagCode, myBody).add(myEpilog); // pre-assemble; then add stuff to individual cats as needed + myResult.add(myProlog).addWith(TagCode.withAttribute("class", "descclassname"), myBody).add(myEpilog); // pre-assemble; then add stuff to individual cats as needed myResult = wrapInTag("html", wrapInTag("body", myResult)); myReassignmentChain = new ChainIterable<>(); } From fadfcaab3624b1380c45b6618c5bc1f9ca81c63c Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 31 Aug 2017 14:12:43 +0300 Subject: [PATCH 09/14] do not wrap code in additional attribute --- .../jetbrains/python/documentation/PyDocumentationBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java index 8f38aff20ce2..45bf3783cef2 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java @@ -79,7 +79,7 @@ public class PyDocumentationBuilder { myBody = new ChainIterable<>(); myEpilog = new ChainIterable<>(); - myResult.add(myProlog).addWith(TagCode.withAttribute("class", "descclassname"), myBody).add(myEpilog); // pre-assemble; then add stuff to individual cats as needed + myResult.add(myProlog).addWith(TagCode, myBody).add(myEpilog); // pre-assemble; then add stuff to individual cats as needed myResult = wrapInTag("html", wrapInTag("body", myResult)); myReassignmentChain = new ChainIterable<>(); } From 8116bf7c1ca173ffbc02050258c64507802f728f Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 31 Aug 2017 14:13:24 +0300 Subject: [PATCH 10/14] PY-25778 Show documentation on import target expression --- .../com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java index 8a1a518df04e..3013196c011d 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java @@ -588,6 +588,10 @@ public class PyTargetExpressionImpl extends PyBaseElementImpl Date: Thu, 31 Aug 2017 15:12:00 +0300 Subject: [PATCH 11/14] PY-25779 Show documentation for method if caret is placed inside parameters list --- .../PythonDocumentationProvider.java | 22 ++++++++++++++++--- python/testData/quickdoc/ArgumentList.html | 1 + python/testData/quickdoc/ArgumentList.py | 6 +++++ python/testData/quickdoc/BuiltinLen.html | 2 +- .../com/jetbrains/python/PyQuickDocTest.java | 8 +++++++ 5 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 python/testData/quickdoc/ArgumentList.html create mode 100644 python/testData/quickdoc/ArgumentList.py diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index bb32343dda0d..2c3758a0946d 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -31,9 +31,11 @@ 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; @@ -547,9 +549,23 @@ 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(); + } + } + } + } } return super.getCustomDocumentationElement(editor, file, contextElement); } diff --git a/python/testData/quickdoc/ArgumentList.html b/python/testData/quickdoc/ArgumentList.html new file mode 100644 index 000000000000..e4cfe0fd4e36 --- /dev/null +++ b/python/testData/quickdoc/ArgumentList.html @@ -0,0 +1 @@ +def foo()
Inferred type: () -> None

Doc of foo.
\ No newline at end of file diff --git a/python/testData/quickdoc/ArgumentList.py b/python/testData/quickdoc/ArgumentList.py new file mode 100644 index 000000000000..6aff48527784 --- /dev/null +++ b/python/testData/quickdoc/ArgumentList.py @@ -0,0 +1,6 @@ +# directly in function +def foo(): + "Doc of foo." + pass + +foo() diff --git a/python/testData/quickdoc/BuiltinLen.html b/python/testData/quickdoc/BuiltinLen.html index db51bb72f7e6..805ad69fbbd3 100644 --- a/python/testData/quickdoc/BuiltinLen.html +++ b/python/testData/quickdoc/BuiltinLen.html @@ -1 +1 @@ -def len(o: Sized)
Inferred type: (o: Sized) -> int


len(object) -> integer

Return the number of items of a sequence or collection.

External documentation:
http://docs.python.org/2.7 Mock SDK/library/__builtin__.html#__builtin__.len +def len(o: Sized)
Inferred type: (o: Sized) -> int


len(object) -> integer

Return the number of items of a sequence or collection.
diff --git a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java index 1e7823e065f5..ce5ae9d67346 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java @@ -292,6 +292,14 @@ public class PyQuickDocTest extends LightMarkedTestCase { checkHTMLOnly(); } + public void testArgumentList() { + Map marks = loadTest(); + final PsiElement originalElement = marks.get(""); + + final PsiElement element = myProvider.getCustomDocumentationElement(myFixture.getEditor(), myFile, originalElement); + checkByHTML(myProvider.generateDoc(element, originalElement)); + } + public void testReferenceToMethodQualifiedWithInstance() { checkHTMLOnly(); } From 99c0e6c3f40068ce1c3853590fcdc3f8fe2144da Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 31 Aug 2017 15:17:25 +0300 Subject: [PATCH 12/14] PY-24854 Allow Quick Documentation invocation when caret is placed inside docstring --- .../python/documentation/PythonDocumentationProvider.java | 4 ++++ python/testData/quickdoc/Docstring.html | 1 + python/testData/quickdoc/Docstring.py | 6 ++++++ python/testSrc/com/jetbrains/python/PyQuickDocTest.java | 8 ++++++++ 4 files changed, 19 insertions(+) create mode 100644 python/testData/quickdoc/Docstring.html create mode 100644 python/testData/quickdoc/Docstring.py diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index 2c3758a0946d..565b39361545 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -566,6 +566,10 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i } } } + if (PyTokenTypes.DOCSTRING == elementType) { + final PyDocStringOwner docstringOwner = PsiTreeUtil.getParentOfType(contextElement, PyDocStringOwner.class); + if (docstringOwner != null) return docstringOwner; + } } return super.getCustomDocumentationElement(editor, file, contextElement); } diff --git a/python/testData/quickdoc/Docstring.html b/python/testData/quickdoc/Docstring.html new file mode 100644 index 000000000000..e4cfe0fd4e36 --- /dev/null +++ b/python/testData/quickdoc/Docstring.html @@ -0,0 +1 @@ +def foo()
Inferred type: () -> None

Doc of foo.
\ No newline at end of file diff --git a/python/testData/quickdoc/Docstring.py b/python/testData/quickdoc/Docstring.py new file mode 100644 index 000000000000..a703742ebbb4 --- /dev/null +++ b/python/testData/quickdoc/Docstring.py @@ -0,0 +1,6 @@ +# directly in function +def foo(): + "Doc of foo." + pass + +foo() diff --git a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java index ce5ae9d67346..8f0599d55795 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java @@ -300,6 +300,14 @@ public class PyQuickDocTest extends LightMarkedTestCase { checkByHTML(myProvider.generateDoc(element, originalElement)); } + public void testDocstring() { + Map marks = loadTest(); + final PsiElement originalElement = marks.get(""); + + final PsiElement element = myProvider.getCustomDocumentationElement(myFixture.getEditor(), myFile, originalElement); + checkByHTML(myProvider.generateDoc(element, originalElement)); + } + public void testReferenceToMethodQualifiedWithInstance() { checkHTMLOnly(); } From 6fdfa74facd311318bc0527325dbbaf0f3c2bed2 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 1 Sep 2017 17:30:01 +0700 Subject: [PATCH 13/14] LiveVariablesAnalyzer#findLiveVars: clone or'ed BitSet as well We should ensure that runDFA lambda never returns an object which will be mutated afterwards as this object used as part of `processed` Set key (inside InstructionState). --- .../codeInspection/dataFlow/LiveVariablesAnalyzer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java index 0c559889e31d..18f2f5f36fc0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java @@ -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()); } } From ac1016dc32993314a866b22c6261e5c058b07684 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Fri, 1 Sep 2017 13:36:53 +0300 Subject: [PATCH 14/14] don't forget to cleanup whitespaces/newline keys (WEB-24694) --- .../configmanagement/DocumentSettingsManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/editorconfig/src/org/editorconfig/configmanagement/DocumentSettingsManager.java b/plugins/editorconfig/src/org/editorconfig/configmanagement/DocumentSettingsManager.java index 61246f56fbb5..166961f61c1e 100644 --- a/plugins/editorconfig/src/org/editorconfig/configmanagement/DocumentSettingsManager.java +++ b/plugins/editorconfig/src/org/editorconfig/configmanagement/DocumentSettingsManager.java @@ -72,7 +72,10 @@ public class DocumentSettingsManager extends FileDocumentManagerAdapter { private void applyConfigValueToUserData(VirtualFile file, Key userDataKey, String editorConfigKey, String configValue, Map configMap) { - if (configValue.isEmpty()) return; + if (configValue.isEmpty()) { + file.putUserData(userDataKey, null); + return; + } final T data = configMap.get(configValue); if (data == null) {