From 941d484330d52d79cd2f1bcb3941337c41b9e0f0 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Tue, 21 Jul 2015 13:40:58 +0300 Subject: [PATCH 01/16] always stop on the first line in debug Added custom executor to make canRun method in pyDebugRunner return false. Also it can be useful to replace debug tool window with custom tool window --- python/edu/src/META-INF/PyCharmEduPlugin.xml | 3 + .../edu/PyCharmEduInitialConfigurator.java | 18 ++++++ .../python/edu/PyDebugCurrentFileAction.java | 22 +++++++ .../edu/PyDebugFileLineMarkerProvider.java | 53 +++++++++++++++ .../python/edu/PyEduDebugExecutor.java | 31 +++++++++ .../python/edu/PyEduDebugRunner.java | 64 +++++++++++++++++++ .../com/jetbrains/python/edu/PyEduUtils.java | 33 ++++++++++ .../edu/PyExecuteFileLineMarkerProvider.java | 30 +-------- .../edu/PyRunConfigurationForFileAction.java | 51 +++++++++++++++ .../python/edu/PyRunCurrentFileAction.java | 40 ++---------- .../python/debugger/PyDebugRunner.java | 19 ++++-- 11 files changed, 294 insertions(+), 70 deletions(-) create mode 100644 python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFileAction.java create mode 100644 python/edu/src/com/jetbrains/python/edu/PyDebugFileLineMarkerProvider.java create mode 100644 python/edu/src/com/jetbrains/python/edu/PyEduDebugExecutor.java create mode 100644 python/edu/src/com/jetbrains/python/edu/PyEduDebugRunner.java create mode 100644 python/edu/src/com/jetbrains/python/edu/PyEduUtils.java create mode 100644 python/edu/src/com/jetbrains/python/edu/PyRunConfigurationForFileAction.java diff --git a/python/edu/src/META-INF/PyCharmEduPlugin.xml b/python/edu/src/META-INF/PyCharmEduPlugin.xml index d19b2cca1a67..38415ba90f2d 100644 --- a/python/edu/src/META-INF/PyCharmEduPlugin.xml +++ b/python/edu/src/META-INF/PyCharmEduPlugin.xml @@ -28,7 +28,10 @@ + + + diff --git a/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java b/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java index e8476ac7f78f..e0dc6544aaa0 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java +++ b/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java @@ -19,6 +19,9 @@ import com.google.common.collect.Sets; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.intention.IntentionActionBean; import com.intellij.codeInsight.intention.IntentionManager; +import com.intellij.execution.Executor; +import com.intellij.execution.ExecutorRegistryImpl; +import com.intellij.execution.executors.DefaultDebugExecutor; import com.intellij.ide.AppLifecycleListener; import com.intellij.ide.GeneralSettings; import com.intellij.ide.RecentProjectsManager; @@ -27,6 +30,9 @@ import com.intellij.ide.ui.UISettings; import com.intellij.ide.util.PropertiesComponent; import com.intellij.ide.util.TipAndTrickBean; import com.intellij.notification.EventLog; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; import com.intellij.openapi.extensions.Extensions; @@ -210,6 +216,9 @@ public class PyCharmEduInitialConfigurator { } private static void patchProjectAreaExtensions(@NotNull final Project project) { + Executor debugExecutor = DefaultDebugExecutor.getDebugExecutorInstance(); + unregisterAction(debugExecutor.getId(), ExecutorRegistryImpl.RUNNERS_GROUP); + unregisterAction(debugExecutor.getContextActionId(), ExecutorRegistryImpl.RUN_CONTEXT_GROUP); for (SelectInTarget target : Extensions.getExtensions(SelectInTarget.EP_NAME, project)) { if (ToolWindowId.FAVORITES_VIEW.equals(target.getToolWindowId())) { Extensions.getArea(project).getExtensionPoint(SelectInTarget.EP_NAME).unregisterExtension(target); @@ -217,6 +226,15 @@ public class PyCharmEduInitialConfigurator { } } + private static void unregisterAction(String actionId, String groupId) { + ActionManager actionManager = ActionManager.getInstance(); + AnAction action = actionManager.getAction(actionId); + if (action != null) { + ((DefaultActionGroup)actionManager.getAction(groupId)).remove(action); + actionManager.unregisterAction(actionId); + } + } + private static void patchKeymap() { Set droppedActions = ContainerUtil.newHashSet( "AddToFavoritesPopup", diff --git a/python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFileAction.java b/python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFileAction.java new file mode 100644 index 000000000000..8e1f394e19c1 --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFileAction.java @@ -0,0 +1,22 @@ +package com.jetbrains.python.edu; + +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.runners.ExecutionUtil; +import com.intellij.icons.AllIcons; + +public class PyDebugCurrentFileAction extends PyRunConfigurationForFileAction { + + public PyDebugCurrentFileAction() { + getTemplatePresentation().setIcon(AllIcons.Actions.StartDebugger); + } + + @Override + protected String getConfigurationType() { + return "Debug"; + } + + @Override + protected void runConfiguration(RunnerAndConfigurationSettings configuration) { + ExecutionUtil.runConfiguration(configuration, PyEduDebugExecutor.getInstance()); + } +} diff --git a/python/edu/src/com/jetbrains/python/edu/PyDebugFileLineMarkerProvider.java b/python/edu/src/com/jetbrains/python/edu/PyDebugFileLineMarkerProvider.java new file mode 100644 index 000000000000..94edd56c730a --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/PyDebugFileLineMarkerProvider.java @@ -0,0 +1,53 @@ +package com.jetbrains.python.edu; + +import com.intellij.codeHighlighting.Pass; +import com.intellij.codeInsight.daemon.GutterIconNavigationHandler; +import com.intellij.codeInsight.daemon.LineMarkerInfo; +import com.intellij.codeInsight.daemon.LineMarkerProvider; +import com.intellij.execution.actions.ConfigurationContext; +import com.intellij.icons.AllIcons; +import com.intellij.ide.DataManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.markup.GutterIconRenderer; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiUtilBase; +import com.intellij.util.Function; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.event.MouseEvent; +import java.util.Collection; +import java.util.List; + +public class PyDebugFileLineMarkerProvider implements LineMarkerProvider { + @Nullable + @Override + public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) { + return null; + } + + @Override + public void collectSlowLineMarkers(@NotNull List elements, @NotNull Collection result) { + for (final PsiElement element : elements) { + if (PyEduUtils.isFirstCodeLine(element)) { + result.add(new LineMarkerInfo(element, element.getTextRange(), AllIcons.Actions.StartDebugger, + Pass.UPDATE_OVERRIDEN_MARKERS, + new Function() { + @Override + public String fun(PsiElement e) { + return "Debug '" + e.getContainingFile().getName() + "'"; + } + }, new GutterIconNavigationHandler() { + @Override + public void navigate(MouseEvent e, PsiElement elt) { + final Editor editor = PsiUtilBase.findEditor(elt); + assert editor != null; + ConfigurationContext configurationContext = + ConfigurationContext.getFromContext(DataManager.getInstance().getDataContext(editor.getComponent())); + new PyDebugCurrentFileAction().run(configurationContext); + } + }, GutterIconRenderer.Alignment.RIGHT)); + } + } + } +} diff --git a/python/edu/src/com/jetbrains/python/edu/PyEduDebugExecutor.java b/python/edu/src/com/jetbrains/python/edu/PyEduDebugExecutor.java new file mode 100644 index 000000000000..69c39f6fa12c --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/PyEduDebugExecutor.java @@ -0,0 +1,31 @@ +package com.jetbrains.python.edu; + +import com.intellij.execution.Executor; +import com.intellij.execution.ExecutorRegistry; +import com.intellij.execution.executors.DefaultDebugExecutor; +import org.jetbrains.annotations.NotNull; + +public class PyEduDebugExecutor extends DefaultDebugExecutor { + public static final String ID = "EduExecutor"; + + @NotNull + @Override + public String getId() { + return ID; + } + + public static Executor getInstance() { + return ExecutorRegistry.getInstance().getExecutorById(ID); + } + + @Override + public String getContextActionId() { + return "EduDebugClass"; + } + + @NotNull + @Override + public String getStartActionText() { + return "Step Through "; + } +} diff --git a/python/edu/src/com/jetbrains/python/edu/PyEduDebugRunner.java b/python/edu/src/com/jetbrains/python/edu/PyEduDebugRunner.java new file mode 100644 index 000000000000..169f1ac9612a --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/PyEduDebugRunner.java @@ -0,0 +1,64 @@ +package com.jetbrains.python.edu; + +import com.intellij.codeInsight.daemon.impl.CollectHighlightsUtil; +import com.intellij.execution.configurations.RunProfile; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.xdebugger.XDebuggerManager; +import com.intellij.xdebugger.breakpoints.XBreakpointManager; +import com.intellij.xdebugger.breakpoints.XBreakpointProperties; +import com.intellij.xdebugger.impl.breakpoints.LineBreakpointState; +import com.intellij.xdebugger.impl.breakpoints.XBreakpointManagerImpl; +import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointImpl; +import com.jetbrains.python.debugger.PyDebugProcess; +import com.jetbrains.python.debugger.PyDebugRunner; +import com.jetbrains.python.debugger.PyLineBreakpointType; +import com.jetbrains.python.debugger.PySourcePosition; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.List; + +public class PyEduDebugRunner extends PyDebugRunner { + + @Override + public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) { + return executorId.equals(PyEduDebugExecutor.ID); + } + + @Override + protected void initDebugProcess(String name, PyDebugProcess pyDebugProcess) { + VirtualFile file = VfsUtil.findFileByIoFile(new File(name), true); + assert file != null; + + final Project project = pyDebugProcess.getProject(); + PsiFile psiFile = PsiManager.getInstance(project).findFile(file); + + assert psiFile != null; + + List psiElements = CollectHighlightsUtil.getElementsInRange(psiFile, 0, psiFile.getTextLength()); + for (PsiElement element : psiElements) { + if (PyEduUtils.isFirstCodeLine(element)) { + int offset = element.getTextRange().getStartOffset(); + Document document = FileDocumentManager.getInstance().getDocument(file); + assert document != null; + int line = document.getLineNumber(offset) + 1; + PySourcePosition sourcePosition = pyDebugProcess.getPositionConverter().create(file.getPath(), line); + XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); + PyLineBreakpointType type = new PyLineBreakpointType(); + XBreakpointProperties properties = type.createBreakpointProperties(file, line); + LineBreakpointState + breakpointState = new LineBreakpointState(true, type.getId(), file.getUrl(), line, false, file.getTimeStamp()); + pyDebugProcess.addBreakpoint(sourcePosition, new XLineBreakpointImpl(type, + ((XBreakpointManagerImpl)breakpointManager), + properties, breakpointState)); + } + } + } +} \ No newline at end of file diff --git a/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java b/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java new file mode 100644 index 000000000000..bdc0d402fa40 --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java @@ -0,0 +1,33 @@ +package com.jetbrains.python.edu; + +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; +import com.jetbrains.python.psi.PyFile; +import com.jetbrains.python.psi.PyImportStatement; +import com.jetbrains.python.psi.PyStatement; + +public class PyEduUtils { + public static boolean isFirstCodeLine(PsiElement element) { + return element instanceof PyStatement && + element.getParent() instanceof PyFile && + !isNothing(element) && + nothingBefore(element); + } + + private static boolean nothingBefore(PsiElement element) { + element = element.getPrevSibling(); + while (element != null) { + if (!isNothing(element)) { + return false; + } + element = element.getPrevSibling(); + } + + return true; + } + + private static boolean isNothing(PsiElement element) { + return (element instanceof PsiComment) || (element instanceof PyImportStatement) || (element instanceof PsiWhiteSpace); + } +} diff --git a/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java b/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java index 0c0208b1f144..e22713dbfa26 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java +++ b/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java @@ -11,14 +11,9 @@ import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.markup.GutterIconRenderer; import com.intellij.openapi.ui.popup.ListPopup; -import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiWhiteSpace; import com.intellij.ui.popup.PopupFactoryImpl; import com.intellij.util.Function; -import com.jetbrains.python.psi.PyFile; -import com.jetbrains.python.psi.PyImportStatement; -import com.jetbrains.python.psi.PyStatement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,7 +33,7 @@ public class PyExecuteFileLineMarkerProvider implements LineMarkerProvider { @Override public void collectSlowLineMarkers(@NotNull List elements, @NotNull Collection result) { for (PsiElement element : elements) { - if (isFirstCodeLine(element)) { + if (PyEduUtils.isFirstCodeLine(element)) { final LineMarkerInfo markerInfo = new LineMarkerInfo( element, element.getTextRange(), AllIcons.Actions.Execute, Pass.UPDATE_OVERRIDEN_MARKERS, new Function() { @@ -100,27 +95,4 @@ public class PyExecuteFileLineMarkerProvider implements LineMarkerProvider { } } } - - private static boolean isFirstCodeLine(PsiElement element) { - return element instanceof PyStatement && - element.getParent() instanceof PyFile && - !isNothing(element) && - nothingBefore(element); - } - - private static boolean nothingBefore(PsiElement element) { - element = element.getPrevSibling(); - while (element != null) { - if (!isNothing(element)) { - return false; - } - element = element.getPrevSibling(); - } - - return true; - } - - private static boolean isNothing(PsiElement element) { - return (element instanceof PsiComment) || (element instanceof PyImportStatement) || (element instanceof PsiWhiteSpace); - } } diff --git a/python/edu/src/com/jetbrains/python/edu/PyRunConfigurationForFileAction.java b/python/edu/src/com/jetbrains/python/edu/PyRunConfigurationForFileAction.java new file mode 100644 index 000000000000..619ebe1c95ba --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/PyRunConfigurationForFileAction.java @@ -0,0 +1,51 @@ +package com.jetbrains.python.edu; + +import com.intellij.execution.Location; +import com.intellij.execution.RunManagerEx; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.actions.ConfigurationContext; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; +import com.jetbrains.python.PythonFileType; +import org.jetbrains.annotations.NotNull; + +public abstract class PyRunConfigurationForFileAction extends AnAction { + + @Override + public void update(AnActionEvent e) { + Presentation presentation = e.getPresentation(); + final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext()); + Location location = context.getLocation(); + if (location != null && location.getPsiElement().getContainingFile() != null && location.getPsiElement().getContainingFile().getFileType() == PythonFileType.INSTANCE) { + presentation.setEnabled(true); + presentation.setText(getConfigurationType() + " '" + location.getPsiElement().getContainingFile().getName() + "'"); + } + } + + protected abstract String getConfigurationType(); + + @Override + public void actionPerformed(AnActionEvent e) { + final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext()); + + run(context); + } + + public void run(@NotNull ConfigurationContext context) { + RunnerAndConfigurationSettings configuration = context.findExisting(); + final RunManagerEx runManager = (RunManagerEx)context.getRunManager(); + if (configuration == null) { + configuration = context.getConfiguration(); + if (configuration == null) { + return; + } + runManager.setTemporaryConfiguration(configuration); + } + runManager.setSelectedConfiguration(configuration); + + runConfiguration(configuration); + } + + protected abstract void runConfiguration(RunnerAndConfigurationSettings configuration); +} diff --git a/python/edu/src/com/jetbrains/python/edu/PyRunCurrentFileAction.java b/python/edu/src/com/jetbrains/python/edu/PyRunCurrentFileAction.java index 4d30fa29a3b3..160bd757884d 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyRunCurrentFileAction.java +++ b/python/edu/src/com/jetbrains/python/edu/PyRunCurrentFileAction.java @@ -1,56 +1,26 @@ package com.jetbrains.python.edu; -import com.intellij.execution.Location; -import com.intellij.execution.RunManagerEx; import com.intellij.execution.RunnerAndConfigurationSettings; -import com.intellij.execution.actions.ConfigurationContext; import com.intellij.execution.executors.DefaultRunExecutor; import com.intellij.execution.runners.ExecutionUtil; import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.Presentation; -import com.jetbrains.python.PythonFileType; -import org.jetbrains.annotations.NotNull; /** * @author traff */ -public class PyRunCurrentFileAction extends AnAction { +public class PyRunCurrentFileAction extends PyRunConfigurationForFileAction { + public PyRunCurrentFileAction() { getTemplatePresentation().setIcon(AllIcons.Actions.Execute); } @Override - public void update(AnActionEvent e) { - Presentation presentation = e.getPresentation(); - final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext()); - Location location = context.getLocation(); - if (location != null && location.getPsiElement().getContainingFile() != null && location.getPsiElement().getContainingFile().getFileType() == PythonFileType.INSTANCE) { - presentation.setEnabled(true); - presentation.setText("Run '" + location.getPsiElement().getContainingFile().getName() + "'"); - } + protected String getConfigurationType() { + return "Run"; } @Override - public void actionPerformed(AnActionEvent e) { - final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext()); - - run(context); - } - - public static void run(@NotNull ConfigurationContext context) { - RunnerAndConfigurationSettings configuration = context.findExisting(); - final RunManagerEx runManager = (RunManagerEx)context.getRunManager(); - if (configuration == null) { - configuration = context.getConfiguration(); - if (configuration == null) { - return; - } - runManager.setTemporaryConfiguration(configuration); - } - runManager.setSelectedConfiguration(configuration); - + protected void runConfiguration(RunnerAndConfigurationSettings configuration) { ExecutionUtil.runConfiguration(configuration, DefaultRunExecutor.getRunExecutorInstance()); } } diff --git a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java index cfe7701e5e0c..abd7f429e5c7 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java @@ -44,6 +44,7 @@ import com.jetbrains.python.console.pydev.ConsoleCommunicationListener; import com.jetbrains.python.run.AbstractPythonRunConfiguration; import com.jetbrains.python.run.CommandLinePatcher; import com.jetbrains.python.run.PythonCommandLineState; +import com.jetbrains.python.run.PythonRunConfiguration; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -81,8 +82,8 @@ public class PyDebugRunner extends GenericProgramRunner { ((AbstractPythonRunConfiguration)profile).canRunWithCoverage(); } - @Override - protected RunContentDescriptor doExecute(@NotNull RunProfileState state, @NotNull final ExecutionEnvironment environment) throws ExecutionException { + + protected XDebugSession createSession(@NotNull RunProfileState state, @NotNull final ExecutionEnvironment environment) throws ExecutionException { FileDocumentManager.getInstance().saveAllDocuments(); final PythonCommandLineState pyState = (PythonCommandLineState)state; @@ -91,7 +92,7 @@ public class PyDebugRunner extends GenericProgramRunner { RunProfile profile = environment.getRunProfile(); final ExecutionResult result = pyState.execute(environment.getExecutor(), createCommandLinePatchers(environment.getProject(), pyState, profile, serverLocalPort)); - final XDebugSession session = XDebuggerManager.getInstance(environment.getProject()). + return XDebuggerManager.getInstance(environment.getProject()). startSession(environment, new XDebugProcessStarter() { @Override @NotNull @@ -101,12 +102,18 @@ public class PyDebugRunner extends GenericProgramRunner { pyState.isMultiprocessDebug()); createConsoleCommunicationAndSetupActions(environment.getProject(), result, pyDebugProcess, session); - - + initDebugProcess(((PythonRunConfiguration)environment.getRunProfile()).getScriptName(), pyDebugProcess); return pyDebugProcess; } }); - return session.getRunContentDescriptor(); + } + + protected void initDebugProcess(String name, PyDebugProcess pyDebugProcess) { + } + + @Override + protected RunContentDescriptor doExecute(@NotNull RunProfileState state, @NotNull final ExecutionEnvironment environment) throws ExecutionException { + return createSession(state, environment).getRunContentDescriptor(); } public static int findIndex(List paramList, String paramName) { From 39313e3fe0d82b25d6f42cab7f0666928369d365 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Thu, 23 Jul 2015 10:44:32 +0300 Subject: [PATCH 02/16] do not try to put breakpoints on docstrings --- .../python/edu/PyEduDebugRunner.java | 39 +++++++++++++++---- .../com/jetbrains/python/edu/PyEduUtils.java | 28 ++++++++----- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/python/edu/src/com/jetbrains/python/edu/PyEduDebugRunner.java b/python/edu/src/com/jetbrains/python/edu/PyEduDebugRunner.java index 169f1ac9612a..32e8fbb38fa9 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyEduDebugRunner.java +++ b/python/edu/src/com/jetbrains/python/edu/PyEduDebugRunner.java @@ -7,9 +7,8 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; +import com.intellij.psi.*; +import com.intellij.util.containers.Predicate; import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.breakpoints.XBreakpointManager; import com.intellij.xdebugger.breakpoints.XBreakpointProperties; @@ -20,13 +19,28 @@ import com.jetbrains.python.debugger.PyDebugProcess; import com.jetbrains.python.debugger.PyDebugRunner; import com.jetbrains.python.debugger.PyLineBreakpointType; import com.jetbrains.python.debugger.PySourcePosition; +import com.jetbrains.python.documentation.DocStringUtil; +import com.jetbrains.python.psi.PyExpression; +import com.jetbrains.python.psi.PyExpressionStatement; +import com.jetbrains.python.psi.PyImportStatement; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.List; public class PyEduDebugRunner extends PyDebugRunner { + public static final Predicate IS_NOTHING = new Predicate() { + @Override + public boolean apply(@Nullable PsiElement input) { + return (input instanceof PsiComment) || + (input instanceof PyImportStatement) || + (input instanceof PsiWhiteSpace) || + (isDocString(input)); + } + }; + @Override public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) { return executorId.equals(PyEduDebugExecutor.ID); @@ -44,7 +58,7 @@ public class PyEduDebugRunner extends PyDebugRunner { List psiElements = CollectHighlightsUtil.getElementsInRange(psiFile, 0, psiFile.getTextLength()); for (PsiElement element : psiElements) { - if (PyEduUtils.isFirstCodeLine(element)) { + if (PyEduUtils.isFirstCodeLine(element, IS_NOTHING)) { int offset = element.getTextRange().getStartOffset(); Document document = FileDocumentManager.getInstance().getDocument(file); assert document != null; @@ -54,11 +68,22 @@ public class PyEduDebugRunner extends PyDebugRunner { PyLineBreakpointType type = new PyLineBreakpointType(); XBreakpointProperties properties = type.createBreakpointProperties(file, line); LineBreakpointState - breakpointState = new LineBreakpointState(true, type.getId(), file.getUrl(), line, false, file.getTimeStamp()); + breakpointState = + new LineBreakpointState(true, type.getId(), file.getUrl(), line, false, file.getTimeStamp()); pyDebugProcess.addBreakpoint(sourcePosition, new XLineBreakpointImpl(type, - ((XBreakpointManagerImpl)breakpointManager), - properties, breakpointState)); + ((XBreakpointManagerImpl)breakpointManager), + properties, breakpointState)); } } } + + private static boolean isDocString(PsiElement element) { + if (element instanceof PyExpressionStatement) { + element = ((PyExpressionStatement)element).getExpression(); + } + if (element instanceof PyExpression) { + return DocStringUtil.isDocStringExpression((PyExpression)element); + } + return false; + } } \ No newline at end of file diff --git a/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java b/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java index bdc0d402fa40..afae305552bf 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java +++ b/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java @@ -3,22 +3,29 @@ package com.jetbrains.python.edu; import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiWhiteSpace; +import com.intellij.util.containers.Predicate; import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyImportStatement; import com.jetbrains.python.psi.PyStatement; +import org.jetbrains.annotations.Nullable; public class PyEduUtils { + public static boolean isFirstCodeLine(PsiElement element) { - return element instanceof PyStatement && - element.getParent() instanceof PyFile && - !isNothing(element) && - nothingBefore(element); + return isFirstCodeLine(element, DEFAULT_CONDITION); } - private static boolean nothingBefore(PsiElement element) { + public static boolean isFirstCodeLine(PsiElement element, Predicate isNothing) { + return element instanceof PyStatement && + element.getParent() instanceof PyFile && + !isNothing.apply(element) && + nothingBefore(element, isNothing); + } + + private static boolean nothingBefore(PsiElement element, Predicate isNothing) { element = element.getPrevSibling(); while (element != null) { - if (!isNothing(element)) { + if (!isNothing.apply(element)) { return false; } element = element.getPrevSibling(); @@ -27,7 +34,10 @@ public class PyEduUtils { return true; } - private static boolean isNothing(PsiElement element) { - return (element instanceof PsiComment) || (element instanceof PyImportStatement) || (element instanceof PsiWhiteSpace); - } + private static Predicate DEFAULT_CONDITION = new Predicate() { + @Override + public boolean apply(@Nullable PsiElement element) { + return (element instanceof PsiComment) || (element instanceof PyImportStatement) || (element instanceof PsiWhiteSpace); + } + }; } From a77730eb0063e78c8cf947fb591aca311ef5508c Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Sun, 26 Jul 2015 21:17:32 +0300 Subject: [PATCH 03/16] extracted magic variables to separate debug value --- python/edu/src/META-INF/PyCharmEduPlugin.xml | 8 +++- .../python/edu/PyDebugCurrentFileAction.java | 1 + .../{ => debugger}/PyEduDebugExecutor.java | 2 +- .../edu/{ => debugger}/PyEduDebugRunner.java | 3 +- .../edu/debugger/PyEduDebugTransformer.java | 31 +++++++++++++ .../edu/debugger/PyEduMagicDebugValue.java | 45 +++++++++++++++++++ python/src/META-INF/python-core.xml | 1 + .../debugger/PyDebugValueTransformer.java | 31 +++++++++++++ .../python/debugger/PyStackFrame.java | 12 ++++- 9 files changed, 128 insertions(+), 6 deletions(-) rename python/edu/src/com/jetbrains/python/edu/{ => debugger}/PyEduDebugExecutor.java (93%) rename python/edu/src/com/jetbrains/python/edu/{ => debugger}/PyEduDebugRunner.java (97%) create mode 100644 python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugTransformer.java create mode 100644 python/edu/src/com/jetbrains/python/edu/debugger/PyEduMagicDebugValue.java create mode 100644 python/src/com/jetbrains/python/debugger/PyDebugValueTransformer.java diff --git a/python/edu/src/META-INF/PyCharmEduPlugin.xml b/python/edu/src/META-INF/PyCharmEduPlugin.xml index 38415ba90f2d..749418f21e8b 100644 --- a/python/edu/src/META-INF/PyCharmEduPlugin.xml +++ b/python/edu/src/META-INF/PyCharmEduPlugin.xml @@ -30,8 +30,12 @@ - - + + > + + + + diff --git a/python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFileAction.java b/python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFileAction.java index 8e1f394e19c1..bd9373f0057d 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFileAction.java +++ b/python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFileAction.java @@ -3,6 +3,7 @@ package com.jetbrains.python.edu; import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.execution.runners.ExecutionUtil; import com.intellij.icons.AllIcons; +import com.jetbrains.python.edu.debugger.PyEduDebugExecutor; public class PyDebugCurrentFileAction extends PyRunConfigurationForFileAction { diff --git a/python/edu/src/com/jetbrains/python/edu/PyEduDebugExecutor.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugExecutor.java similarity index 93% rename from python/edu/src/com/jetbrains/python/edu/PyEduDebugExecutor.java rename to python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugExecutor.java index 69c39f6fa12c..3bf50fa25b18 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyEduDebugExecutor.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugExecutor.java @@ -1,4 +1,4 @@ -package com.jetbrains.python.edu; +package com.jetbrains.python.edu.debugger; import com.intellij.execution.Executor; import com.intellij.execution.ExecutorRegistry; diff --git a/python/edu/src/com/jetbrains/python/edu/PyEduDebugRunner.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java similarity index 97% rename from python/edu/src/com/jetbrains/python/edu/PyEduDebugRunner.java rename to python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java index 32e8fbb38fa9..23a5068df1c9 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyEduDebugRunner.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java @@ -1,4 +1,4 @@ -package com.jetbrains.python.edu; +package com.jetbrains.python.edu.debugger; import com.intellij.codeInsight.daemon.impl.CollectHighlightsUtil; import com.intellij.execution.configurations.RunProfile; @@ -20,6 +20,7 @@ import com.jetbrains.python.debugger.PyDebugRunner; import com.jetbrains.python.debugger.PyLineBreakpointType; import com.jetbrains.python.debugger.PySourcePosition; import com.jetbrains.python.documentation.DocStringUtil; +import com.jetbrains.python.edu.PyEduUtils; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PyExpressionStatement; import com.jetbrains.python.psi.PyImportStatement; diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugTransformer.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugTransformer.java new file mode 100644 index 000000000000..a4ce04444bea --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugTransformer.java @@ -0,0 +1,31 @@ +package com.jetbrains.python.edu.debugger; + +import com.intellij.util.containers.hash.HashMap; +import com.intellij.xdebugger.frame.XValue; +import com.intellij.xdebugger.frame.XValueChildrenList; +import com.jetbrains.python.debugger.PyDebugValueTransformer; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public class PyEduDebugTransformer implements PyDebugValueTransformer { + @Override + public XValueChildrenList getTransformedChildren(@NotNull XValueChildrenList children) { + XValueChildrenList list = new XValueChildrenList(); + Map magicValues = new HashMap(); + for (int i = 0; i < children.size(); i++) { + String name = children.getName(i); + XValue value = children.getValue(i); + if (name.startsWith("__") && name.endsWith("__")) { + magicValues.put(name, value); + } + else { + list.add(name, value); + } + } + if (!magicValues.isEmpty()) { + list.add(new PyEduMagicDebugValue("magic variables", magicValues)); + } + return list; + } +} diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduMagicDebugValue.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduMagicDebugValue.java new file mode 100644 index 000000000000..eebf37036dbc --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduMagicDebugValue.java @@ -0,0 +1,45 @@ +package com.jetbrains.python.edu.debugger; + + +import com.intellij.icons.AllIcons; +import com.intellij.xdebugger.frame.*; +import com.intellij.xdebugger.frame.presentation.XValuePresentation; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public class PyEduMagicDebugValue extends XNamedValue { + + private final Map myValues; + + protected PyEduMagicDebugValue(@NotNull String name, Map values) { + super(name); + myValues = values; + } + + @Override + public void computePresentation(@NotNull XValueNode node, @NotNull XValuePlace place) { + node.setPresentation(AllIcons.Nodes.Artifact, new XValuePresentation() { + + @Override + public void renderValue(@NotNull XValueTextRenderer renderer) { + renderer.renderComment("{Python Pro Only}"); + } + + @NotNull + @Override + public String getSeparator() { + return " "; + } + }, true); + } + + @Override + public void computeChildren(@NotNull XCompositeNode node) { + XValueChildrenList children = new XValueChildrenList(); + for (Map.Entry entry : myValues.entrySet()) { + children.add(entry.getKey(), entry.getValue()); + } + node.addChildren(children, true); + } +} \ No newline at end of file diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml index 476948f3a9bc..a4d701bb8528 100644 --- a/python/src/META-INF/python-core.xml +++ b/python/src/META-INF/python-core.xml @@ -598,6 +598,7 @@ + diff --git a/python/src/com/jetbrains/python/debugger/PyDebugValueTransformer.java b/python/src/com/jetbrains/python/debugger/PyDebugValueTransformer.java new file mode 100644 index 000000000000..b92802984070 --- /dev/null +++ b/python/src/com/jetbrains/python/debugger/PyDebugValueTransformer.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2015 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.debugger; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.xdebugger.frame.XValueChildrenList; +import org.jetbrains.annotations.NotNull; + +public interface PyDebugValueTransformer { + ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.pyDebugValueTransformer"); + + /** + * This method is used in python debugger to modify content and presentation of stack frame nodes + * @param children + * @return modified children list + */ + XValueChildrenList getTransformedChildren(@NotNull final XValueChildrenList children); +} diff --git a/python/src/com/jetbrains/python/debugger/PyStackFrame.java b/python/src/com/jetbrains/python/debugger/PyStackFrame.java index 9f1f0234694c..3d2d3326c707 100644 --- a/python/src/com/jetbrains/python/debugger/PyStackFrame.java +++ b/python/src/com/jetbrains/python/debugger/PyStackFrame.java @@ -19,6 +19,7 @@ import com.intellij.icons.AllIcons; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; @@ -108,9 +109,16 @@ public class PyStackFrame extends XStackFrame { @Override public void run() { try { - final XValueChildrenList values = myDebugProcess.loadFrame(); + XValueChildrenList values = myDebugProcess.loadFrame(); if (!node.isObsolete()) { - node.addChildren(values != null ? values : XValueChildrenList.EMPTY, true); + if (values == null) { + node.addChildren(XValueChildrenList.EMPTY, true); + return; + } + for (PyDebugValueTransformer transformer : Extensions.getExtensions(PyDebugValueTransformer.EP_NAME)) { + values = transformer.getTransformedChildren(values); + } + node.addChildren(values, true); } } catch (PyDebuggerException e) { From a82ca602353e70d2abf8ee3cad786e2c3088d528 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Sun, 26 Jul 2015 22:35:59 +0300 Subject: [PATCH 04/16] customized frames list --- python/edu/src/META-INF/PyCharmEduPlugin.xml | 1 + .../python/edu/debugger/PyEduDebugRunner.java | 37 ++++++++++++-- .../edu/debugger/PyEduFramesTransformer.java | 29 +++++++++++ .../python/edu/debugger/PyEduStackFrame.java | 51 +++++++++++++++++++ .../python/debugger/PyFramesTransformer.java | 13 +++++ .../python/debugger/PyThreadInfo.java | 17 ++++++- python/src/META-INF/python-core.xml | 1 + .../python/debugger/PyDebugRunner.java | 12 ++++- .../python/debugger/PyStackFrame.java | 8 ++- 9 files changed, 159 insertions(+), 10 deletions(-) create mode 100644 python/edu/src/com/jetbrains/python/edu/debugger/PyEduFramesTransformer.java create mode 100644 python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java create mode 100644 python/pydevSrc/com/jetbrains/python/debugger/PyFramesTransformer.java diff --git a/python/edu/src/META-INF/PyCharmEduPlugin.xml b/python/edu/src/META-INF/PyCharmEduPlugin.xml index 749418f21e8b..b676ee5fd53c 100644 --- a/python/edu/src/META-INF/PyCharmEduPlugin.xml +++ b/python/edu/src/META-INF/PyCharmEduPlugin.xml @@ -36,6 +36,7 @@ + diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java index 23a5068df1c9..3e358292c309 100644 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java @@ -1,7 +1,10 @@ package com.jetbrains.python.edu.debugger; import com.intellij.codeInsight.daemon.impl.CollectHighlightsUtil; +import com.intellij.execution.ExecutionResult; import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.ui.ExecutionConsole; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; @@ -9,25 +12,25 @@ import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.util.containers.Predicate; +import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.breakpoints.XBreakpointManager; import com.intellij.xdebugger.breakpoints.XBreakpointProperties; import com.intellij.xdebugger.impl.breakpoints.LineBreakpointState; import com.intellij.xdebugger.impl.breakpoints.XBreakpointManagerImpl; import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointImpl; -import com.jetbrains.python.debugger.PyDebugProcess; -import com.jetbrains.python.debugger.PyDebugRunner; -import com.jetbrains.python.debugger.PyLineBreakpointType; -import com.jetbrains.python.debugger.PySourcePosition; +import com.jetbrains.python.debugger.*; import com.jetbrains.python.documentation.DocStringUtil; import com.jetbrains.python.edu.PyEduUtils; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PyExpressionStatement; import com.jetbrains.python.psi.PyImportStatement; +import com.jetbrains.python.run.PythonCommandLineState; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.net.ServerSocket; import java.util.List; public class PyEduDebugRunner extends PyDebugRunner { @@ -47,6 +50,17 @@ public class PyEduDebugRunner extends PyDebugRunner { return executorId.equals(PyEduDebugExecutor.ID); } + @NotNull + @Override + protected PyDebugProcess createDebugProcess(@NotNull XDebugSession session, + ServerSocket serverSocket, + ExecutionResult result, + PythonCommandLineState pyState) { + + return new PyEduDebugProcess(session, serverSocket, result.getExecutionConsole(), result.getProcessHandler(), + pyState.isMultiprocessDebug()); + } + @Override protected void initDebugProcess(String name, PyDebugProcess pyDebugProcess) { VirtualFile file = VfsUtil.findFileByIoFile(new File(name), true); @@ -87,4 +101,19 @@ public class PyEduDebugRunner extends PyDebugRunner { } return false; } + + private class PyEduDebugProcess extends PyDebugProcess { + public PyEduDebugProcess(@NotNull XDebugSession session, + @NotNull ServerSocket serverSocket, + @NotNull ExecutionConsole executionConsole, + @Nullable ProcessHandler processHandler, boolean multiProcess) { + super(session, serverSocket, executionConsole, processHandler, multiProcess); + } + + @Override + public PyStackFrame createStackFrame(PyStackFrameInfo frameInfo) { + return new PyEduStackFrame(getSession().getProject(), this, frameInfo, + getPositionConverter().convertFromPython(frameInfo.getPosition())); + } + } } \ No newline at end of file diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduFramesTransformer.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduFramesTransformer.java new file mode 100644 index 000000000000..e83a1e301500 --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduFramesTransformer.java @@ -0,0 +1,29 @@ +package com.jetbrains.python.edu.debugger; + +import com.jetbrains.python.PythonHelpersLocator; +import com.jetbrains.python.debugger.PyDebugRunner; +import com.jetbrains.python.debugger.PyFramesTransformer; +import com.jetbrains.python.debugger.PyStackFrameInfo; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class PyEduFramesTransformer implements PyFramesTransformer { + @Nullable + @Override + public List transformFrames(@Nullable List frames) { + if (frames == null) { + return null; + } + String debugger = PythonHelpersLocator.getHelperPath(PyDebugRunner.DEBUGGER_MAIN); + List newFrames = new ArrayList(); + for (PyStackFrameInfo frame : frames) { + String file = frame.getPosition().getFile(); + if (!debugger.equals(file)) { + newFrames.add(frame); + } + } + return newFrames; + } +} diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java new file mode 100644 index 000000000000..ca3b63b13f21 --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java @@ -0,0 +1,51 @@ +package com.jetbrains.python.edu.debugger; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.ColoredTextContainer; +import com.intellij.ui.SimpleTextAttributes; +import com.intellij.xdebugger.XSourcePosition; +import com.jetbrains.python.debugger.PyFrameAccessor; +import com.jetbrains.python.debugger.PyStackFrame; +import com.jetbrains.python.debugger.PyStackFrameInfo; +import org.jetbrains.annotations.NotNull; + +public class PyEduStackFrame extends PyStackFrame { + public static final String MODULE = ""; + public static final String GLOBAL_FRAME = "Global Frame"; + private final PyStackFrameInfo myFrameInfo; + private final XSourcePosition myPosition; + + public PyEduStackFrame(@NotNull Project project, + @NotNull PyFrameAccessor debugProcess, + @NotNull PyStackFrameInfo frameInfo, + XSourcePosition position) { + super(project, debugProcess, frameInfo, position); + myFrameInfo = frameInfo; + myPosition = position; + } + + @Override + public void customizePresentation(@NotNull ColoredTextContainer component) { + component.setIcon(AllIcons.Debugger.StackFrame); + if (myPosition == null) { + component.append("", SimpleTextAttributes.GRAY_ATTRIBUTES); + return; + } + + final VirtualFile file = myPosition.getFile(); + + String frameName = myFrameInfo.getName(); + component.setIcon(MODULE.equals(frameName) ? AllIcons.FileTypes.Text : AllIcons.Nodes.Field); + SimpleTextAttributes regularAttributes = SimpleTextAttributes.REGULAR_ATTRIBUTES; + if (MODULE.equals(frameName)) { + component.append(GLOBAL_FRAME, regularAttributes); + component.append(" (" + file.getName() + ")", getGrayAttributes(regularAttributes)); + } + else { + component + .append(MODULE.equals(frameName) ? GLOBAL_FRAME : frameName, regularAttributes); + } + } +} diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyFramesTransformer.java b/python/pydevSrc/com/jetbrains/python/debugger/PyFramesTransformer.java new file mode 100644 index 000000000000..302edefb7c07 --- /dev/null +++ b/python/pydevSrc/com/jetbrains/python/debugger/PyFramesTransformer.java @@ -0,0 +1,13 @@ +package com.jetbrains.python.debugger; + +import com.intellij.openapi.extensions.ExtensionPointName; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public interface PyFramesTransformer { + ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.pyFramesTransformer"); + + @Nullable + List transformFrames(@Nullable List frames); +} diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java b/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java index d7a2d5fe187c..f48c27bc226c 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java @@ -1,8 +1,10 @@ package com.jetbrains.python.debugger; +import com.intellij.openapi.extensions.Extensions; import com.jetbrains.python.debugger.pydev.AbstractCommand; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -26,11 +28,22 @@ public class PyThreadInfo { String message) { myId = id; myName = name; - myFrames = (frames != null && frames.size() > 0 ? Collections.unmodifiableList(frames) : null); + myFrames = prepareFrames(frames); myStopReason = stopReason; myMessage = message; } + private static List prepareFrames(List frames) { + if (frames == null) { + return null; + } + List framesCopy = new ArrayList(frames); + for (PyFramesTransformer transformer: Extensions.getExtensions(PyFramesTransformer.EP_NAME)) { + framesCopy = transformer.transformFrames(framesCopy); + } + return framesCopy != null && framesCopy.size() > 0 ? Collections.unmodifiableList(framesCopy) : null; + } + public String getId() { return myId; } @@ -63,7 +76,7 @@ public class PyThreadInfo { public synchronized void updateState(final State state, final List frames) { myState = state; - myFrames = (frames != null && frames.size() > 0 ? Collections.unmodifiableList(frames) : null); + myFrames = prepareFrames(frames); } diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml index a4d701bb8528..aa537166a662 100644 --- a/python/src/META-INF/python-core.xml +++ b/python/src/META-INF/python-core.xml @@ -599,6 +599,7 @@ + diff --git a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java index abd7f429e5c7..2c1454ca285a 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java @@ -98,8 +98,7 @@ public class PyDebugRunner extends GenericProgramRunner { @NotNull public XDebugProcess start(@NotNull final XDebugSession session) { PyDebugProcess pyDebugProcess = - new PyDebugProcess(session, serverSocket, result.getExecutionConsole(), result.getProcessHandler(), - pyState.isMultiprocessDebug()); + createDebugProcess(session, serverSocket, result, pyState); createConsoleCommunicationAndSetupActions(environment.getProject(), result, pyDebugProcess, session); initDebugProcess(((PythonRunConfiguration)environment.getRunProfile()).getScriptName(), pyDebugProcess); @@ -108,6 +107,15 @@ public class PyDebugRunner extends GenericProgramRunner { }); } + @NotNull + protected PyDebugProcess createDebugProcess(@NotNull XDebugSession session, + ServerSocket serverSocket, + ExecutionResult result, + PythonCommandLineState pyState) { + return new PyDebugProcess(session, serverSocket, result.getExecutionConsole(), result.getProcessHandler(), + pyState.isMultiprocessDebug()); + } + protected void initDebugProcess(String name, PyDebugProcess pyDebugProcess) { } diff --git a/python/src/com/jetbrains/python/debugger/PyStackFrame.java b/python/src/com/jetbrains/python/debugger/PyStackFrame.java index 3d2d3326c707..80cce5540e6f 100644 --- a/python/src/com/jetbrains/python/debugger/PyStackFrame.java +++ b/python/src/com/jetbrains/python/debugger/PyStackFrame.java @@ -97,11 +97,15 @@ public class PyStackFrame extends XStackFrame { return attributes; } else { - return (attributes.getStyle() & SimpleTextAttributes.STYLE_ITALIC) != 0 - ? SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES : SimpleTextAttributes.GRAYED_ATTRIBUTES; + return getGrayAttributes(attributes); } } + protected static SimpleTextAttributes getGrayAttributes(SimpleTextAttributes attributes) { + return (attributes.getStyle() & SimpleTextAttributes.STYLE_ITALIC) != 0 + ? SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES : SimpleTextAttributes.GRAYED_ATTRIBUTES; + } + @Override public void computeChildren(@NotNull final XCompositeNode node) { if (node.isObsolete()) return; From f1816909a9a5951ee91adf34d0616ddb475bdc01 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Thu, 30 Jul 2015 12:38:30 +0300 Subject: [PATCH 05/16] replaced watches tab with simplified console --- python/edu/src/META-INF/PyCharmEduPlugin.xml | 1 + .../debugger/PyEduConsoleOutputFilter.java | 18 ++++ .../python/edu/debugger/PyEduDebugRunner.java | 90 ++++++++++++++++++- .../actions/CCRunTestsAction.java | 5 ++ python/src/META-INF/python-core.xml | 1 + .../python/console/PyConsoleOutputFilter.java | 26 ++++++ .../python/console/PythonConsoleView.java | 7 ++ .../python/debugger/PyDebugRunner.java | 8 +- 8 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 python/edu/src/com/jetbrains/python/edu/debugger/PyEduConsoleOutputFilter.java create mode 100644 python/src/com/jetbrains/python/console/PyConsoleOutputFilter.java diff --git a/python/edu/src/META-INF/PyCharmEduPlugin.xml b/python/edu/src/META-INF/PyCharmEduPlugin.xml index b676ee5fd53c..da680fc346ba 100644 --- a/python/edu/src/META-INF/PyCharmEduPlugin.xml +++ b/python/edu/src/META-INF/PyCharmEduPlugin.xml @@ -37,6 +37,7 @@ + diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduConsoleOutputFilter.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduConsoleOutputFilter.java new file mode 100644 index 000000000000..d1bde91517a2 --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduConsoleOutputFilter.java @@ -0,0 +1,18 @@ +package com.jetbrains.python.edu.debugger; + +import com.intellij.execution.ui.ConsoleViewContentType; +import com.jetbrains.python.console.PyConsoleOutputFilter; +import org.jetbrains.annotations.NotNull; + +public class PyEduConsoleOutputFilter implements PyConsoleOutputFilter { + @Override + public boolean reject(@NotNull String text, @NotNull ConsoleViewContentType outputType) { + if (outputType.equals(ConsoleViewContentType.SYSTEM_OUTPUT) && !text.contains("exit code")) { + return true; + } + if (text.startsWith("pydev debugger")) { + return true; + } + return false; + } +} diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java index 3e358292c309..98071490addb 100644 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java @@ -2,23 +2,42 @@ package com.jetbrains.python.edu.debugger; import com.intellij.codeInsight.daemon.impl.CollectHighlightsUtil; import com.intellij.execution.ExecutionResult; +import com.intellij.execution.Executor; import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.configurations.RunProfileState; +import com.intellij.execution.filters.UrlFilter; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.ui.ExecutionConsole; +import com.intellij.execution.ui.RunnerLayoutUi; +import com.intellij.execution.ui.layout.PlaceInGrid; +import com.intellij.icons.AllIcons; +import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.ActionPlaces; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; +import com.intellij.ui.content.Content; +import com.intellij.ui.content.ContentManager; import com.intellij.util.containers.Predicate; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.breakpoints.XBreakpointManager; import com.intellij.xdebugger.breakpoints.XBreakpointProperties; +import com.intellij.xdebugger.impl.XDebugSessionImpl; import com.intellij.xdebugger.impl.breakpoints.LineBreakpointState; import com.intellij.xdebugger.impl.breakpoints.XBreakpointManagerImpl; import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointImpl; +import com.intellij.xdebugger.impl.ui.XDebugSessionTab; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.console.PythonDebugLanguageConsoleView; import com.jetbrains.python.debugger.*; import com.jetbrains.python.documentation.DocStringUtil; import com.jetbrains.python.edu.PyEduUtils; @@ -26,6 +45,8 @@ import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PyExpressionStatement; import com.jetbrains.python.psi.PyImportStatement; import com.jetbrains.python.run.PythonCommandLineState; +import com.jetbrains.python.run.PythonTracebackFilter; +import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,6 +65,7 @@ public class PyEduDebugRunner extends PyDebugRunner { (isDocString(input)); } }; + public static final String OUTPUT = "Output"; @Override public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) { @@ -92,6 +114,72 @@ public class PyEduDebugRunner extends PyDebugRunner { } } + + @Override + protected void initSession(XDebugSession session, RunProfileState state, Executor executor) { + XDebugSessionTab tab = ((XDebugSessionImpl)session).getSessionTab(); + if (tab != null) { + RunnerLayoutUi ui = tab.getUi(); + ContentManager contentManager = ui.getContentManager(); + Content content = findContent(contentManager, "Watches"); + if (content != null) { + contentManager.removeContent(content, true); + } + content = findContent(contentManager, "Console"); + if (content != null) { + contentManager.removeContent(content, true); + } + initEduConsole(session, ui); + } + } + + private static void initEduConsole(@NotNull final XDebugSession session, + @NotNull final RunnerLayoutUi ui) { + Project project = session.getProject(); + final Sdk sdk = PythonSdkType.findPythonSdk(ModuleManager.getInstance(project).getModules()[0]); + final PythonDebugLanguageConsoleView view = new PythonDebugLanguageConsoleView(project, sdk); + final ProcessHandler processHandler = session.getDebugProcess().getProcessHandler(); + + view.attachToProcess(processHandler); + view.addMessageFilter(new PythonTracebackFilter(project)); + view.addMessageFilter(new UrlFilter()); + + switchToPythonConsole(view); + + Content eduConsole = + ui.createContent(OUTPUT, view.getComponent() , OUTPUT, AllIcons.Debugger.ToolConsole, view.getPreferredFocusableComponent()); + eduConsole.setCloseable(false); + ui.addContent(eduConsole, 0, PlaceInGrid.right, false); + + PyDebugProcess process = (PyDebugProcess)session.getDebugProcess(); + PyDebugRunner.initDebugConsoleView(project, process, view, processHandler, session); + } + + private static void switchToPythonConsole(PythonDebugLanguageConsoleView view) { + AnAction[] actions = view.createConsoleActions(); + for (AnAction action : actions) { + Presentation presentation = action.getTemplatePresentation(); + String text = presentation.getText(); + if (PyBundle.message("run.configuration.show.command.line.action.name").equals(text)) { + AnActionEvent event = + AnActionEvent.createFromAnAction(action, null, + ActionPlaces.DEBUGGER_TOOLBAR, DataManager.getInstance().getDataContext(view)); + action.actionPerformed(event); + } + } + } + + @Nullable + private static Content findContent(ContentManager manager, String name) { + for (Content content : manager.getContents()) { + if (content.getDisplayName().equals(name)) { + return content; + } + } + return null; + } + + private static boolean isDocString(PsiElement element) { if (element instanceof PyExpressionStatement) { element = ((PyExpressionStatement)element).getExpression(); @@ -102,7 +190,7 @@ public class PyEduDebugRunner extends PyDebugRunner { return false; } - private class PyEduDebugProcess extends PyDebugProcess { + private static class PyEduDebugProcess extends PyDebugProcess { public PyEduDebugProcess(@NotNull XDebugSession session, @NotNull ServerSocket serverSocket, @NotNull ExecutionConsole executionConsole, diff --git a/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCRunTestsAction.java b/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCRunTestsAction.java index f1d9d6cba063..851475b8afe0 100644 --- a/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCRunTestsAction.java +++ b/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCRunTestsAction.java @@ -56,6 +56,11 @@ public abstract class CCRunTestsAction extends AnAction { @Override public void update(@NotNull AnActionEvent e) { + if (!CCProjectService.setCCActionAvailable(e)) { + EduUtils.enableAction(e, false); + return; + } + Presentation presentation = e.getPresentation(); presentation.setText(""); presentation.setVisible(false); diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml index aa537166a662..e77452a9d3e7 100644 --- a/python/src/META-INF/python-core.xml +++ b/python/src/META-INF/python-core.xml @@ -600,6 +600,7 @@ + diff --git a/python/src/com/jetbrains/python/console/PyConsoleOutputFilter.java b/python/src/com/jetbrains/python/console/PyConsoleOutputFilter.java new file mode 100644 index 000000000000..45759439b05a --- /dev/null +++ b/python/src/com/jetbrains/python/console/PyConsoleOutputFilter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2015 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.console; + +import com.intellij.execution.ui.ConsoleViewContentType; +import com.intellij.openapi.extensions.ExtensionPointName; +import org.jetbrains.annotations.NotNull; + +public interface PyConsoleOutputFilter { + ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.pyConsoleOutputFilter"); + + boolean reject(@NotNull String text, @NotNull final ConsoleViewContentType outputType); +} diff --git a/python/src/com/jetbrains/python/console/PythonConsoleView.java b/python/src/com/jetbrains/python/console/PythonConsoleView.java index d5ddcb6f5175..a78fc2e61401 100644 --- a/python/src/com/jetbrains/python/console/PythonConsoleView.java +++ b/python/src/com/jetbrains/python/console/PythonConsoleView.java @@ -25,6 +25,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; @@ -177,6 +178,12 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable @Override public void print(@NotNull String text, @NotNull final ConsoleViewContentType outputType) { + for (PyConsoleOutputFilter filter : Extensions.getExtensions(PyConsoleOutputFilter.EP_NAME)) { + if (filter.reject(text, outputType)) { + return; + } + } + detectIPython(text, outputType); if (PyConsoleUtil.detectIPythonEnd(text)) { myIsIPythonOutput = false; diff --git a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java index 2c1454ca285a..2d0c5416350f 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java @@ -18,6 +18,7 @@ package com.jetbrains.python.debugger; import com.google.common.collect.Lists; import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionResult; +import com.intellij.execution.Executor; import com.intellij.execution.configurations.*; import com.intellij.execution.console.LanguageConsoleBuilder; import com.intellij.execution.executors.DefaultDebugExecutor; @@ -121,7 +122,12 @@ public class PyDebugRunner extends GenericProgramRunner { @Override protected RunContentDescriptor doExecute(@NotNull RunProfileState state, @NotNull final ExecutionEnvironment environment) throws ExecutionException { - return createSession(state, environment).getRunContentDescriptor(); + XDebugSession session = createSession(state, environment); + initSession(session, state, environment.getExecutor()); + return session.getRunContentDescriptor(); + } + + protected void initSession(XDebugSession session, RunProfileState state, Executor executor) { } public static int findIndex(List paramList, String paramName) { From a6a6430eaa25814a509e19dcba4f04161721cd48 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 5 Aug 2015 21:44:46 +0300 Subject: [PATCH 06/16] fixed after IDEA-CR-4069 --- python/edu/src/META-INF/PyCharmEduPlugin.xml | 7 +- .../edu/PyCharmEduInitialConfigurator.java | 7 +- .../com/jetbrains/python/edu/PyEduUtils.java | 24 +-- .../edu/PyRunConfigurationForFileAction.java | 3 + .../debugger/PyEduConsoleOutputFilter.java | 18 -- .../edu/debugger/PyEduDebugExecutor.java | 2 +- .../edu/debugger/PyEduDebugProcess.java | 67 +++++++ .../python/edu/debugger/PyEduDebugRunner.java | 167 +++++++----------- .../edu/debugger/PyEduFramesTransformer.java | 29 --- .../edu/debugger/PyEduMagicDebugValue.java | 4 + .../python/edu/debugger/PyEduStackFrame.java | 2 +- .../python/debugger/PyFramesTransformer.java | 13 -- .../python/debugger/PyThreadInfo.java | 17 +- python/src/META-INF/python-core.xml | 4 +- .../python/console/PyConsoleOutputFilter.java | 26 --- .../python/console/PythonConsoleView.java | 7 - .../python/debugger/PyDebugProcess.java | 13 +- .../python/debugger/PyDebugRunner.java | 5 - .../debugger/PyDebugValueTransformer.java | 2 +- 19 files changed, 166 insertions(+), 251 deletions(-) delete mode 100644 python/edu/src/com/jetbrains/python/edu/debugger/PyEduConsoleOutputFilter.java create mode 100644 python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugProcess.java delete mode 100644 python/edu/src/com/jetbrains/python/edu/debugger/PyEduFramesTransformer.java delete mode 100644 python/pydevSrc/com/jetbrains/python/debugger/PyFramesTransformer.java delete mode 100644 python/src/com/jetbrains/python/console/PyConsoleOutputFilter.java diff --git a/python/edu/src/META-INF/PyCharmEduPlugin.xml b/python/edu/src/META-INF/PyCharmEduPlugin.xml index da680fc346ba..743e43a7d779 100644 --- a/python/edu/src/META-INF/PyCharmEduPlugin.xml +++ b/python/edu/src/META-INF/PyCharmEduPlugin.xml @@ -31,13 +31,12 @@ - > + + - - - + diff --git a/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java b/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java index e0dc6544aaa0..73d9e9b8142b 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java +++ b/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java @@ -230,8 +230,11 @@ public class PyCharmEduInitialConfigurator { ActionManager actionManager = ActionManager.getInstance(); AnAction action = actionManager.getAction(actionId); if (action != null) { - ((DefaultActionGroup)actionManager.getAction(groupId)).remove(action); - actionManager.unregisterAction(actionId); + AnAction actionGroup = actionManager.getAction(groupId); + if (actionGroup != null && actionGroup instanceof DefaultActionGroup) { + ((DefaultActionGroup)actionGroup).remove(action); + actionManager.unregisterAction(actionId); + } } } diff --git a/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java b/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java index afae305552bf..bdc0d402fa40 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java +++ b/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java @@ -3,29 +3,22 @@ package com.jetbrains.python.edu; import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiWhiteSpace; -import com.intellij.util.containers.Predicate; import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyImportStatement; import com.jetbrains.python.psi.PyStatement; -import org.jetbrains.annotations.Nullable; public class PyEduUtils { - public static boolean isFirstCodeLine(PsiElement element) { - return isFirstCodeLine(element, DEFAULT_CONDITION); - } - - public static boolean isFirstCodeLine(PsiElement element, Predicate isNothing) { return element instanceof PyStatement && element.getParent() instanceof PyFile && - !isNothing.apply(element) && - nothingBefore(element, isNothing); + !isNothing(element) && + nothingBefore(element); } - private static boolean nothingBefore(PsiElement element, Predicate isNothing) { + private static boolean nothingBefore(PsiElement element) { element = element.getPrevSibling(); while (element != null) { - if (!isNothing.apply(element)) { + if (!isNothing(element)) { return false; } element = element.getPrevSibling(); @@ -34,10 +27,7 @@ public class PyEduUtils { return true; } - private static Predicate DEFAULT_CONDITION = new Predicate() { - @Override - public boolean apply(@Nullable PsiElement element) { - return (element instanceof PsiComment) || (element instanceof PyImportStatement) || (element instanceof PsiWhiteSpace); - } - }; + private static boolean isNothing(PsiElement element) { + return (element instanceof PsiComment) || (element instanceof PyImportStatement) || (element instanceof PsiWhiteSpace); + } } diff --git a/python/edu/src/com/jetbrains/python/edu/PyRunConfigurationForFileAction.java b/python/edu/src/com/jetbrains/python/edu/PyRunConfigurationForFileAction.java index 619ebe1c95ba..8c42fe2b43b2 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyRunConfigurationForFileAction.java +++ b/python/edu/src/com/jetbrains/python/edu/PyRunConfigurationForFileAction.java @@ -16,6 +16,9 @@ public abstract class PyRunConfigurationForFileAction extends AnAction { public void update(AnActionEvent e) { Presentation presentation = e.getPresentation(); final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext()); + if (context.findExisting() == null && context.getConfiguration() == null) { + return; + } Location location = context.getLocation(); if (location != null && location.getPsiElement().getContainingFile() != null && location.getPsiElement().getContainingFile().getFileType() == PythonFileType.INSTANCE) { presentation.setEnabled(true); diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduConsoleOutputFilter.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduConsoleOutputFilter.java deleted file mode 100644 index d1bde91517a2..000000000000 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduConsoleOutputFilter.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jetbrains.python.edu.debugger; - -import com.intellij.execution.ui.ConsoleViewContentType; -import com.jetbrains.python.console.PyConsoleOutputFilter; -import org.jetbrains.annotations.NotNull; - -public class PyEduConsoleOutputFilter implements PyConsoleOutputFilter { - @Override - public boolean reject(@NotNull String text, @NotNull ConsoleViewContentType outputType) { - if (outputType.equals(ConsoleViewContentType.SYSTEM_OUTPUT) && !text.contains("exit code")) { - return true; - } - if (text.startsWith("pydev debugger")) { - return true; - } - return false; - } -} diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugExecutor.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugExecutor.java index 3bf50fa25b18..fe9e573dd86f 100644 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugExecutor.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugExecutor.java @@ -20,7 +20,7 @@ public class PyEduDebugExecutor extends DefaultDebugExecutor { @Override public String getContextActionId() { - return "EduDebugClass"; + return "EduDebug"; } @NotNull diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugProcess.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugProcess.java new file mode 100644 index 000000000000..0904ec772846 --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugProcess.java @@ -0,0 +1,67 @@ +package com.jetbrains.python.edu.debugger; + +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.ui.ExecutionConsole; +import com.intellij.xdebugger.XDebugSession; +import com.jetbrains.python.PythonHelpersLocator; +import com.jetbrains.python.debugger.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.net.ServerSocket; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +class PyEduDebugProcess extends PyDebugProcess { + + private final String myScriptName; + private final int myLine; + + public PyEduDebugProcess(@NotNull XDebugSession session, + @NotNull ServerSocket serverSocket, + @NotNull ExecutionConsole executionConsole, + @Nullable ProcessHandler processHandler, boolean multiProcess, + String scriptName, + int line) { + super(session, serverSocket, executionConsole, processHandler, multiProcess); + myScriptName = scriptName; + myLine = line; + } + + @Override + public PyStackFrame createStackFrame(PyStackFrameInfo frameInfo) { + return new PyEduStackFrame(getSession().getProject(), this, frameInfo, + getPositionConverter().convertFromPython(frameInfo.getPosition())); + } + + @Override + public void init() { + super.init(); + addTemporaryBreakpoint(PyLineBreakpointType.ID, myScriptName, myLine); + } + + @NotNull + @Override + protected PySuspendContext createSuspendContext(PyThreadInfo threadInfo) { + threadInfo.updateState(threadInfo.getState(), new ArrayList(filterFrames(threadInfo.getFrames()))); + return new PySuspendContext(this, threadInfo); + } + + public Collection filterFrames(@Nullable List frames) { + if (frames == null) { + return Collections.emptyList(); + } + final String debugger = PythonHelpersLocator.getHelperPath(PyDebugRunner.DEBUGGER_MAIN); + return Collections2.filter(frames, new Predicate() { + @Override + public boolean apply(PyStackFrameInfo frame) { + String file = frame.getPosition().getFile(); + return !debugger.equals(file); + } + }); + } +} diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java index 98071490addb..15d2fc98cdea 100644 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java @@ -1,21 +1,17 @@ package com.jetbrains.python.edu.debugger; -import com.intellij.codeInsight.daemon.impl.CollectHighlightsUtil; import com.intellij.execution.ExecutionResult; import com.intellij.execution.Executor; import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunProfileState; import com.intellij.execution.filters.UrlFilter; import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.ui.ExecutionConsole; import com.intellij.execution.ui.RunnerLayoutUi; import com.intellij.execution.ui.layout.PlaceInGrid; import com.intellij.icons.AllIcons; -import com.intellij.ide.DataManager; -import com.intellij.openapi.actionSystem.ActionPlaces; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.module.ModuleManager; @@ -23,28 +19,18 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentManager; -import com.intellij.util.containers.Predicate; import com.intellij.xdebugger.XDebugSession; -import com.intellij.xdebugger.XDebuggerManager; -import com.intellij.xdebugger.breakpoints.XBreakpointManager; -import com.intellij.xdebugger.breakpoints.XBreakpointProperties; +import com.intellij.xdebugger.XDebuggerBundle; import com.intellij.xdebugger.impl.XDebugSessionImpl; -import com.intellij.xdebugger.impl.breakpoints.LineBreakpointState; -import com.intellij.xdebugger.impl.breakpoints.XBreakpointManagerImpl; -import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointImpl; import com.intellij.xdebugger.impl.ui.XDebugSessionTab; -import com.jetbrains.python.PyBundle; import com.jetbrains.python.console.PythonDebugLanguageConsoleView; -import com.jetbrains.python.debugger.*; -import com.jetbrains.python.documentation.DocStringUtil; -import com.jetbrains.python.edu.PyEduUtils; -import com.jetbrains.python.psi.PyExpression; -import com.jetbrains.python.psi.PyExpressionStatement; -import com.jetbrains.python.psi.PyImportStatement; +import com.jetbrains.python.debugger.PyDebugProcess; +import com.jetbrains.python.debugger.PyDebugRunner; +import com.jetbrains.python.debugger.PyLineBreakpointType; import com.jetbrains.python.run.PythonCommandLineState; +import com.jetbrains.python.run.PythonRunConfiguration; import com.jetbrains.python.run.PythonTracebackFilter; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; @@ -52,20 +38,11 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.net.ServerSocket; -import java.util.List; public class PyEduDebugRunner extends PyDebugRunner { - - public static final Predicate IS_NOTHING = new Predicate() { - @Override - public boolean apply(@Nullable PsiElement input) { - return (input instanceof PsiComment) || - (input instanceof PyImportStatement) || - (input instanceof PsiWhiteSpace) || - (isDocString(input)); - } - }; public static final String OUTPUT = "Output"; + private static final Logger LOG = Logger.getInstance(PyEduDebugRunner.class); + public static final int NO_LINE = -1; @Override public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) { @@ -78,40 +55,54 @@ public class PyEduDebugRunner extends PyDebugRunner { ServerSocket serverSocket, ExecutionResult result, PythonCommandLineState pyState) { - - return new PyEduDebugProcess(session, serverSocket, result.getExecutionConsole(), result.getProcessHandler(), - pyState.isMultiprocessDebug()); - } - - @Override - protected void initDebugProcess(String name, PyDebugProcess pyDebugProcess) { - VirtualFile file = VfsUtil.findFileByIoFile(new File(name), true); - assert file != null; - - final Project project = pyDebugProcess.getProject(); - PsiFile psiFile = PsiManager.getInstance(project).findFile(file); - - assert psiFile != null; - - List psiElements = CollectHighlightsUtil.getElementsInRange(psiFile, 0, psiFile.getTextLength()); - for (PsiElement element : psiElements) { - if (PyEduUtils.isFirstCodeLine(element, IS_NOTHING)) { - int offset = element.getTextRange().getStartOffset(); - Document document = FileDocumentManager.getInstance().getDocument(file); - assert document != null; - int line = document.getLineNumber(offset) + 1; - PySourcePosition sourcePosition = pyDebugProcess.getPositionConverter().create(file.getPath(), line); - XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); - PyLineBreakpointType type = new PyLineBreakpointType(); - XBreakpointProperties properties = type.createBreakpointProperties(file, line); - LineBreakpointState - breakpointState = - new LineBreakpointState(true, type.getId(), file.getUrl(), line, false, file.getTimeStamp()); - pyDebugProcess.addBreakpoint(sourcePosition, new XLineBreakpointImpl(type, - ((XBreakpointManagerImpl)breakpointManager), - properties, breakpointState)); + ExecutionConsole executionConsole = result.getExecutionConsole(); + ProcessHandler processHandler = result.getProcessHandler(); + boolean isMultiProcess = pyState.isMultiprocessDebug(); + String scriptName = getScriptName(pyState); + if (scriptName != null) { + VirtualFile file = VfsUtil.findFileByIoFile(new File(scriptName), true); + if (file != null) { + int line = getBreakpointLineNumber(file, session.getProject()); + if (line != NO_LINE) { + return new PyEduDebugProcess(session, serverSocket, + executionConsole, processHandler, + isMultiProcess, scriptName, line + 1); + } } } + LOG.info("Failed to create PyEduDebugProcess. PyDebugProcess created instead."); + return new PyDebugProcess(session, serverSocket, executionConsole, + processHandler, isMultiProcess); + } + + @Nullable + private static String getScriptName(PythonCommandLineState pyState) { + ExecutionEnvironment environment = pyState.getEnvironment(); + if (environment == null) { + return null; + } + RunProfile runProfile = environment.getRunProfile(); + if (runProfile instanceof PythonRunConfiguration) { + return ((PythonRunConfiguration)runProfile).getScriptName(); + } + return null; + } + + /** + * @return the smallest line (from 0 to line number) suitable to set breakpoint on it, NO_LINE if there is no such line in the file + */ + private static int getBreakpointLineNumber(@NotNull final VirtualFile file, @NotNull final Project project) { + Document document = FileDocumentManager.getInstance().getDocument(file); + if (document == null) { + return NO_LINE; + } + PyLineBreakpointType lineBreakpointType = new PyLineBreakpointType(); + for (int line = 0; line < document.getLineCount(); line++) { + if (lineBreakpointType.canPutAt(file, line, project)) { + return line; + } + } + return NO_LINE; } @@ -121,11 +112,11 @@ public class PyEduDebugRunner extends PyDebugRunner { if (tab != null) { RunnerLayoutUi ui = tab.getUi(); ContentManager contentManager = ui.getContentManager(); - Content content = findContent(contentManager, "Watches"); + Content content = findContent(contentManager, XDebuggerBundle.message("debugger.session.tab.watches.title")); if (content != null) { contentManager.removeContent(content, true); } - content = findContent(contentManager, "Console"); + content = findContent(contentManager, XDebuggerBundle.message("debugger.session.tab.console.content.name")); if (content != null) { contentManager.removeContent(content, true); } @@ -144,10 +135,10 @@ public class PyEduDebugRunner extends PyDebugRunner { view.addMessageFilter(new PythonTracebackFilter(project)); view.addMessageFilter(new UrlFilter()); - switchToPythonConsole(view); + view.enableConsole(false); Content eduConsole = - ui.createContent(OUTPUT, view.getComponent() , OUTPUT, AllIcons.Debugger.ToolConsole, view.getPreferredFocusableComponent()); + ui.createContent(OUTPUT, view.getComponent(), OUTPUT, AllIcons.Debugger.ToolConsole, view.getPreferredFocusableComponent()); eduConsole.setCloseable(false); ui.addContent(eduConsole, 0, PlaceInGrid.right, false); @@ -155,20 +146,6 @@ public class PyEduDebugRunner extends PyDebugRunner { PyDebugRunner.initDebugConsoleView(project, process, view, processHandler, session); } - private static void switchToPythonConsole(PythonDebugLanguageConsoleView view) { - AnAction[] actions = view.createConsoleActions(); - for (AnAction action : actions) { - Presentation presentation = action.getTemplatePresentation(); - String text = presentation.getText(); - if (PyBundle.message("run.configuration.show.command.line.action.name").equals(text)) { - AnActionEvent event = - AnActionEvent.createFromAnAction(action, null, - ActionPlaces.DEBUGGER_TOOLBAR, DataManager.getInstance().getDataContext(view)); - action.actionPerformed(event); - } - } - } - @Nullable private static Content findContent(ContentManager manager, String name) { for (Content content : manager.getContents()) { @@ -178,30 +155,4 @@ public class PyEduDebugRunner extends PyDebugRunner { } return null; } - - - private static boolean isDocString(PsiElement element) { - if (element instanceof PyExpressionStatement) { - element = ((PyExpressionStatement)element).getExpression(); - } - if (element instanceof PyExpression) { - return DocStringUtil.isDocStringExpression((PyExpression)element); - } - return false; - } - - private static class PyEduDebugProcess extends PyDebugProcess { - public PyEduDebugProcess(@NotNull XDebugSession session, - @NotNull ServerSocket serverSocket, - @NotNull ExecutionConsole executionConsole, - @Nullable ProcessHandler processHandler, boolean multiProcess) { - super(session, serverSocket, executionConsole, processHandler, multiProcess); - } - - @Override - public PyStackFrame createStackFrame(PyStackFrameInfo frameInfo) { - return new PyEduStackFrame(getSession().getProject(), this, frameInfo, - getPositionConverter().convertFromPython(frameInfo.getPosition())); - } - } } \ No newline at end of file diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduFramesTransformer.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduFramesTransformer.java deleted file mode 100644 index e83a1e301500..000000000000 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduFramesTransformer.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.jetbrains.python.edu.debugger; - -import com.jetbrains.python.PythonHelpersLocator; -import com.jetbrains.python.debugger.PyDebugRunner; -import com.jetbrains.python.debugger.PyFramesTransformer; -import com.jetbrains.python.debugger.PyStackFrameInfo; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -public class PyEduFramesTransformer implements PyFramesTransformer { - @Nullable - @Override - public List transformFrames(@Nullable List frames) { - if (frames == null) { - return null; - } - String debugger = PythonHelpersLocator.getHelperPath(PyDebugRunner.DEBUGGER_MAIN); - List newFrames = new ArrayList(); - for (PyStackFrameInfo frame : frames) { - String file = frame.getPosition().getFile(); - if (!debugger.equals(file)) { - newFrames.add(frame); - } - } - return newFrames; - } -} diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduMagicDebugValue.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduMagicDebugValue.java index eebf37036dbc..ddb2f4df714c 100644 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduMagicDebugValue.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduMagicDebugValue.java @@ -8,6 +8,10 @@ import org.jetbrains.annotations.NotNull; import java.util.Map; +/** + * Represents debug value for content that should be hidden from the python beginners + * (e.g. values named with double underscore prefix and postfix) + */ public class PyEduMagicDebugValue extends XNamedValue { private final Map myValues; diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java index ca3b63b13f21..be496d1a31fb 100644 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java @@ -13,7 +13,7 @@ import org.jetbrains.annotations.NotNull; public class PyEduStackFrame extends PyStackFrame { public static final String MODULE = ""; - public static final String GLOBAL_FRAME = "Global Frame"; + public static final String GLOBAL_FRAME = "Globals"; private final PyStackFrameInfo myFrameInfo; private final XSourcePosition myPosition; diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyFramesTransformer.java b/python/pydevSrc/com/jetbrains/python/debugger/PyFramesTransformer.java deleted file mode 100644 index 302edefb7c07..000000000000 --- a/python/pydevSrc/com/jetbrains/python/debugger/PyFramesTransformer.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.jetbrains.python.debugger; - -import com.intellij.openapi.extensions.ExtensionPointName; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -public interface PyFramesTransformer { - ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.pyFramesTransformer"); - - @Nullable - List transformFrames(@Nullable List frames); -} diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java b/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java index f48c27bc226c..d7a2d5fe187c 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java @@ -1,10 +1,8 @@ package com.jetbrains.python.debugger; -import com.intellij.openapi.extensions.Extensions; import com.jetbrains.python.debugger.pydev.AbstractCommand; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -28,22 +26,11 @@ public class PyThreadInfo { String message) { myId = id; myName = name; - myFrames = prepareFrames(frames); + myFrames = (frames != null && frames.size() > 0 ? Collections.unmodifiableList(frames) : null); myStopReason = stopReason; myMessage = message; } - private static List prepareFrames(List frames) { - if (frames == null) { - return null; - } - List framesCopy = new ArrayList(frames); - for (PyFramesTransformer transformer: Extensions.getExtensions(PyFramesTransformer.EP_NAME)) { - framesCopy = transformer.transformFrames(framesCopy); - } - return framesCopy != null && framesCopy.size() > 0 ? Collections.unmodifiableList(framesCopy) : null; - } - public String getId() { return myId; } @@ -76,7 +63,7 @@ public class PyThreadInfo { public synchronized void updateState(final State state, final List frames) { myState = state; - myFrames = prepareFrames(frames); + myFrames = (frames != null && frames.size() > 0 ? Collections.unmodifiableList(frames) : null); } diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml index e77452a9d3e7..abd422fe5b3a 100644 --- a/python/src/META-INF/python-core.xml +++ b/python/src/META-INF/python-core.xml @@ -598,9 +598,7 @@ - - - + diff --git a/python/src/com/jetbrains/python/console/PyConsoleOutputFilter.java b/python/src/com/jetbrains/python/console/PyConsoleOutputFilter.java deleted file mode 100644 index 45759439b05a..000000000000 --- a/python/src/com/jetbrains/python/console/PyConsoleOutputFilter.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2000-2015 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.console; - -import com.intellij.execution.ui.ConsoleViewContentType; -import com.intellij.openapi.extensions.ExtensionPointName; -import org.jetbrains.annotations.NotNull; - -public interface PyConsoleOutputFilter { - ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.pyConsoleOutputFilter"); - - boolean reject(@NotNull String text, @NotNull final ConsoleViewContentType outputType); -} diff --git a/python/src/com/jetbrains/python/console/PythonConsoleView.java b/python/src/com/jetbrains/python/console/PythonConsoleView.java index a78fc2e61401..d5ddcb6f5175 100644 --- a/python/src/com/jetbrains/python/console/PythonConsoleView.java +++ b/python/src/com/jetbrains/python/console/PythonConsoleView.java @@ -25,7 +25,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.colors.EditorColorsScheme; -import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; @@ -178,12 +177,6 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable @Override public void print(@NotNull String text, @NotNull final ConsoleViewContentType outputType) { - for (PyConsoleOutputFilter filter : Extensions.getExtensions(PyConsoleOutputFilter.EP_NAME)) { - if (filter.reject(text, outputType)) { - return; - } - } - detectIPython(text, outputType); if (PyConsoleUtil.detectIPythonEnd(text)) { myIsIPythonOutput = false; diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index 0ab8651f56fd..83e44db7ff2c 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -668,6 +668,12 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr } } + public void addTemporaryBreakpoint(String typeId, String file, int line) { + if (isConnected()) { + myDebugger.setTempBreakpoint(typeId, file, line); + } + } + public void removeBreakpoint(final PySourcePosition position) { XLineBreakpoint breakpoint = myRegisteredBreakpoints.get(position); if (breakpoint != null) { @@ -703,7 +709,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr final List frames = threadInfo.getFrames(); if (frames != null) { - final PySuspendContext suspendContext = new PySuspendContext(this, threadInfo); + final PySuspendContext suspendContext = createSuspendContext(threadInfo); XBreakpoint breakpoint = null; if (threadInfo.isStopOnBreakpoint()) { @@ -733,6 +739,11 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr } } + @NotNull + protected PySuspendContext createSuspendContext(PyThreadInfo threadInfo) { + return new PySuspendContext(this, threadInfo); + } + @Override public void threadResumed(final PyThreadInfo threadInfo) { mySuspendedThreads.remove(threadInfo); diff --git a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java index 2d0c5416350f..728936052ced 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java @@ -45,7 +45,6 @@ import com.jetbrains.python.console.pydev.ConsoleCommunicationListener; import com.jetbrains.python.run.AbstractPythonRunConfiguration; import com.jetbrains.python.run.CommandLinePatcher; import com.jetbrains.python.run.PythonCommandLineState; -import com.jetbrains.python.run.PythonRunConfiguration; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -102,7 +101,6 @@ public class PyDebugRunner extends GenericProgramRunner { createDebugProcess(session, serverSocket, result, pyState); createConsoleCommunicationAndSetupActions(environment.getProject(), result, pyDebugProcess, session); - initDebugProcess(((PythonRunConfiguration)environment.getRunProfile()).getScriptName(), pyDebugProcess); return pyDebugProcess; } }); @@ -117,9 +115,6 @@ public class PyDebugRunner extends GenericProgramRunner { pyState.isMultiprocessDebug()); } - protected void initDebugProcess(String name, PyDebugProcess pyDebugProcess) { - } - @Override protected RunContentDescriptor doExecute(@NotNull RunProfileState state, @NotNull final ExecutionEnvironment environment) throws ExecutionException { XDebugSession session = createSession(state, environment); diff --git a/python/src/com/jetbrains/python/debugger/PyDebugValueTransformer.java b/python/src/com/jetbrains/python/debugger/PyDebugValueTransformer.java index b92802984070..3b697d5e891e 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugValueTransformer.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugValueTransformer.java @@ -20,7 +20,7 @@ import com.intellij.xdebugger.frame.XValueChildrenList; import org.jetbrains.annotations.NotNull; public interface PyDebugValueTransformer { - ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.pyDebugValueTransformer"); + ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.debugValueTransformer"); /** * This method is used in python debugger to modify content and presentation of stack frame nodes From ac20259254eedd68082b91d523f3f7ed9b6172f8 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Fri, 14 Aug 2015 20:00:44 +0300 Subject: [PATCH 07/16] added missing file --- .../PyEduConsoleInputFilterProvider.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 python/edu/src/com/jetbrains/python/edu/debugger/PyEduConsoleInputFilterProvider.java diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduConsoleInputFilterProvider.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduConsoleInputFilterProvider.java new file mode 100644 index 000000000000..0f74c0277511 --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduConsoleInputFilterProvider.java @@ -0,0 +1,32 @@ +package com.jetbrains.python.edu.debugger; + +import com.intellij.execution.filters.ConsoleInputFilterProvider; +import com.intellij.execution.filters.InputFilter; +import com.intellij.execution.ui.ConsoleViewContentType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; + +public class PyEduConsoleInputFilterProvider implements ConsoleInputFilterProvider { + @NotNull + @Override + public InputFilter[] getDefaultFilters(@NotNull Project project) { + return new InputFilter[]{new InputFilter() { + @Nullable + @Override + public List> applyFilter(String text, ConsoleViewContentType outputType) { + if (outputType.equals(ConsoleViewContentType.SYSTEM_OUTPUT) && !text.contains("exit code")) { + return Collections.emptyList(); + } + if (text.startsWith("pydev debugger")) { + return Collections.emptyList(); + } + return Collections.singletonList(Pair.create(text, outputType)); + } + }}; + } +} From b7150d00d42e2053a161e1fd91420ba1bc1460f5 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Fri, 14 Aug 2015 20:10:31 +0300 Subject: [PATCH 08/16] renamed "Output" back to "Console" --- .../com/jetbrains/python/edu/debugger/PyEduDebugRunner.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java index 15d2fc98cdea..244eb2cc91dd 100644 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java @@ -40,7 +40,6 @@ import java.io.File; import java.net.ServerSocket; public class PyEduDebugRunner extends PyDebugRunner { - public static final String OUTPUT = "Output"; private static final Logger LOG = Logger.getInstance(PyEduDebugRunner.class); public static final int NO_LINE = -1; @@ -138,7 +137,9 @@ public class PyEduDebugRunner extends PyDebugRunner { view.enableConsole(false); Content eduConsole = - ui.createContent(OUTPUT, view.getComponent(), OUTPUT, AllIcons.Debugger.ToolConsole, view.getPreferredFocusableComponent()); + ui.createContent("EduConsole", view.getComponent(), + XDebuggerBundle.message("debugger.session.tab.console.content.name"), + AllIcons.Debugger.ToolConsole, view.getPreferredFocusableComponent()); eduConsole.setCloseable(false); ui.addContent(eduConsole, 0, PlaceInGrid.right, false); From d917649909e2bc6b949c4730e00adba4c1ff051c Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 19 Aug 2015 11:00:39 +0300 Subject: [PATCH 09/16] removed redundant extension point --- python/edu/src/META-INF/PyCharmEduPlugin.xml | 4 --- .../edu/debugger/PyEduDebugTransformer.java | 31 ----------------- .../python/edu/debugger/PyEduStackFrame.java | 33 +++++++++++++++++++ python/src/META-INF/python-core.xml | 1 - .../debugger/PyDebugValueTransformer.java | 31 ----------------- .../python/debugger/PyStackFrame.java | 15 ++++----- 6 files changed, 39 insertions(+), 76 deletions(-) delete mode 100644 python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugTransformer.java delete mode 100644 python/src/com/jetbrains/python/debugger/PyDebugValueTransformer.java diff --git a/python/edu/src/META-INF/PyCharmEduPlugin.xml b/python/edu/src/META-INF/PyCharmEduPlugin.xml index 743e43a7d779..a1724898ccfd 100644 --- a/python/edu/src/META-INF/PyCharmEduPlugin.xml +++ b/python/edu/src/META-INF/PyCharmEduPlugin.xml @@ -35,10 +35,6 @@ - - - - diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugTransformer.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugTransformer.java deleted file mode 100644 index a4ce04444bea..000000000000 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugTransformer.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.jetbrains.python.edu.debugger; - -import com.intellij.util.containers.hash.HashMap; -import com.intellij.xdebugger.frame.XValue; -import com.intellij.xdebugger.frame.XValueChildrenList; -import com.jetbrains.python.debugger.PyDebugValueTransformer; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; - -public class PyEduDebugTransformer implements PyDebugValueTransformer { - @Override - public XValueChildrenList getTransformedChildren(@NotNull XValueChildrenList children) { - XValueChildrenList list = new XValueChildrenList(); - Map magicValues = new HashMap(); - for (int i = 0; i < children.size(); i++) { - String name = children.getName(i); - XValue value = children.getValue(i); - if (name.startsWith("__") && name.endsWith("__")) { - magicValues.put(name, value); - } - else { - list.add(name, value); - } - } - if (!magicValues.isEmpty()) { - list.add(new PyEduMagicDebugValue("magic variables", magicValues)); - } - return list; - } -} diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java index be496d1a31fb..f88c23e7dc7e 100644 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java @@ -5,15 +5,23 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.ColoredTextContainer; import com.intellij.ui.SimpleTextAttributes; +import com.intellij.util.containers.hash.HashMap; import com.intellij.xdebugger.XSourcePosition; +import com.intellij.xdebugger.frame.XCompositeNode; +import com.intellij.xdebugger.frame.XValue; +import com.intellij.xdebugger.frame.XValueChildrenList; import com.jetbrains.python.debugger.PyFrameAccessor; import com.jetbrains.python.debugger.PyStackFrame; import com.jetbrains.python.debugger.PyStackFrameInfo; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; public class PyEduStackFrame extends PyStackFrame { public static final String MODULE = ""; public static final String GLOBAL_FRAME = "Globals"; + public static final String DOUBLE_UNDERSCORE = "__"; private final PyStackFrameInfo myFrameInfo; private final XSourcePosition myPosition; @@ -48,4 +56,29 @@ public class PyEduStackFrame extends PyStackFrame { .append(MODULE.equals(frameName) ? GLOBAL_FRAME : frameName, regularAttributes); } } + + @Override + protected void addChildren(@NotNull final XCompositeNode node, + @Nullable final XValueChildrenList children) { + Map specialValues = new HashMap(); + XValueChildrenList newChildren = new XValueChildrenList(); + if (children == null) { + node.addChildren(XValueChildrenList.EMPTY, true); + return; + } + for (int i = 0; i < children.size(); i++) { + String name = children.getName(i); + XValue value = children.getValue(i); + if (name.startsWith(DOUBLE_UNDERSCORE) && name.endsWith(DOUBLE_UNDERSCORE)) { + specialValues.put(name, value); + } + else { + newChildren.add(name, value); + } + } + if (!specialValues.isEmpty()) { + newChildren.add(new PyEduMagicDebugValue("special variables", specialValues)); + } + node.addChildren(newChildren, true); + } } diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml index abd422fe5b3a..476948f3a9bc 100644 --- a/python/src/META-INF/python-core.xml +++ b/python/src/META-INF/python-core.xml @@ -598,7 +598,6 @@ - diff --git a/python/src/com/jetbrains/python/debugger/PyDebugValueTransformer.java b/python/src/com/jetbrains/python/debugger/PyDebugValueTransformer.java deleted file mode 100644 index 3b697d5e891e..000000000000 --- a/python/src/com/jetbrains/python/debugger/PyDebugValueTransformer.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2000-2015 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.debugger; - -import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.xdebugger.frame.XValueChildrenList; -import org.jetbrains.annotations.NotNull; - -public interface PyDebugValueTransformer { - ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.debugValueTransformer"); - - /** - * This method is used in python debugger to modify content and presentation of stack frame nodes - * @param children - * @return modified children list - */ - XValueChildrenList getTransformedChildren(@NotNull final XValueChildrenList children); -} diff --git a/python/src/com/jetbrains/python/debugger/PyStackFrame.java b/python/src/com/jetbrains/python/debugger/PyStackFrame.java index 80cce5540e6f..4ada2e7fc112 100644 --- a/python/src/com/jetbrains/python/debugger/PyStackFrame.java +++ b/python/src/com/jetbrains/python/debugger/PyStackFrame.java @@ -19,7 +19,6 @@ import com.intellij.icons.AllIcons; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; @@ -32,6 +31,7 @@ import com.intellij.xdebugger.frame.XCompositeNode; import com.intellij.xdebugger.frame.XStackFrame; import com.intellij.xdebugger.frame.XValueChildrenList; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class PyStackFrame extends XStackFrame { @@ -115,14 +115,7 @@ public class PyStackFrame extends XStackFrame { try { XValueChildrenList values = myDebugProcess.loadFrame(); if (!node.isObsolete()) { - if (values == null) { - node.addChildren(XValueChildrenList.EMPTY, true); - return; - } - for (PyDebugValueTransformer transformer : Extensions.getExtensions(PyDebugValueTransformer.EP_NAME)) { - values = transformer.getTransformedChildren(values); - } - node.addChildren(values, true); + addChildren(node, values); } } catch (PyDebuggerException e) { @@ -135,6 +128,10 @@ public class PyStackFrame extends XStackFrame { }); } + protected void addChildren(@NotNull final XCompositeNode node, @Nullable final XValueChildrenList children) { + node.addChildren(children != null ? children : XValueChildrenList.EMPTY, true); + } + public String getThreadId() { return myFrameInfo.getThreadId(); } From 59f8b37d6dfbdaf3fd16399c57459ebac028a622 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 19 Aug 2015 14:07:54 +0300 Subject: [PATCH 10/16] changed presentation of some debug values There is no need in custom DebugValue because we have XVaueGroup. Also changed the name of new special value after discussion. --- .../edu/debugger/PyEduMagicDebugValue.java | 49 -------------- .../python/edu/debugger/PyEduStackFrame.java | 66 ++++++++++++++----- 2 files changed, 48 insertions(+), 67 deletions(-) delete mode 100644 python/edu/src/com/jetbrains/python/edu/debugger/PyEduMagicDebugValue.java diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduMagicDebugValue.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduMagicDebugValue.java deleted file mode 100644 index ddb2f4df714c..000000000000 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduMagicDebugValue.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.jetbrains.python.edu.debugger; - - -import com.intellij.icons.AllIcons; -import com.intellij.xdebugger.frame.*; -import com.intellij.xdebugger.frame.presentation.XValuePresentation; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; - -/** - * Represents debug value for content that should be hidden from the python beginners - * (e.g. values named with double underscore prefix and postfix) - */ -public class PyEduMagicDebugValue extends XNamedValue { - - private final Map myValues; - - protected PyEduMagicDebugValue(@NotNull String name, Map values) { - super(name); - myValues = values; - } - - @Override - public void computePresentation(@NotNull XValueNode node, @NotNull XValuePlace place) { - node.setPresentation(AllIcons.Nodes.Artifact, new XValuePresentation() { - - @Override - public void renderValue(@NotNull XValueTextRenderer renderer) { - renderer.renderComment("{Python Pro Only}"); - } - - @NotNull - @Override - public String getSeparator() { - return " "; - } - }, true); - } - - @Override - public void computeChildren(@NotNull XCompositeNode node) { - XValueChildrenList children = new XValueChildrenList(); - for (Map.Entry entry : myValues.entrySet()) { - children.add(entry.getKey(), entry.getValue()); - } - node.addChildren(children, true); - } -} \ No newline at end of file diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java index f88c23e7dc7e..f9b3f172cf65 100644 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java @@ -5,23 +5,27 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.ColoredTextContainer; import com.intellij.ui.SimpleTextAttributes; -import com.intellij.util.containers.hash.HashMap; import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.frame.XCompositeNode; import com.intellij.xdebugger.frame.XValue; import com.intellij.xdebugger.frame.XValueChildrenList; +import com.intellij.xdebugger.frame.XValueGroup; import com.jetbrains.python.debugger.PyFrameAccessor; import com.jetbrains.python.debugger.PyStackFrame; import com.jetbrains.python.debugger.PyStackFrameInfo; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; +import java.util.HashMap; import java.util.Map; public class PyEduStackFrame extends PyStackFrame { public static final String MODULE = ""; public static final String GLOBAL_FRAME = "Globals"; public static final String DOUBLE_UNDERSCORE = "__"; + public static final String BUILTINS_VALUE_NAME = "__builtins__"; + private final PyStackFrameInfo myFrameInfo; private final XSourcePosition myPosition; @@ -36,49 +40,75 @@ public class PyEduStackFrame extends PyStackFrame { @Override public void customizePresentation(@NotNull ColoredTextContainer component) { - component.setIcon(AllIcons.Debugger.StackFrame); if (myPosition == null) { component.append("", SimpleTextAttributes.GRAY_ATTRIBUTES); return; } - final VirtualFile file = myPosition.getFile(); - String frameName = myFrameInfo.getName(); + //TODO: get icons from designers component.setIcon(MODULE.equals(frameName) ? AllIcons.FileTypes.Text : AllIcons.Nodes.Field); - SimpleTextAttributes regularAttributes = SimpleTextAttributes.REGULAR_ATTRIBUTES; if (MODULE.equals(frameName)) { - component.append(GLOBAL_FRAME, regularAttributes); - component.append(" (" + file.getName() + ")", getGrayAttributes(regularAttributes)); + component.append(GLOBAL_FRAME, SimpleTextAttributes.REGULAR_ATTRIBUTES); + component.append(" (" + file.getName() + ")", getGrayAttributes(SimpleTextAttributes.REGULAR_ATTRIBUTES)); } else { - component - .append(MODULE.equals(frameName) ? GLOBAL_FRAME : frameName, regularAttributes); + component.append(frameName, SimpleTextAttributes.REGULAR_ATTRIBUTES); } } @Override protected void addChildren(@NotNull final XCompositeNode node, @Nullable final XValueChildrenList children) { - Map specialValues = new HashMap(); - XValueChildrenList newChildren = new XValueChildrenList(); if (children == null) { node.addChildren(XValueChildrenList.EMPTY, true); return; } + final Map specialValues = new HashMap(); + XValueChildrenList filteredChildren = new XValueChildrenList(); for (int i = 0; i < children.size(); i++) { String name = children.getName(i); XValue value = children.getValue(i); if (name.startsWith(DOUBLE_UNDERSCORE) && name.endsWith(DOUBLE_UNDERSCORE)) { specialValues.put(name, value); + continue; } - else { - newChildren.add(name, value); + filteredChildren.add(name, value); + } + node.addChildren(filteredChildren, specialValues.isEmpty()); + if (specialValues.isEmpty()) { + return; + } + addSpecialVars(node, specialValues); + } + + private static void addSpecialVars(@NotNull XCompositeNode node, Map specialValues) { + XValue builtins = specialValues.get(BUILTINS_VALUE_NAME); + if (builtins != null) { + specialValues.remove(BUILTINS_VALUE_NAME); + node.addChildren(XValueChildrenList.singleton("Builtins", builtins), false); } - } - if (!specialValues.isEmpty()) { - newChildren.add(new PyEduMagicDebugValue("special variables", specialValues)); - } - node.addChildren(newChildren, true); + node.addChildren(XValueChildrenList.bottomGroup(createSpecialVarsGroup(specialValues)), true); + } + + @NotNull + private static XValueGroup createSpecialVarsGroup(final Map specialValues) { + return new XValueGroup("Special Variables") { + @Nullable + @Override + public Icon getIcon() { + //TODO: get icon from designers + return AllIcons.Nodes.Artifact; + } + + @Override + public void computeChildren(@NotNull XCompositeNode node) { + XValueChildrenList list = new XValueChildrenList(); + for (Map.Entry entry : specialValues.entrySet()) { + list.add(entry.getKey(), entry.getValue()); + } + node.addChildren(list, true); + } + }; } } From e10b6eb6c2af7ea4a5d719e1edc11583dd9d859a Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 19 Aug 2015 15:41:47 +0300 Subject: [PATCH 11/16] added icons --- .../edu/gen/icons/PythonEducationalIcons.java | 17 +++++++++++++++++ python/edu/resources/icon-robots.txt | 1 + .../icons/com/jetbrains/edu/Field.png | Bin 0 -> 307 bytes .../icons/com/jetbrains/edu/Field@2x.png | Bin 0 -> 537 bytes .../python/edu/debugger/PyEduStackFrame.java | 5 +++-- 5 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 python/edu/gen/icons/PythonEducationalIcons.java create mode 100644 python/edu/resources/icon-robots.txt create mode 100644 python/edu/resources/icons/com/jetbrains/edu/Field.png create mode 100644 python/edu/resources/icons/com/jetbrains/edu/Field@2x.png diff --git a/python/edu/gen/icons/PythonEducationalIcons.java b/python/edu/gen/icons/PythonEducationalIcons.java new file mode 100644 index 000000000000..c8828ed8ae68 --- /dev/null +++ b/python/edu/gen/icons/PythonEducationalIcons.java @@ -0,0 +1,17 @@ +package icons; + +import com.intellij.openapi.util.IconLoader; + +import javax.swing.*; + +/** + * NOTE THIS FILE IS AUTO-GENERATED + * DO NOT EDIT IT BY HAND, run build/scripts/icons.gant instead + */ +public class PythonEducationalIcons { + private static Icon load(String path) { + return IconLoader.getIcon(path, PythonEducationalIcons.class); + } + + public static final Icon Field = load("/icons/com/jetbrains/edu/Field.png"); // 16x16 +} diff --git a/python/edu/resources/icon-robots.txt b/python/edu/resources/icon-robots.txt new file mode 100644 index 000000000000..c6ebcdbff50a --- /dev/null +++ b/python/edu/resources/icon-robots.txt @@ -0,0 +1 @@ +skip: tips diff --git a/python/edu/resources/icons/com/jetbrains/edu/Field.png b/python/edu/resources/icons/com/jetbrains/edu/Field.png new file mode 100644 index 0000000000000000000000000000000000000000..f4a6122dbe7b80f0c70d04f4729e09614a0dbe15 GIT binary patch literal 307 zcmV-30nGl1P)~y>sqz0rGsOKfJ0YHf< z|G%A?N)!gE1?fREU=jvi)RXtWDmUi;<&Di4a+n63?8Crmal!xh&M(I*hiSm^E)=|~ zKj(jPbin_nqS*hJ*VSOiV;Jz|Xe$OziuV71aDEY1IZOi%H)7zVD4+rJ^0CTc8gQTn z11ClK{XaM-2df;00iXAkW8kDn-~R_@Wnh)VG+<9LNf^U`kGt~!f7(qP2B}3i;LY=O zY5za&$ocf415yjpgKR($5WgTHGra`jP`CkGy!6H{BX5lRU~#1Pk1Q(|YuMu zs{r|>aknIk zRWK5v&%ffwfXqWkDKfxFEVDdc2-ui(fw!$5TAVeoFw)AKBLnUiSwg`!xfty%dEsd{ z$eN=A?&euMdL6Vls$taIz@9;L!0j9hE=OWWXU`xy;AXa<@MbTFK(o2LN^&>XLeS@g ztyvd2i|Bysse+C-eNsMPxLcE-6We}r7Lft(@ktilQ7MT)6MF{H0ap_&x>hNP!AABB zq603+SiS-p*fWR@I3HorwF*fLIN39Z4u}o2d<8hzGl&dG#{w+6RxXJFjXi_tfKxw< zZZDUF-_D*vbihd;i*7HIM1MVd2GIf0UZv=Oh)*dpAQkCRiVR4GyCHR~Ml#%0FhE{P zUk_c73VW2mvkP5H<+c1}KOf;Pn&gq&JhRih@_)V!qJQ#Xf=YAGr>ug-+1%NsmQS;P b`#Syra@IJj6+uvP00000NkvXXu0mjf*YoXh literal 0 HcmV?d00001 diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java index f9b3f172cf65..f8b557e2b418 100644 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java @@ -13,6 +13,8 @@ import com.intellij.xdebugger.frame.XValueGroup; import com.jetbrains.python.debugger.PyFrameAccessor; import com.jetbrains.python.debugger.PyStackFrame; import com.jetbrains.python.debugger.PyStackFrameInfo; +import icons.PythonEducationalIcons; +import icons.PythonPsiApiIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,8 +48,7 @@ public class PyEduStackFrame extends PyStackFrame { } final VirtualFile file = myPosition.getFile(); String frameName = myFrameInfo.getName(); - //TODO: get icons from designers - component.setIcon(MODULE.equals(frameName) ? AllIcons.FileTypes.Text : AllIcons.Nodes.Field); + component.setIcon(MODULE.equals(frameName) ? PythonPsiApiIcons.PythonFile : PythonEducationalIcons.Field); if (MODULE.equals(frameName)) { component.append(GLOBAL_FRAME, SimpleTextAttributes.REGULAR_ATTRIBUTES); component.append(" (" + file.getName() + ")", getGrayAttributes(SimpleTextAttributes.REGULAR_ATTRIBUTES)); From 239c7761c67501d308564b94c67eaaa03cecbd8c Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 19 Aug 2015 19:16:22 +0300 Subject: [PATCH 12/16] EDU-380 Merge PyDebugFileLineMarkerProvider and PyExecuteFileLineMarkerProvider there is no need in additional actions at all, because there are created in ExecutorRegistry for every executor --- python/edu/src/META-INF/PyCharmEduPlugin.xml | 10 +-- .../python/edu/PyDebugCurrentFile.java | 16 +++++ .../python/edu/PyDebugCurrentFileAction.java | 23 ------- .../edu/PyDebugFileLineMarkerProvider.java | 53 --------------- .../com/jetbrains/python/edu/PyEduUtils.java | 33 ---------- .../edu/PyExecuteFileExtensionPoint.java | 4 +- .../edu/PyExecuteFileLineMarkerProvider.java | 66 +++++++++++-------- .../edu/PyRunConfigurationForFileAction.java | 54 --------------- .../python/edu/PyRunCurrentFileAction.java | 26 -------- .../edu/debugger/PyEduDebugExecutor.java | 2 +- 10 files changed, 59 insertions(+), 228 deletions(-) create mode 100644 python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFile.java delete mode 100644 python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFileAction.java delete mode 100644 python/edu/src/com/jetbrains/python/edu/PyDebugFileLineMarkerProvider.java delete mode 100644 python/edu/src/com/jetbrains/python/edu/PyEduUtils.java delete mode 100644 python/edu/src/com/jetbrains/python/edu/PyRunConfigurationForFileAction.java delete mode 100644 python/edu/src/com/jetbrains/python/edu/PyRunCurrentFileAction.java diff --git a/python/edu/src/META-INF/PyCharmEduPlugin.xml b/python/edu/src/META-INF/PyCharmEduPlugin.xml index a1724898ccfd..b1dfd7039a3d 100644 --- a/python/edu/src/META-INF/PyCharmEduPlugin.xml +++ b/python/edu/src/META-INF/PyCharmEduPlugin.xml @@ -28,12 +28,14 @@ - + + + @@ -53,11 +55,5 @@ - - - - - - diff --git a/python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFile.java b/python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFile.java new file mode 100644 index 000000000000..f9f9a6883e5e --- /dev/null +++ b/python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFile.java @@ -0,0 +1,16 @@ +package com.jetbrains.python.edu; + +import com.intellij.execution.actions.RunContextAction; +import com.intellij.openapi.actionSystem.AnAction; +import com.jetbrains.python.edu.debugger.PyEduDebugExecutor; +import org.jetbrains.annotations.Nullable; + +public class PyDebugCurrentFile implements PyExecuteFileExtensionPoint { + + @Nullable + @Override + public AnAction getRunAction() { + return new RunContextAction(PyEduDebugExecutor.getInstance()); + } +} + diff --git a/python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFileAction.java b/python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFileAction.java deleted file mode 100644 index bd9373f0057d..000000000000 --- a/python/edu/src/com/jetbrains/python/edu/PyDebugCurrentFileAction.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.jetbrains.python.edu; - -import com.intellij.execution.RunnerAndConfigurationSettings; -import com.intellij.execution.runners.ExecutionUtil; -import com.intellij.icons.AllIcons; -import com.jetbrains.python.edu.debugger.PyEduDebugExecutor; - -public class PyDebugCurrentFileAction extends PyRunConfigurationForFileAction { - - public PyDebugCurrentFileAction() { - getTemplatePresentation().setIcon(AllIcons.Actions.StartDebugger); - } - - @Override - protected String getConfigurationType() { - return "Debug"; - } - - @Override - protected void runConfiguration(RunnerAndConfigurationSettings configuration) { - ExecutionUtil.runConfiguration(configuration, PyEduDebugExecutor.getInstance()); - } -} diff --git a/python/edu/src/com/jetbrains/python/edu/PyDebugFileLineMarkerProvider.java b/python/edu/src/com/jetbrains/python/edu/PyDebugFileLineMarkerProvider.java deleted file mode 100644 index 94edd56c730a..000000000000 --- a/python/edu/src/com/jetbrains/python/edu/PyDebugFileLineMarkerProvider.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.jetbrains.python.edu; - -import com.intellij.codeHighlighting.Pass; -import com.intellij.codeInsight.daemon.GutterIconNavigationHandler; -import com.intellij.codeInsight.daemon.LineMarkerInfo; -import com.intellij.codeInsight.daemon.LineMarkerProvider; -import com.intellij.execution.actions.ConfigurationContext; -import com.intellij.icons.AllIcons; -import com.intellij.ide.DataManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.markup.GutterIconRenderer; -import com.intellij.psi.PsiElement; -import com.intellij.psi.util.PsiUtilBase; -import com.intellij.util.Function; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.event.MouseEvent; -import java.util.Collection; -import java.util.List; - -public class PyDebugFileLineMarkerProvider implements LineMarkerProvider { - @Nullable - @Override - public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) { - return null; - } - - @Override - public void collectSlowLineMarkers(@NotNull List elements, @NotNull Collection result) { - for (final PsiElement element : elements) { - if (PyEduUtils.isFirstCodeLine(element)) { - result.add(new LineMarkerInfo(element, element.getTextRange(), AllIcons.Actions.StartDebugger, - Pass.UPDATE_OVERRIDEN_MARKERS, - new Function() { - @Override - public String fun(PsiElement e) { - return "Debug '" + e.getContainingFile().getName() + "'"; - } - }, new GutterIconNavigationHandler() { - @Override - public void navigate(MouseEvent e, PsiElement elt) { - final Editor editor = PsiUtilBase.findEditor(elt); - assert editor != null; - ConfigurationContext configurationContext = - ConfigurationContext.getFromContext(DataManager.getInstance().getDataContext(editor.getComponent())); - new PyDebugCurrentFileAction().run(configurationContext); - } - }, GutterIconRenderer.Alignment.RIGHT)); - } - } - } -} diff --git a/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java b/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java deleted file mode 100644 index bdc0d402fa40..000000000000 --- a/python/edu/src/com/jetbrains/python/edu/PyEduUtils.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.jetbrains.python.edu; - -import com.intellij.psi.PsiComment; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiWhiteSpace; -import com.jetbrains.python.psi.PyFile; -import com.jetbrains.python.psi.PyImportStatement; -import com.jetbrains.python.psi.PyStatement; - -public class PyEduUtils { - public static boolean isFirstCodeLine(PsiElement element) { - return element instanceof PyStatement && - element.getParent() instanceof PyFile && - !isNothing(element) && - nothingBefore(element); - } - - private static boolean nothingBefore(PsiElement element) { - element = element.getPrevSibling(); - while (element != null) { - if (!isNothing(element)) { - return false; - } - element = element.getPrevSibling(); - } - - return true; - } - - private static boolean isNothing(PsiElement element) { - return (element instanceof PsiComment) || (element instanceof PyImportStatement) || (element instanceof PsiWhiteSpace); - } -} diff --git a/python/edu/src/com/jetbrains/python/edu/PyExecuteFileExtensionPoint.java b/python/edu/src/com/jetbrains/python/edu/PyExecuteFileExtensionPoint.java index 7f5a077c2650..d0c54fe86b3b 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyExecuteFileExtensionPoint.java +++ b/python/edu/src/com/jetbrains/python/edu/PyExecuteFileExtensionPoint.java @@ -17,13 +17,13 @@ package com.jetbrains.python.edu; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.extensions.ExtensionPointName; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public interface PyExecuteFileExtensionPoint { ExtensionPointName EP_NAME = ExtensionPointName.create("Edu.executeFile"); - @NotNull + @Nullable AnAction getRunAction(); } diff --git a/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java b/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java index e22713dbfa26..c38577cb6884 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java +++ b/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java @@ -3,17 +3,21 @@ package com.jetbrains.python.edu; import com.intellij.codeHighlighting.Pass; import com.intellij.codeInsight.daemon.LineMarkerInfo; import com.intellij.codeInsight.daemon.LineMarkerProvider; +import com.intellij.execution.actions.RunContextAction; +import com.intellij.execution.executors.DefaultRunExecutor; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.markup.GutterIconRenderer; -import com.intellij.openapi.ui.popup.ListPopup; +import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; -import com.intellij.ui.popup.PopupFactoryImpl; +import com.intellij.psi.PsiWhiteSpace; import com.intellij.util.Function; +import com.jetbrains.python.psi.PyFile; +import com.jetbrains.python.psi.PyImportStatement; +import com.jetbrains.python.psi.PyStatement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -33,7 +37,8 @@ public class PyExecuteFileLineMarkerProvider implements LineMarkerProvider { @Override public void collectSlowLineMarkers(@NotNull List elements, @NotNull Collection result) { for (PsiElement element : elements) { - if (PyEduUtils.isFirstCodeLine(element)) { + if (isFirstCodeLine(element)) { + final RunContextAction runAction = new RunContextAction(DefaultRunExecutor.getRunExecutorInstance()); final LineMarkerInfo markerInfo = new LineMarkerInfo( element, element.getTextRange(), AllIcons.Actions.Execute, Pass.UPDATE_OVERRIDEN_MARKERS, new Function() { @@ -49,41 +54,21 @@ public class PyExecuteFileLineMarkerProvider implements LineMarkerProvider { return new LineMarkerGutterIconRenderer(this){ @Override public AnAction getClickAction() { - - return new AnAction() { - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - final DefaultActionGroup group = new DefaultActionGroup(); - group.add(new PyRunCurrentFileAction()); - final PyExecuteFileExtensionPoint[] extensions = - ApplicationManager.getApplication().getExtensions(PyExecuteFileExtensionPoint.EP_NAME); - for (PyExecuteFileExtensionPoint extension : extensions) { - final AnAction action = extension.getRunAction(); - action.update(e); - if (e.getPresentation().isEnabled()) - group.add(action); - } - if (group.getChildrenCount() == 1) { - new PyRunCurrentFileAction().actionPerformed(e); - } - else { - final ListPopup popup = - new PopupFactoryImpl().createActionGroupPopup(null, group, e.getDataContext(), false, false, false, null, 5); - popup.showInBestPositionFor(e.getDataContext()); - } - } - }; + return runAction; } @Nullable @Override public ActionGroup getPopupMenuActions() { final DefaultActionGroup group = new DefaultActionGroup(); - group.add(new PyRunCurrentFileAction()); + group.add(runAction); final PyExecuteFileExtensionPoint[] extensions = ApplicationManager.getApplication().getExtensions(PyExecuteFileExtensionPoint.EP_NAME); for (PyExecuteFileExtensionPoint extension : extensions) { final AnAction action = extension.getRunAction(); + if (action == null) { + continue; + } group.add(action); } return group; @@ -95,4 +80,27 @@ public class PyExecuteFileLineMarkerProvider implements LineMarkerProvider { } } } + + private static boolean isFirstCodeLine(PsiElement element) { + return element instanceof PyStatement && + element.getParent() instanceof PyFile && + !isNothing(element) && + nothingBefore(element); + } + + private static boolean nothingBefore(PsiElement element) { + element = element.getPrevSibling(); + while (element != null) { + if (!isNothing(element)) { + return false; + } + element = element.getPrevSibling(); + } + + return true; + } + + private static boolean isNothing(PsiElement element) { + return (element instanceof PsiComment) || (element instanceof PyImportStatement) || (element instanceof PsiWhiteSpace); + } } diff --git a/python/edu/src/com/jetbrains/python/edu/PyRunConfigurationForFileAction.java b/python/edu/src/com/jetbrains/python/edu/PyRunConfigurationForFileAction.java deleted file mode 100644 index 8c42fe2b43b2..000000000000 --- a/python/edu/src/com/jetbrains/python/edu/PyRunConfigurationForFileAction.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.jetbrains.python.edu; - -import com.intellij.execution.Location; -import com.intellij.execution.RunManagerEx; -import com.intellij.execution.RunnerAndConfigurationSettings; -import com.intellij.execution.actions.ConfigurationContext; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.Presentation; -import com.jetbrains.python.PythonFileType; -import org.jetbrains.annotations.NotNull; - -public abstract class PyRunConfigurationForFileAction extends AnAction { - - @Override - public void update(AnActionEvent e) { - Presentation presentation = e.getPresentation(); - final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext()); - if (context.findExisting() == null && context.getConfiguration() == null) { - return; - } - Location location = context.getLocation(); - if (location != null && location.getPsiElement().getContainingFile() != null && location.getPsiElement().getContainingFile().getFileType() == PythonFileType.INSTANCE) { - presentation.setEnabled(true); - presentation.setText(getConfigurationType() + " '" + location.getPsiElement().getContainingFile().getName() + "'"); - } - } - - protected abstract String getConfigurationType(); - - @Override - public void actionPerformed(AnActionEvent e) { - final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext()); - - run(context); - } - - public void run(@NotNull ConfigurationContext context) { - RunnerAndConfigurationSettings configuration = context.findExisting(); - final RunManagerEx runManager = (RunManagerEx)context.getRunManager(); - if (configuration == null) { - configuration = context.getConfiguration(); - if (configuration == null) { - return; - } - runManager.setTemporaryConfiguration(configuration); - } - runManager.setSelectedConfiguration(configuration); - - runConfiguration(configuration); - } - - protected abstract void runConfiguration(RunnerAndConfigurationSettings configuration); -} diff --git a/python/edu/src/com/jetbrains/python/edu/PyRunCurrentFileAction.java b/python/edu/src/com/jetbrains/python/edu/PyRunCurrentFileAction.java deleted file mode 100644 index 160bd757884d..000000000000 --- a/python/edu/src/com/jetbrains/python/edu/PyRunCurrentFileAction.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.jetbrains.python.edu; - -import com.intellij.execution.RunnerAndConfigurationSettings; -import com.intellij.execution.executors.DefaultRunExecutor; -import com.intellij.execution.runners.ExecutionUtil; -import com.intellij.icons.AllIcons; - -/** - * @author traff - */ -public class PyRunCurrentFileAction extends PyRunConfigurationForFileAction { - - public PyRunCurrentFileAction() { - getTemplatePresentation().setIcon(AllIcons.Actions.Execute); - } - - @Override - protected String getConfigurationType() { - return "Run"; - } - - @Override - protected void runConfiguration(RunnerAndConfigurationSettings configuration) { - ExecutionUtil.runConfiguration(configuration, DefaultRunExecutor.getRunExecutorInstance()); - } -} diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugExecutor.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugExecutor.java index fe9e573dd86f..4c05b0df8d17 100644 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugExecutor.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugExecutor.java @@ -26,6 +26,6 @@ public class PyEduDebugExecutor extends DefaultDebugExecutor { @NotNull @Override public String getStartActionText() { - return "Step Through "; + return "Step Through"; } } From 6b121f89391044c840ddb0c4a3cb2312fb8d5eff Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 19 Aug 2015 21:58:07 +0300 Subject: [PATCH 13/16] EDU-384 Always show "execute file" icon on the first line --- .../edu/PyExecuteFileLineMarkerProvider.java | 102 +++++++----------- 1 file changed, 37 insertions(+), 65 deletions(-) diff --git a/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java b/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java index c38577cb6884..ba4413b853b9 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java +++ b/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java @@ -11,13 +11,8 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.markup.GutterIconRenderer; -import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiWhiteSpace; import com.intellij.util.Function; -import com.jetbrains.python.psi.PyFile; -import com.jetbrains.python.psi.PyImportStatement; -import com.jetbrains.python.psi.PyStatement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,71 +31,48 @@ public class PyExecuteFileLineMarkerProvider implements LineMarkerProvider { @Override public void collectSlowLineMarkers(@NotNull List elements, @NotNull Collection result) { - for (PsiElement element : elements) { - if (isFirstCodeLine(element)) { - final RunContextAction runAction = new RunContextAction(DefaultRunExecutor.getRunExecutorInstance()); - final LineMarkerInfo markerInfo = new LineMarkerInfo( - element, element.getTextRange(), AllIcons.Actions.Execute, Pass.UPDATE_OVERRIDEN_MARKERS, - new Function() { - @Override - public String fun(PsiElement e) { - return "Execute '" + e.getContainingFile().getName() + "'"; - } - }, null, - GutterIconRenderer.Alignment.RIGHT) { + if (elements.isEmpty()) { + return; + } + PsiElement element = elements.get(0); + final RunContextAction runAction = new RunContextAction(DefaultRunExecutor.getRunExecutorInstance()); + final LineMarkerInfo markerInfo = new LineMarkerInfo( + element, element.getTextRange(), AllIcons.Actions.Execute, Pass.UPDATE_OVERRIDEN_MARKERS, + new Function() { + @Override + public String fun(PsiElement e) { + return "Execute '" + e.getContainingFile().getName() + "'"; + } + }, null, + GutterIconRenderer.Alignment.RIGHT) { + @Nullable + @Override + public GutterIconRenderer createGutterRenderer() { + return new LineMarkerGutterIconRenderer(this) { + @Override + public AnAction getClickAction() { + return runAction; + } + @Nullable @Override - public GutterIconRenderer createGutterRenderer() { - return new LineMarkerGutterIconRenderer(this){ - @Override - public AnAction getClickAction() { - return runAction; + public ActionGroup getPopupMenuActions() { + final DefaultActionGroup group = new DefaultActionGroup(); + group.add(runAction); + final PyExecuteFileExtensionPoint[] extensions = + ApplicationManager.getApplication().getExtensions(PyExecuteFileExtensionPoint.EP_NAME); + for (PyExecuteFileExtensionPoint extension : extensions) { + final AnAction action = extension.getRunAction(); + if (action == null) { + continue; } - - @Nullable - @Override - public ActionGroup getPopupMenuActions() { - final DefaultActionGroup group = new DefaultActionGroup(); - group.add(runAction); - final PyExecuteFileExtensionPoint[] extensions = - ApplicationManager.getApplication().getExtensions(PyExecuteFileExtensionPoint.EP_NAME); - for (PyExecuteFileExtensionPoint extension : extensions) { - final AnAction action = extension.getRunAction(); - if (action == null) { - continue; - } - group.add(action); - } - return group; - } - }; + group.add(action); + } + return group; } }; - result.add(markerInfo); } - } - } - - private static boolean isFirstCodeLine(PsiElement element) { - return element instanceof PyStatement && - element.getParent() instanceof PyFile && - !isNothing(element) && - nothingBefore(element); - } - - private static boolean nothingBefore(PsiElement element) { - element = element.getPrevSibling(); - while (element != null) { - if (!isNothing(element)) { - return false; - } - element = element.getPrevSibling(); - } - - return true; - } - - private static boolean isNothing(PsiElement element) { - return (element instanceof PsiComment) || (element instanceof PyImportStatement) || (element instanceof PsiWhiteSpace); + }; + result.add(markerInfo); } } From d2a19f7aebe4403da314f35e6939abc87bb32348 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 19 Aug 2015 22:02:13 +0300 Subject: [PATCH 14/16] used psi file instead of the first element --- .../jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java b/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java index ba4413b853b9..e0c76446ce4e 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java +++ b/python/edu/src/com/jetbrains/python/edu/PyExecuteFileLineMarkerProvider.java @@ -34,10 +34,10 @@ public class PyExecuteFileLineMarkerProvider implements LineMarkerProvider { if (elements.isEmpty()) { return; } - PsiElement element = elements.get(0); + PsiElement element = elements.get(0).getContainingFile(); final RunContextAction runAction = new RunContextAction(DefaultRunExecutor.getRunExecutorInstance()); final LineMarkerInfo markerInfo = new LineMarkerInfo( - element, element.getTextRange(), AllIcons.Actions.Execute, Pass.UPDATE_OVERRIDEN_MARKERS, + element, 0, AllIcons.Actions.Execute, Pass.UPDATE_OVERRIDEN_MARKERS, new Function() { @Override public String fun(PsiElement e) { From 596db8b0ead0b5a6bdc3006f1c3d6d4cdef30d7d Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Thu, 20 Aug 2015 15:31:41 +0300 Subject: [PATCH 15/16] removed some actions from left toolbar --- .../python/edu/debugger/PyEduDebugRunner.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java index 244eb2cc91dd..c8cb537f4edb 100644 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduDebugRunner.java @@ -9,8 +9,11 @@ import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.ui.ExecutionConsole; import com.intellij.execution.ui.RunnerLayoutUi; +import com.intellij.execution.ui.actions.CloseAction; import com.intellij.execution.ui.layout.PlaceInGrid; import com.intellij.icons.AllIcons; +import com.intellij.ide.actions.ContextHelpAction; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; @@ -24,6 +27,7 @@ import com.intellij.ui.content.ContentManager; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerBundle; import com.intellij.xdebugger.impl.XDebugSessionImpl; +import com.intellij.xdebugger.impl.actions.XDebuggerActions; import com.intellij.xdebugger.impl.ui.XDebugSessionTab; import com.jetbrains.python.console.PythonDebugLanguageConsoleView; import com.jetbrains.python.debugger.PyDebugProcess; @@ -145,6 +149,34 @@ public class PyEduDebugRunner extends PyDebugRunner { PyDebugProcess process = (PyDebugProcess)session.getDebugProcess(); PyDebugRunner.initDebugConsoleView(project, process, view, processHandler, session); + + patchLeftToolbar(session, ui); + } + + private static void patchLeftToolbar(@NotNull XDebugSession session, @NotNull RunnerLayoutUi ui) { + DefaultActionGroup newLeftToolbar = new DefaultActionGroup(); + + DefaultActionGroup firstGroup = new DefaultActionGroup(); + addActionToGroup(firstGroup, XDebuggerActions.RESUME); + addActionToGroup(firstGroup, IdeActions.ACTION_STOP_PROGRAM); + newLeftToolbar.addAll(firstGroup); + + newLeftToolbar.addSeparator(); + + Executor executor = PyEduDebugExecutor.getInstance(); + newLeftToolbar.add(new CloseAction(executor, session.getRunContentDescriptor(), session.getProject())); + //TODO: return proper helpID + newLeftToolbar.add(new ContextHelpAction(executor.getHelpId())); + + ui.getOptions().setLeftToolbar(newLeftToolbar, ActionPlaces.DEBUGGER_TOOLBAR); + } + + private static void addActionToGroup(DefaultActionGroup group, String actionId) { + AnAction action = ActionManager.getInstance().getAction(actionId); + if (action != null) { + action.getTemplatePresentation().setEnabled(true); + group.add(action, Constraints.LAST); + } } @Nullable From 8c465f8cb110d709caf1bb030701ae09f22c074b Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Thu, 20 Aug 2015 16:20:52 +0300 Subject: [PATCH 16/16] added icon for special variables group --- python/edu/gen/icons/PythonEducationalIcons.java | 1 + .../icons/com/jetbrains/edu/specialVar.png | Bin 0 -> 240 bytes .../icons/com/jetbrains/edu/specialVar@2x.png | Bin 0 -> 370 bytes .../python/edu/debugger/PyEduStackFrame.java | 4 +--- 4 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 python/edu/resources/icons/com/jetbrains/edu/specialVar.png create mode 100644 python/edu/resources/icons/com/jetbrains/edu/specialVar@2x.png diff --git a/python/edu/gen/icons/PythonEducationalIcons.java b/python/edu/gen/icons/PythonEducationalIcons.java index c8828ed8ae68..fb04abc3c3eb 100644 --- a/python/edu/gen/icons/PythonEducationalIcons.java +++ b/python/edu/gen/icons/PythonEducationalIcons.java @@ -14,4 +14,5 @@ public class PythonEducationalIcons { } public static final Icon Field = load("/icons/com/jetbrains/edu/Field.png"); // 16x16 + public static final Icon SpecialVar = load("/icons/com/jetbrains/edu/specialVar.png"); // 16x16 } diff --git a/python/edu/resources/icons/com/jetbrains/edu/specialVar.png b/python/edu/resources/icons/com/jetbrains/edu/specialVar.png new file mode 100644 index 0000000000000000000000000000000000000000..25612ae2077c836eef0839dce7da3518bd508ad5 GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`+dW+zLn>~qo$SkX$UvaAST8o> zqqtVbmw;Ut^wv0PM^tqx_3uu$B98C;nZ$apezCmY7x3zs(uq)hjXN$D zd+Nm<*Hty#<_p|aD-2{gth035Xeng`4v>N1OaK_F~%inQ>$5c4_-di2}f|WbkzLb6Mw< G&;$VFI-dyu literal 0 HcmV?d00001 diff --git a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java index f8b557e2b418..743a696144e1 100644 --- a/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java +++ b/python/edu/src/com/jetbrains/python/edu/debugger/PyEduStackFrame.java @@ -1,6 +1,5 @@ package com.jetbrains.python.edu.debugger; -import com.intellij.icons.AllIcons; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.ColoredTextContainer; @@ -98,8 +97,7 @@ public class PyEduStackFrame extends PyStackFrame { @Nullable @Override public Icon getIcon() { - //TODO: get icon from designers - return AllIcons.Nodes.Artifact; + return PythonEducationalIcons.SpecialVar; } @Override