blob: ddec6797ea8dcc6019b066473815ac8fa523efea [file] [log] [blame]
package com.jetbrains.python.debugger;
import com.intellij.icons.AllIcons;
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;
import javax.swing.*;
// todo: load long lists by parts
// todo: null modifier for modify modules, class objects etc.
public class PyDebugValue extends XNamedValue {
private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.pydev.PyDebugValue");
public static final int MAX_VALUE = 512;
private String myTempName = null;
private final String myType;
private final String myValue;
private final boolean myContainer;
private final PyDebugValue myParent;
private String myId = null;
private final PyFrameAccessor myFrameAccessor;
private PyVariableLocator myVariableLocator;
private final boolean myErrorOnEval;
public PyDebugValue(@NotNull final String name, final String type, final String value, final boolean container,
boolean errorOnEval, final PyFrameAccessor frameAccessor) {
this(name, type, value, container, errorOnEval, null, frameAccessor);
}
public PyDebugValue(@NotNull final String name, final String type, final String value, final boolean container,
boolean errorOnEval, final PyDebugValue parent, final PyFrameAccessor frameAccessor) {
super(name);
myType = type;
myValue = value;
myContainer = container;
myErrorOnEval = errorOnEval;
myParent = parent;
myFrameAccessor = frameAccessor;
}
public String getTempName() {
return myTempName != null ? myTempName : myName;
}
public void setTempName(String tempName) {
myTempName = tempName;
}
public String getType() {
return myType;
}
public String getValue() {
return myValue;
}
public boolean isContainer() {
return myContainer;
}
public boolean isErrorOnEval() {
return myErrorOnEval;
}
public PyDebugValue setParent(@Nullable PyDebugValue parent) {
return new PyDebugValue(myName, myType, myValue, myContainer, myErrorOnEval, parent, myFrameAccessor);
}
public PyDebugValue getParent() {
return myParent;
}
public PyDebugValue getTopParent() {
return myParent == null ? this : myParent.getTopParent();
}
@Override
public String getEvaluationExpression() {
StringBuilder stringBuilder = new StringBuilder();
buildExpression(stringBuilder);
return stringBuilder.toString();
}
void buildExpression(StringBuilder result) {
if (myParent == null) {
result.append(getTempName());
}
else {
myParent.buildExpression(result);
if (("dict".equals(myParent.getType()) || "list".equals(myParent.getType()) || "tuple".equals(myParent.getType())) &&
!isLen(myName)) {
result.append('[').append(removeLeadingZeros(removeId(myName))).append(']');
}
else if (("set".equals(myParent.getType())) && !isLen(myName)) {
//set doesn't support indexing
}
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);
}
}
}
private static String removeId(@NotNull String name) {
if (name.indexOf('(') != -1) {
name = name.substring(0, name.indexOf('(')).trim();
}
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);
}
@Override
public void computePresentation(@NotNull XValueNode node, @NotNull XValuePlace place) {
String value = PyTypeHandler.format(this);
if (value.length() >= MAX_VALUE) {
node.setFullValueEvaluator(new PyFullValueEvaluator(myFrameAccessor, myName));
value = value.substring(0, MAX_VALUE);
}
node.setPresentation(getValueIcon(), myType, value, myContainer);
}
@Override
public void computeChildren(@NotNull final XCompositeNode node) {
if (node.isObsolete()) return;
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
if (myFrameAccessor == null) return;
try {
final XValueChildrenList values = myFrameAccessor.loadVariable(PyDebugValue.this);
if (!node.isObsolete()) {
node.addChildren(values, true);
}
}
catch (PyDebuggerException e) {
if (!node.isObsolete()) {
node.setErrorMessage("Unable to display children:" + e.getMessage());
}
LOG.warn(e);
}
}
});
}
@Override
public XValueModifier getModifier() {
return new PyValueModifier(myFrameAccessor, this);
}
private Icon getValueIcon() {
if (!myContainer) {
return AllIcons.Debugger.Db_primitive;
}
else if ("list".equals(myType) || "tuple".equals(myType)) {
return AllIcons.Debugger.Db_array;
}
else {
return AllIcons.Debugger.Value;
}
}
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;
}
}