summaryrefslogtreecommitdiff
path: root/python/pydevSrc
diff options
context:
space:
mode:
Diffstat (limited to 'python/pydevSrc')
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java6
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java53
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/PyFrameAccessor.java3
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/PyReferrersLoader.java20
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/PyReferringObjectsValue.java71
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java2
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/PyTypeHandler.java3
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java12
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java2
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/GetReferrersCommand.java50
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java32
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java12
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java17
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java26
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/PyDebugCallback.java12
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java17
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java50
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/RunCustomOperationCommand.java86
18 files changed, 429 insertions, 45 deletions
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java b/python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java
index ab6ccfab0bc6..762225f18f12 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java
@@ -1,6 +1,8 @@
package com.jetbrains.python.debugger;
import com.intellij.execution.ui.ConsoleViewContentType;
+import com.intellij.xdebugger.frame.XValueChildrenList;
+import com.jetbrains.python.debugger.pydev.PyDebugCallback;
import java.io.IOException;
@@ -12,7 +14,7 @@ public interface IPyDebugProcess extends PyFrameAccessor {
void threadSuspended(PyThreadInfo thread);
- boolean isVariable(String name);
+ boolean canSaveToTemp(String name);
void threadResumed(PyThreadInfo thread);
@@ -25,4 +27,6 @@ public interface IPyDebugProcess extends PyFrameAccessor {
void recordSignature(PySignature signature);
void showConsole(PyThreadInfo thread);
+
+ void loadReferrers(PyReferringObjectsValue var, PyDebugCallback<XValueChildrenList> callback);
}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java b/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java
index 69b64827c40f..ddec6797ea8d 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java
@@ -5,6 +5,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.xdebugger.frame.XNamedValue;
import com.intellij.xdebugger.frame.*;
+import com.jetbrains.python.debugger.pydev.PyVariableLocator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -21,14 +22,13 @@ public class PyDebugValue extends XNamedValue {
private final String myValue;
private final boolean myContainer;
private final PyDebugValue myParent;
+ private String myId = null;
private final PyFrameAccessor myFrameAccessor;
- private final boolean myErrorOnEval;
+ private PyVariableLocator myVariableLocator;
- public PyDebugValue(@NotNull final String name, final String type, final String value, final boolean container, boolean errorOnEval) {
- this(name, type, value, container, errorOnEval, null, null);
- }
+ private final boolean myErrorOnEval;
public PyDebugValue(@NotNull final String name, final String type, final String value, final boolean container,
boolean errorOnEval, final PyFrameAccessor frameAccessor) {
@@ -97,7 +97,7 @@ public class PyDebugValue extends XNamedValue {
myParent.buildExpression(result);
if (("dict".equals(myParent.getType()) || "list".equals(myParent.getType()) || "tuple".equals(myParent.getType())) &&
!isLen(myName)) {
- result.append('[').append(removeId(myName)).append(']');
+ result.append('[').append(removeLeadingZeros(removeId(myName))).append(']');
}
else if (("set".equals(myParent.getType())) && !isLen(myName)) {
//set doesn't support indexing
@@ -105,6 +105,9 @@ public class PyDebugValue extends XNamedValue {
else if (isLen(myName)) {
result.append('.').append(myName).append("()");
}
+ else if (("ndarray".equals(myParent.getType()) || "matrix".equals(myParent.getType())) && myName.startsWith("[")) {
+ result.append(removeLeadingZeros(myName));
+ }
else {
result.append('.').append(myName);
}
@@ -119,6 +122,11 @@ public class PyDebugValue extends XNamedValue {
return name;
}
+ private static String removeLeadingZeros(@NotNull String name) {
+ //bugs.python.org/issue15254: "0" prefix for octal
+ return name.replaceFirst("^0+(?!$)", "");
+ }
+
private static boolean isLen(String name) {
return "__len__".equals(name);
}
@@ -179,4 +187,39 @@ public class PyDebugValue extends XNamedValue {
public PyDebugValue setName(String newName) {
return new PyDebugValue(newName, myType, myValue, myContainer, myErrorOnEval, myParent, myFrameAccessor);
}
+
+ @Nullable
+ @Override
+ public XReferrersProvider getReferrersProvider() {
+ if (myFrameAccessor.getReferrersLoader() != null) {
+ return new XReferrersProvider() {
+ @Override
+ public XValue getReferringObjectsValue() {
+ return new PyReferringObjectsValue(PyDebugValue.this);
+ }
+ };
+ } else {
+ return null;
+ }
+ }
+
+ public PyFrameAccessor getFrameAccessor() {
+ return myFrameAccessor;
+ }
+
+ public PyVariableLocator getVariableLocator() {
+ return myVariableLocator;
+ }
+
+ public void setVariableLocator(PyVariableLocator variableLocator) {
+ myVariableLocator = variableLocator;
+ }
+
+ public String getId() {
+ return myId;
+ }
+
+ public void setId(String id) {
+ myId = id;
+ }
}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyFrameAccessor.java b/python/pydevSrc/com/jetbrains/python/debugger/PyFrameAccessor.java
index 530035e78a4b..01666456f420 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/PyFrameAccessor.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/PyFrameAccessor.java
@@ -17,4 +17,7 @@ public interface PyFrameAccessor {
XValueChildrenList loadVariable(PyDebugValue var) throws PyDebuggerException;
void changeVariable(PyDebugValue variable, String expression) throws PyDebuggerException;
+
+ @Nullable
+ PyReferrersLoader getReferrersLoader();
}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyReferrersLoader.java b/python/pydevSrc/com/jetbrains/python/debugger/PyReferrersLoader.java
new file mode 100644
index 000000000000..edb2f641b192
--- /dev/null
+++ b/python/pydevSrc/com/jetbrains/python/debugger/PyReferrersLoader.java
@@ -0,0 +1,20 @@
+package com.jetbrains.python.debugger;
+
+import com.intellij.xdebugger.frame.XReferrersProvider;
+import com.intellij.xdebugger.frame.XValueChildrenList;
+import com.jetbrains.python.debugger.pydev.PyDebugCallback;
+
+/**
+ * @author traff
+ */
+public class PyReferrersLoader {
+ private final IPyDebugProcess myProcess;
+
+ public PyReferrersLoader(IPyDebugProcess process) {
+ myProcess = process;
+ }
+
+ public void loadReferrers(PyReferringObjectsValue value, PyDebugCallback<XValueChildrenList> callback) {
+ myProcess.loadReferrers(value, callback);
+ }
+}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyReferringObjectsValue.java b/python/pydevSrc/com/jetbrains/python/debugger/PyReferringObjectsValue.java
new file mode 100644
index 000000000000..283653659d0d
--- /dev/null
+++ b/python/pydevSrc/com/jetbrains/python/debugger/PyReferringObjectsValue.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2000-2014 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.diagnostic.Logger;
+import com.intellij.xdebugger.frame.XCompositeNode;
+import com.intellij.xdebugger.frame.XValueChildrenList;
+import com.jetbrains.python.debugger.pydev.PyDebugCallback;
+import org.jetbrains.annotations.NotNull;
+
+public class PyReferringObjectsValue extends PyDebugValue {
+ private static final Logger LOG = Logger.getInstance(PyReferringObjectsValue.class);
+
+ private final @NotNull PyReferrersLoader myReferrersLoader;
+
+ public PyReferringObjectsValue(@NotNull String name,
+ String type,
+ String value,
+ boolean container, boolean errorOnEval, @NotNull PyFrameAccessor frameAccessor) {
+ super(name, type, value, container, errorOnEval, frameAccessor);
+ myReferrersLoader = frameAccessor.getReferrersLoader();
+ }
+
+ public PyReferringObjectsValue(PyDebugValue debugValue) {
+ this(debugValue.getName(), debugValue.getType(), debugValue.getValue(), debugValue.isContainer(), debugValue.isErrorOnEval(), debugValue.getFrameAccessor());
+ }
+
+ @Override
+ public boolean canNavigateToSource() {
+ return true;
+ }
+
+ @Override
+ public void computeChildren(@NotNull final XCompositeNode node) {
+ if (node.isObsolete()) return;
+
+ myReferrersLoader.loadReferrers(this, new PyDebugCallback<XValueChildrenList>() {
+ @Override
+ public void ok(XValueChildrenList value) {
+ if (!node.isObsolete()) {
+ node.addChildren(value, true);
+ }
+ }
+
+ @Override
+ public void error(PyDebuggerException e) {
+ if (!node.isObsolete()) {
+ node.setErrorMessage("Unable to display children:" + e.getMessage());
+ }
+ LOG.warn(e);
+ }
+ });
+ }
+
+ public boolean isField() {
+ return false; //TODO
+ }
+}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java b/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java
index c01be15384ab..7fffc636a9fb 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java
@@ -80,7 +80,7 @@ public class PyThreadInfo {
}
public boolean isExceptionBreak() {
- return myStopReason == AbstractCommand.ADD_EXCEPTION_BREAKPOINT || myStopReason == AbstractCommand.ADD_DJANGO_EXCEPTION_BREAKPOINT;
+ return myStopReason == AbstractCommand.ADD_EXCEPTION_BREAKPOINT;
}
@Override
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyTypeHandler.java b/python/pydevSrc/com/jetbrains/python/debugger/PyTypeHandler.java
index 6db612488d4b..f882aae4d0e7 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/PyTypeHandler.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/PyTypeHandler.java
@@ -37,6 +37,9 @@ public class PyTypeHandler {
FORMATTERS = new HashMap<String, Formatter>();
FORMATTERS.put("str", STR_FORMATTER);
FORMATTERS.put("unicode", UNI_FORMATTER);
+ //numpy types
+ FORMATTERS.put("string_", STR_FORMATTER);
+ FORMATTERS.put("unicode_", UNI_FORMATTER);
}
private PyTypeHandler() { }
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java
index 15bb76b6c3d1..d13addaade04 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java
@@ -28,11 +28,10 @@ public abstract class AbstractCommand<T> {
public static final int ADD_EXCEPTION_BREAKPOINT = 122;
public static final int REMOVE_EXCEPTION_BREAKPOINT = 123;
public static final int LOAD_SOURCE = 124;
- public static final int ADD_DJANGO_EXCEPTION_BREAKPOINT = 125;
- public static final int REMOVE_DJANGO_EXCEPTION_BREAKPOINT = 126;
public static final int SMART_STEP_INTO = 128;
public static final int EXIT = 129;
public static final int CALL_SIGNATURE_TRACE = 130;
+ public static final int CMD_RUN_CUSTOM_OPERATION = 135;
public static final int SHOW_CONSOLE = 142;
public static final int ERROR = 901;
@@ -41,7 +40,7 @@ public abstract class AbstractCommand<T> {
public static final String TAB_CHAR = "@_@TAB_CHAR@_@";
- @NotNull protected final RemoteDebugger myDebugger;
+ @NotNull private final RemoteDebugger myDebugger;
private final int myCommandCode;
private final ResponseProcessor<T> myResponseProcessor;
@@ -107,7 +106,7 @@ public abstract class AbstractCommand<T> {
}
}
- public void execute(final ProcessDebugger.DebugCallback<T> callback) {
+ public void execute(final PyDebugCallback<T> callback) {
final int sequence = myDebugger.getNextSequence();
final ResponseProcessor<T> processor = getResponseProcessor();
@@ -186,6 +185,11 @@ public abstract class AbstractCommand<T> {
return command == ERROR;
}
+ @NotNull
+ public RemoteDebugger getDebugger() {
+ return myDebugger;
+ }
+
protected static class Payload {
private final StringBuilder myBuilder = new StringBuilder();
private static final char SEPARATOR = '\t';
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java
index 14d8c084a39d..c03890f088e8 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java
@@ -28,7 +28,7 @@ public class ConsoleExecCommand extends AbstractFrameCommand<String> {
return new ResponseProcessor<String>() {
@Override
protected String parseResponse(ProtocolFrame response) throws PyDebuggerException {
- final PyDebugValue value = ProtocolParser.parseValue(response.getPayload(), myDebugger.getDebugProcess());
+ final PyDebugValue value = ProtocolParser.parseValue(response.getPayload(), getDebugger().getDebugProcess());
return value.getValue();
}
};
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetReferrersCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetReferrersCommand.java
new file mode 100644
index 000000000000..3698266f66b7
--- /dev/null
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetReferrersCommand.java
@@ -0,0 +1,50 @@
+package com.jetbrains.python.debugger.pydev;
+
+import com.jetbrains.python.debugger.PyDebugValue;
+import com.jetbrains.python.debugger.PyDebuggerException;
+import com.jetbrains.python.debugger.PyReferringObjectsValue;
+
+import java.util.List;
+
+/**
+ * @author traff
+ */
+public class GetReferrersCommand extends RunCustomOperationCommand<List<PyDebugValue>> {
+
+ public GetReferrersCommand(RemoteDebugger target, String threadId, String frameId, PyReferringObjectsValue value) {
+ super(target, createVariableLocator(threadId, frameId, value), "from pydevd_referrers import get_referrer_info",
+ "get_referrer_info");
+ }
+
+ @Override
+ protected ResponseProcessor<List<PyDebugValue>> createResponseProcessor() {
+ return new ResponseProcessor<List<PyDebugValue>>() {
+ @Override
+ protected List<PyDebugValue> parseResponse(ProtocolFrame response) throws PyDebuggerException {
+ return ProtocolParser.parseReferrers(decode(response.getPayload()), getDebugger().getDebugProcess());
+ }
+ };
+ }
+
+
+ private static PyVariableLocator createVariableLocator(final String threadId, final String frameId, final PyReferringObjectsValue var) {
+ return new PyVariableLocator() {
+ @Override
+ public String getThreadId() {
+ return threadId;
+ }
+
+
+ @Override
+ public String getPyDBLocation() {
+ if (var.getId() == null) {
+ return threadId + "\t" + frameId + "\tFRAME\t" + var.getName();
+ }
+ //Ok, this only happens when we're dealing with references with no proper scope given and we need to get
+ //things by id (which is usually not ideal). In this case we keep the proper thread id and set the frame id
+ //as the id of the object to be searched later on based on the list of all alive objects.
+ return getThreadId() + "\t" + var.getId() + "\tBY_ID";
+ }
+ };
+ }
+}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java
index ef4bd12059d7..e5a218607ac8 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java
@@ -5,6 +5,7 @@ import com.jetbrains.python.debugger.PyDebugValue;
public class GetVariableCommand extends GetFrameCommand {
+ public static final String BY_ID = "BY_ID";
private final String myVariableName;
private final PyDebugValue myParent;
@@ -15,23 +16,40 @@ public class GetVariableCommand extends GetFrameCommand {
}
public static String composeName(final PyDebugValue var) {
- final StringBuilder sb = new StringBuilder(var.getTempName());
+ final StringBuilder sb = new StringBuilder();
PyDebugValue p = var;
- while ((p = p.getParent()) != null) {
- sb.insert(0, '\t').insert(0, p.getTempName());
+ while (p != null) {
+ if (sb.length() > 0 ) {
+ sb.insert(0, '\t');
+ }
+ if (p.getId() != null) {
+ sb.insert(0, BY_ID).insert(0, '\t').insert(0, p.getId());
+ break;
+ } else {
+ sb.insert(0, p.getTempName());
+ }
+ p = p.getParent();
}
return sb.toString();
}
@Override
protected void buildPayload(Payload payload) {
- super.buildPayload(payload);
- payload.add(myVariableName);
+ if (myParent.getVariableLocator() != null) {
+ payload.add(myParent.getVariableLocator().getThreadId()).add(myParent.getVariableLocator().getPyDBLocation());
+ }
+ else if (myVariableName.contains(BY_ID)) {
+ payload.add(getThreadId()).add(myVariableName);
+ }
+ else {
+ super.buildPayload(payload);
+ payload.add(myVariableName);
+ }
}
@Override
protected PyDebugValue extend(final PyDebugValue value) {
- return new PyDebugValue(value.getName(), value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(), myParent, myDebugProcess);
+ return new PyDebugValue(value.getName(), value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(), myParent,
+ myDebugProcess);
}
-
}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java
index d210d7ae03a8..d54bac8de85f 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java
@@ -8,10 +8,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.xdebugger.frame.XValueChildrenList;
import com.jetbrains.python.console.pydev.PydevCompletionVariant;
-import com.jetbrains.python.debugger.IPyDebugProcess;
-import com.jetbrains.python.debugger.PyDebugValue;
-import com.jetbrains.python.debugger.PyDebuggerException;
-import com.jetbrains.python.debugger.PyThreadInfo;
+import com.jetbrains.python.debugger.*;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
@@ -168,7 +165,7 @@ public class MultiProcessDebugger implements ProcessDebugger {
}
@Override
- public void consoleExec(String threadId, String frameId, String expression, DebugCallback<String> callback) {
+ public void consoleExec(String threadId, String frameId, String expression, PyDebugCallback<String> callback) {
debugger(threadId).consoleExec(threadId, frameId, expression, callback);
}
@@ -182,6 +179,11 @@ public class MultiProcessDebugger implements ProcessDebugger {
return debugger(threadId).loadVariable(threadId, frameId, var);
}
+ @Override
+ public void loadReferrers(String threadId, String frameId, PyReferringObjectsValue var, PyDebugCallback<XValueChildrenList> callback) {
+ debugger(threadId).loadReferrers(threadId, frameId, var, callback);
+ }
+
@NotNull
private ProcessDebugger debugger(@NotNull String threadId) {
ProcessDebugger debugger = myThreadRegistry.getDebugger(threadId);
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java
index 2d864f0df2ca..0fa5a5c21931 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java
@@ -4,6 +4,7 @@ import com.intellij.xdebugger.frame.XValueChildrenList;
import com.jetbrains.python.console.pydev.PydevCompletionVariant;
import com.jetbrains.python.debugger.PyDebugValue;
import com.jetbrains.python.debugger.PyDebuggerException;
+import com.jetbrains.python.debugger.PyReferringObjectsValue;
import com.jetbrains.python.debugger.PyThreadInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -26,15 +27,17 @@ public interface ProcessDebugger {
String expression,
boolean execute,
boolean trimResult)
- throws PyDebuggerException;
+ throws PyDebuggerException;
- void consoleExec(String threadId, String frameId, String expression, DebugCallback<String> callback);
+ void consoleExec(String threadId, String frameId, String expression, PyDebugCallback<String> callback);
XValueChildrenList loadFrame(String threadId, String frameId) throws PyDebuggerException;
// todo: don't generate temp variables for qualified expressions - just split 'em
XValueChildrenList loadVariable(String threadId, String frameId, PyDebugValue var) throws PyDebuggerException;
+ void loadReferrers(String threadId, String frameId, PyReferringObjectsValue var, PyDebugCallback<XValueChildrenList> callback);
+
PyDebugValue changeVariable(String threadId, String frameId, PyDebugValue var, String value)
throws PyDebuggerException;
@@ -50,7 +53,7 @@ public interface ProcessDebugger {
void suspendThread(String threadId);
/**
- * Disconnects current debug process. Closes all resources.
+ * Disconnects current debug process. Closes all resources.
*/
void close();
@@ -84,12 +87,4 @@ public interface ProcessDebugger {
void addExceptionBreakpoint(ExceptionBreakpointCommandFactory factory);
void removeExceptionBreakpoint(ExceptionBreakpointCommandFactory factory);
-
- /**
- * @author traff
- */
- interface DebugCallback<T> {
- void ok(T value);
- void error(PyDebuggerException exception);
- }
}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java
index 0801077fbea3..1822b17efaa3 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java
@@ -122,6 +122,32 @@ public class ProtocolParser {
}
@NotNull
+ public static List<PyDebugValue> parseReferrers(final String text, final PyFrameAccessor frameAccessor) throws PyDebuggerException {
+ final List<PyDebugValue> values = new LinkedList<PyDebugValue>();
+
+ final XppReader reader = openReader(text, false);
+
+ while (reader.hasMoreChildren()) {
+ reader.moveDown();
+ if (reader.getNodeName().equals("var")) {
+ PyDebugValue value = parseValue(reader, frameAccessor);
+ value.setId(readString(reader, "id", null));
+ values.add(value);
+ }
+ else if (reader.getNodeName().equals("for")) {
+ //TODO
+ }
+ else {
+ throw new PyDebuggerException("Expected <var> or <for>, found " + reader.getNodeName());
+ }
+ reader.moveUp();
+ }
+
+ return values;
+ }
+
+
+ @NotNull
public static List<PyDebugValue> parseValues(final String text, final PyFrameAccessor frameAccessor) throws PyDebuggerException {
final List<PyDebugValue> values = new LinkedList<PyDebugValue>();
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyDebugCallback.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyDebugCallback.java
new file mode 100644
index 000000000000..c78f3e20bdc5
--- /dev/null
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyDebugCallback.java
@@ -0,0 +1,12 @@
+package com.jetbrains.python.debugger.pydev;
+
+import com.jetbrains.python.debugger.PyDebuggerException;
+
+/**
+ * @author traff
+ */
+public interface PyDebugCallback<T> {
+ void ok(T value);
+
+ void error(PyDebuggerException exception);
+}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java
new file mode 100644
index 000000000000..3ba4e1cd96de
--- /dev/null
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java
@@ -0,0 +1,17 @@
+package com.jetbrains.python.debugger.pydev;
+
+/**
+ * IVariableLocator knows how to produce location information
+ * for CMD_GET_VARIABLE
+ *
+ * The location is specified as:
+ *
+ * thread_id, stack_frame, LOCAL|GLOBAL, attribute*
+ */
+public interface PyVariableLocator {
+
+ public String getThreadId();
+
+ public String getPyDBLocation();
+
+}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java
index df33148edb10..4ce7bdf67434 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java
@@ -133,7 +133,7 @@ public class RemoteDebugger implements ProcessDebugger {
}
@Override
- public void consoleExec(String threadId, String frameId, String expression, DebugCallback<String> callback) {
+ public void consoleExec(String threadId, String frameId, String expression, PyDebugCallback<String> callback) {
final ConsoleExecCommand command = new ConsoleExecCommand(this, threadId, frameId, expression);
command.execute(callback);
}
@@ -154,6 +154,31 @@ public class RemoteDebugger implements ProcessDebugger {
return command.getVariables();
}
+
+ @Override
+ public void loadReferrers(final String threadId,
+ final String frameId,
+ final PyReferringObjectsValue var,
+ final PyDebugCallback<XValueChildrenList> callback) {
+ RunCustomOperationCommand cmd = new GetReferrersCommand(this, threadId, frameId, var);
+
+ cmd.execute(new PyDebugCallback<List<PyDebugValue>>() {
+ @Override
+ public void ok(List<PyDebugValue> value) {
+ XValueChildrenList list = new XValueChildrenList();
+ for (PyDebugValue v : value) {
+ list.add(v);
+ }
+ callback.ok(list);
+ }
+
+ @Override
+ public void error(PyDebuggerException exception) {
+ callback.error(exception);
+ }
+ });
+ }
+
@Override
public PyDebugValue changeVariable(final String threadId, final String frameId, final PyDebugValue var, final String value)
throws PyDebuggerException {
@@ -191,7 +216,7 @@ public class RemoteDebugger implements ProcessDebugger {
// todo: change variable in lists doesn't work - either fix in pydevd or format var name appropriately
private void setTempVariable(final String threadId, final String frameId, final PyDebugValue var) {
final PyDebugValue topVar = var.getTopParent();
- if (myDebugProcess.isVariable(topVar.getName())) {
+ if (!myDebugProcess.canSaveToTemp(topVar.getName())) {
return;
}
if (myTempVars.contains(threadId, frameId, topVar.getTempName())) {
@@ -343,7 +368,7 @@ public class RemoteDebugger implements ProcessDebugger {
}
}
if (myDebuggerReader != null) {
- myDebuggerReader.close();
+ myDebuggerReader.stop();
}
fireCloseEvent();
}
@@ -428,7 +453,6 @@ public class RemoteDebugger implements ProcessDebugger {
}
private class DebuggerReader extends BaseOutputReader {
- private boolean myClosing = false;
private Reader myReader;
private DebuggerReader(final Reader reader) throws IOException {
@@ -442,7 +466,7 @@ public class RemoteDebugger implements ProcessDebugger {
while (true) {
boolean read = readAvailable();
- if (myClosing) {
+ if (isStopped) {
break;
}
@@ -453,7 +477,7 @@ public class RemoteDebugger implements ProcessDebugger {
fireCommunicationError();
}
finally {
- closeReader(myReader);
+ close();
fireExitEvent();
}
}
@@ -475,10 +499,10 @@ public class RemoteDebugger implements ProcessDebugger {
else if (AbstractCommand.isCallSignatureTrace(frame.getCommand())) {
recordCallSignature(ProtocolParser.parseCallSignature(frame.getPayload()));
}
- else if (AbstractCommand.isErrorEvent(frame.getCommand())) {
- LOG.error("Error response from debugger: " + frame.getPayload());
- }
else {
+ if (AbstractCommand.isErrorEvent(frame.getCommand())) {
+ LOG.error("Error response from debugger: " + frame.getPayload());
+ }
placeResponse(frame.getSequence(), frame);
}
}
@@ -568,7 +592,13 @@ public class RemoteDebugger implements ProcessDebugger {
}
public void close() {
- myClosing = true;
+ closeReader(myReader);
+ }
+
+ @Override
+ public void stop() {
+ super.stop();
+ close();
}
@Override
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RunCustomOperationCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RunCustomOperationCommand.java
new file mode 100644
index 000000000000..7a3315b4acce
--- /dev/null
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RunCustomOperationCommand.java
@@ -0,0 +1,86 @@
+package com.jetbrains.python.debugger.pydev;
+
+import com.intellij.openapi.diagnostic.Logger;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+
+
+/**
+ * Run a custom bit of Python in the context of the specified debug target.
+ * <p>
+ * This command takes a variable or expression (expressed as an {@link PyVariableLocator#getPyDBLocation()} style
+ * location) and passes it to the function provided in the constructor. The constructor also takes either a code
+ * snippet that should define the function, or a file to execfile that should define the function.
+ * <p>
+ * Once created, the command should be posted to the target with {@link AbstractDebugTarget#postCommand(AbstractDebuggerCommand)}.
+ * Optionally, the function run on the target can return a string for further processing. In this case the command's
+ * {@link #setCompletionListener(ICommandResponseListener)} should be set and on completion, {@link #getResponsePayload()}
+ * can be used to obtain the returned value.
+ * <p>
+ * For an example, see {@link PrettyPrintCommandHandler}
+ */
+public class RunCustomOperationCommand<T> extends AbstractCommand<T> {
+ private static final Logger LOG = Logger.getInstance(RunCustomOperationCommand.class);
+
+ private String myEncodedCodeOrFile;
+ private String myOperationFnName;
+ private PyVariableLocator myLocator;
+ private String myStyle;
+
+ private RunCustomOperationCommand(RemoteDebugger target, PyVariableLocator locator,
+ String style, String codeOrFile, String operationFnName) {
+ super(target, CMD_RUN_CUSTOM_OPERATION);
+
+ this.myLocator = locator;
+ this.myStyle = style;
+ this.myEncodedCodeOrFile = encode(codeOrFile);
+ this.myOperationFnName = operationFnName;
+ }
+
+ /**
+ * Create a new command to run with the function defined in a string.
+ *
+ * @param target Debug Target to run on
+ * @param locator Location of variable or expression.
+ * @param operationSource Definition of the function to be run (this code is "exec"ed by the target)
+ * @param operationFnName Function to call, must be defined by operationSource
+ */
+ public RunCustomOperationCommand(RemoteDebugger target, PyVariableLocator locator,
+ String operationSource, String operationFnName) {
+ this(target, locator, "EXEC", operationSource, operationFnName);
+ }
+
+
+ @Override
+ protected void buildPayload(Payload payload) {
+ payload.add(myLocator.getPyDBLocation() + "||" + myStyle).add(myEncodedCodeOrFile).add(myOperationFnName);
+ }
+
+ @Override
+ public boolean isResponseExpected() {
+ return true;
+ }
+
+ private static String encode(String in) {
+ try {
+ return URLEncoder.encode(in, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ LOG.error("Unreachable? UTF-8 is always supported.", e);
+ return "";
+ }
+ }
+
+ protected static String decode(String in) {
+ try {
+ return URLDecoder.decode(in, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ LOG.error("Unreachable? UTF-8 is always supported.", e);
+ return "";
+ }
+ }
+
+}
+