summaryrefslogtreecommitdiff
path: root/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java')
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java187
1 files changed, 170 insertions, 17 deletions
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java
index a3aa8ec43fc5..e73564095b21 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java
@@ -15,61 +15,214 @@
*/
package com.intellij.xdebugger.impl.evaluate;
+import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorLinePainter;
import com.intellij.openapi.editor.LineExtensionInfo;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
import com.intellij.ui.SimpleColoredText;
+import com.intellij.ui.SimpleTextAttributes;
+import com.intellij.xdebugger.XDebugSession;
+import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.frame.presentation.XValuePresentation;
+import com.intellij.xdebugger.impl.frame.XDebugView;
import com.intellij.xdebugger.impl.frame.XVariablesView;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueTextRendererImpl;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
+import java.util.List;
/**
* @author Konstantin Bulenkov
*/
public class XDebuggerEditorLinePainter extends EditorLinePainter {
+ public static final Key<Map<Variable, VariableValue>> CACHE = Key.create("debug.inline.variables.cache");
@Override
public Collection<LineExtensionInfo> getLineExtensions(@NotNull Project project, @NotNull VirtualFile file, int lineNumber) {
if (!Registry.is("ide.debugger.inline")) {
return null;
}
- Map<Pair<VirtualFile, Integer>, Set<XValueNodeImpl>> map = project.getUserData(XVariablesView.DEBUG_VARIABLES);
- if (map != null) {
- Set<XValueNodeImpl> values = map.get(Pair.create(file, lineNumber));
- if (values != null && !values.isEmpty()) {
- ArrayList<LineExtensionInfo> result = new ArrayList<LineExtensionInfo>();
- for (XValueNodeImpl value : values) {
- SimpleColoredText text = new SimpleColoredText();
- XValueTextRendererImpl renderer = new XValueTextRendererImpl(text);
- final XValuePresentation presentation = value.getValuePresentation();
- if (presentation == null) continue;
+ final Map<Pair<VirtualFile, Integer>, Set<XValueNodeImpl>> map = project.getUserData(XVariablesView.DEBUG_VARIABLES);
+ final Map<VirtualFile, Long> timestamps = project.getUserData(XVariablesView.DEBUG_VARIABLES_TIMESTAMPS);
+ final Document doc = FileDocumentManager.getInstance().getDocument(file);
+
+ if (map == null || timestamps == null || doc == null) {
+ return null;
+ }
+
+ Map<Variable, VariableValue> oldValues = project.getUserData(CACHE);
+ if (oldValues == null) {
+ oldValues = new HashMap<Variable, VariableValue>();
+ project.putUserData(CACHE, oldValues);
+ }
+ final Long timestamp = timestamps.get(file);
+ if (timestamp == null || timestamp < doc.getModificationStamp()) {
+ return null;
+ }
+ Set<XValueNodeImpl> values = map.get(Pair.create(file, lineNumber));
+ if (values != null && !values.isEmpty()) {
+ final int bpLine = getCurrentBreakPointLine(values);
+ ArrayList<LineExtensionInfo> result = new ArrayList<LineExtensionInfo>();
+ for (XValueNodeImpl value : values) {
+ SimpleColoredText text = new SimpleColoredText();
+ XValueTextRendererImpl renderer = new XValueTextRendererImpl(text);
+ final XValuePresentation presentation = value.getValuePresentation();
+ if (presentation == null) continue;
+ try {
if (presentation instanceof XValueCompactPresentation) {
((XValueCompactPresentation)presentation).renderValue(renderer, value);
} else {
presentation.renderValue(renderer);
}
- final Color color = new JBColor(new Color(61, 128, 101), new Color(61, 128, 101));
- result.add(new LineExtensionInfo(" " + value.getName() + ": ", color, null, null, Font.PLAIN));
+ if (StringUtil.isEmpty(text.toString())) {
+ final String type = value.getValuePresentation().getType();
+ if (!StringUtil.isEmpty(type)) {
+ text.append(type, SimpleTextAttributes.REGULAR_ATTRIBUTES);
+ }
+ }
+ } catch (Exception e) {
+ continue;
+ }
+ final Color color = bpLine == lineNumber ? new JBColor(Gray._180, new Color(147, 217, 186)) : getForeground();
+
+ final String name = value.getName();
+ if (StringUtil.isEmpty(text.toString())) {
+ continue;
+ }
+ result.add(new LineExtensionInfo(" " + name + ": ", color, null, null, Font.PLAIN));
+
+ Variable var = new Variable(name, lineNumber);
+ VariableValue variableValue = oldValues.get(var);
+ if (variableValue == null) {
+ variableValue = new VariableValue(text.toString(), null, value.hashCode());
+ oldValues.put(var, variableValue);
+ }
+ if (variableValue.valueNodeHashCode != value.hashCode()) {
+ variableValue.old = variableValue.actual;
+ variableValue.actual = text.toString();
+ variableValue.valueNodeHashCode = value.hashCode();
+ }
+
+ if (!variableValue.isChanged()) {
for (String s : text.getTexts()) {
result.add(new LineExtensionInfo(s, color, null, null, Font.PLAIN));
}
+ } else {
+ variableValue.produceChangedParts(result);
}
- return result;
}
+ return result;
}
return null;
}
+
+ private static int getCurrentBreakPointLine(Set<XValueNodeImpl> values) {
+ try {
+ final XValueNodeImpl node = values.iterator().next();
+ final XDebugSession session = XDebugView.getSession(node.getTree());
+ if (session != null) {
+ final XSourcePosition position = session.getCurrentPosition();
+ if (position != null) {
+ return position.getLine();
+ }
+ }
+ } catch (Exception ignore){}
+ return -1;
+ }
+
+ public static JBColor getForeground() {
+ return new JBColor(new Color(61, 128, 101), new Color(61, 128, 101));
+ }
+
+ public static JBColor getChangedForeground() {
+ return new JBColor(new Color(202, 128, 33), new Color(161, 131, 10));
+ }
+
+ static class Variable {
+ private int lineNumber;
+ private String name;
+
+ public Variable(String name, int lineNumber) {
+ this.lineNumber = lineNumber;
+ this.name = name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Variable variable = (Variable)o;
+
+ if (lineNumber != variable.lineNumber) return false;
+ if (!name.equals(variable.name)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = lineNumber;
+ result = 31 * result + name.hashCode();
+ return result;
+ }
+ }
+
+ static class VariableValue {
+ private String actual;
+ private String old;
+ private int valueNodeHashCode;
+
+ public VariableValue(String actual, String old, int valueNodeHashCode) {
+ this.actual = actual;
+ this.old = old;
+ this.valueNodeHashCode = valueNodeHashCode;
+ }
+
+ public boolean isChanged() {
+ return old != null && !StringUtil.equals(actual, old);
+ }
+
+ public void produceChangedParts(List<LineExtensionInfo> result) {
+ if (isArray(actual) && isArray(old)) {
+ List<String> actualParts = getArrayParts(actual);
+ List<String> oldParts = getArrayParts(old);
+ result.add(new LineExtensionInfo("{", getForeground(), null, null, Font.PLAIN));
+ for (int i = 0; i < actualParts.size(); i++) {
+ if (i < oldParts.size() && StringUtil.equals(actualParts.get(i), oldParts.get(i))) {
+ result.add(new LineExtensionInfo(actualParts.get(i), getForeground(), null, null, Font.PLAIN));
+ } else {
+ result.add(new LineExtensionInfo(actualParts.get(i), getChangedForeground(), null, null, Font.BOLD));
+ }
+ if (i != actualParts.size() - 1) {
+ result.add(new LineExtensionInfo(", ", getForeground(), null, null, Font.PLAIN));
+ }
+ }
+ result.add(new LineExtensionInfo("}", getForeground(), null, null, Font.PLAIN));
+ return;
+ }
+
+ result.add(new LineExtensionInfo(actual, getChangedForeground(), null, null, Font.BOLD));
+ }
+
+ private static boolean isArray(String s) {
+ return s != null && s.startsWith("{") && s.endsWith("}");
+ }
+
+ private static List<String> getArrayParts(String array) {
+ return StringUtil.split(array.substring(1, array.length() - 1), ", ");
+ }
+ }
}