diff options
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.java | 187 |
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), ", "); + } + } } |