diff options
Diffstat (limited to 'platform/xdebugger-impl')
27 files changed, 615 insertions, 125 deletions
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java index 8ee2f1ee587a..1b0f0ca69a59 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java @@ -45,6 +45,7 @@ import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.ui.AppUIUtil; @@ -96,7 +97,8 @@ public class XDebugSessionImpl implements XDebugSession { private XSuspendContext mySuspendContext; private XExecutionStack myCurrentExecutionStack; private XStackFrame myCurrentStackFrame; - private XSourcePosition myCurrentPosition; + private boolean myIsTopFrame; + private XSourcePosition myTopFramePosition; private final AtomicBoolean myPaused = new AtomicBoolean(); private MyDependentBreakpointListener myDependentBreakpointListener; private XValueMarkers<?, ?> myValueMarkers; @@ -255,7 +257,13 @@ public class XDebugSessionImpl implements XDebugSession { @Override @Nullable public XSourcePosition getCurrentPosition() { - return myCurrentPosition; + return myCurrentStackFrame != null ? myCurrentStackFrame.getSourcePosition() : null; + } + + @Nullable + @Override + public XSourcePosition getTopFramePosition() { + return myTopFramePosition; } public XDebugSessionTab init(@NotNull XDebugProcess process, @NotNull XDebugSessionData sessionData, @Nullable RunContentDescriptor contentToReuse) { @@ -538,8 +546,8 @@ public class XDebugSessionImpl implements XDebugSession { mySuspendContext = null; myCurrentExecutionStack = null; myCurrentStackFrame = null; - adjustMouseTrackingCounter(myCurrentPosition, -1); - myCurrentPosition = null; + adjustMouseTrackingCounter(myTopFramePosition, -1); + myTopFramePosition = null; myActiveNonLineBreakpoint = null; UIUtil.invokeLaterIfNeeded(new Runnable() { @Override @@ -559,7 +567,7 @@ public class XDebugSessionImpl implements XDebugSession { } private boolean isTopFrameSelected() { - return myCurrentExecutionStack != null && myCurrentExecutionStack.getTopFrame() == myCurrentStackFrame; + return myCurrentExecutionStack != null && myIsTopFrame; } @@ -570,7 +578,7 @@ public class XDebugSessionImpl implements XDebugSession { if (executionStack != null) { XStackFrame topFrame = executionStack.getTopFrame(); if (topFrame != null) { - setCurrentStackFrame(executionStack, topFrame); + setCurrentStackFrame(executionStack, topFrame, true); myDebuggerManager.showExecutionPosition(); } } @@ -578,17 +586,18 @@ public class XDebugSessionImpl implements XDebugSession { } @Override - public void setCurrentStackFrame(@NotNull final XStackFrame frame) { - setCurrentStackFrame(myCurrentExecutionStack, frame); + public void setCurrentStackFrame(@NotNull XExecutionStack executionStack, @NotNull XStackFrame frame) { + setCurrentStackFrame(myCurrentExecutionStack, frame, frame == executionStack.getTopFrame()); } @Override - public void setCurrentStackFrame(@NotNull XExecutionStack executionStack, @NotNull XStackFrame frame) { + public void setCurrentStackFrame(@NotNull XExecutionStack executionStack, @NotNull XStackFrame frame, boolean isTopFrame) { if (mySuspendContext == null) return; boolean frameChanged = myCurrentStackFrame != frame; myCurrentExecutionStack = executionStack; myCurrentStackFrame = frame; + myIsTopFrame = isTopFrame; activateSession(); if (frameChanged) { @@ -708,7 +717,9 @@ public class XDebugSessionImpl implements XDebugSession { @Override public void run() { if (mySessionTab != null) { - mySessionTab.toFront(true); + if (XDebuggerSettingsManager.getInstanceImpl().getGeneralSettings().isShowDebuggerOnBreakpoint()) { + mySessionTab.toFront(true); + } mySessionTab.getUi().attractBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION); } } @@ -781,14 +792,14 @@ public class XDebugSessionImpl implements XDebugSession { mySuspendContext = suspendContext; myCurrentExecutionStack = suspendContext.getActiveExecutionStack(); myCurrentStackFrame = myCurrentExecutionStack != null ? myCurrentExecutionStack.getTopFrame() : null; - myCurrentPosition = myCurrentStackFrame != null ? myCurrentStackFrame.getSourcePosition() : null; + myTopFramePosition = myCurrentStackFrame != null ? myCurrentStackFrame.getSourcePosition() : null; myPaused.set(true); - if (myCurrentPosition != null) { - myDebuggerManager.setActiveSession(this, myCurrentPosition, false, getPositionIconRenderer(true)); + if (myTopFramePosition != null) { + myDebuggerManager.setActiveSession(this, myTopFramePosition, false, getPositionIconRenderer(true)); } - adjustMouseTrackingCounter(myCurrentPosition, 1); + adjustMouseTrackingCounter(myTopFramePosition, 1); if (myShowTabOnSuspend.compareAndSet(true, false)) { UIUtil.invokeLaterIfNeeded(new Runnable() { @@ -810,6 +821,7 @@ public class XDebugSessionImpl implements XDebugSession { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { + if (myProject.isDisposed()) return; Editor editor = XDebuggerUtilImpl.createEditor(new OpenFileDescriptor(myProject, position.getFile())); if (editor != null) { JComponent component = editor.getComponent(); @@ -855,8 +867,8 @@ public class XDebugSessionImpl implements XDebugSession { mySessionTab.detachFromSession(); } - adjustMouseTrackingCounter(myCurrentPosition, -1); - myCurrentPosition = null; + adjustMouseTrackingCounter(myTopFramePosition, -1); + myTopFramePosition = null; myCurrentExecutionStack = null; myCurrentStackFrame = null; mySuspendContext = null; @@ -970,6 +982,9 @@ public class XDebugSessionImpl implements XDebugSession { public void setWatchExpressions(@NotNull XExpression[] watchExpressions) { mySessionData.setWatchExpressions(watchExpressions); myDebuggerManager.getWatchesManager().setWatches(getWatchesKey(), watchExpressions); + if (Registry.is("debugger.watches.in.variables")) { + rebuildViews(); + } } XExpression[] getWatchExpressions() { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerSmartStepIntoHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerSmartStepIntoHandler.java index 6d09b8fd3128..2b84d05011c2 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerSmartStepIntoHandler.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerSmartStepIntoHandler.java @@ -47,7 +47,7 @@ public class XDebuggerSmartStepIntoHandler extends XDebuggerSuspendedActionHandl @Override protected void perform(@NotNull XDebugSession session, DataContext dataContext) { final XSmartStepIntoHandler<?> handler = session.getDebugProcess().getSmartStepIntoHandler(); - final XSourcePosition position = session.getCurrentPosition(); + final XSourcePosition position = session.getTopFramePosition(); if (position == null || handler == null) return; final FileEditor editor = FileEditorManager.getInstance(session.getProject()).getSelectedEditor(position.getFile()); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java index e2ce9ca7c63d..855abaaad74e 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java @@ -36,6 +36,7 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.util.DocumentUtil; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerUtil; import com.intellij.xdebugger.XSourcePosition; @@ -91,7 +92,7 @@ public class XLineBreakpointImpl<P extends XBreakpointProperties> extends XBreak RangeHighlighterEx highlighter = myHighlighter; if (highlighter != null && (!highlighter.isValid() - || highlighter.getStartOffset() >= document.getTextLength() + || !DocumentUtil.isValidOffset(highlighter.getStartOffset(), document) || !Comparing.equal(highlighter.getTextAttributes(), attributes) // it seems that this check is not needed - we always update line number from the highlighter // and highlighter is removed on line and file change anyway diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointManager.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointManager.java index 098b64052284..e88f54f24799 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointManager.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointManager.java @@ -261,7 +261,7 @@ public class XLineBreakpointManager { || mouseEvent.isMetaDown() || mouseEvent.isControlDown() || mouseEvent.getButton() != MouseEvent.BUTTON1 || MarkupEditorFilterFactory.createIsDiffFilter().avaliableIn(editor) - || e.getArea() != EditorMouseEventArea.LINE_MARKERS_AREA + || (e.getArea() != EditorMouseEventArea.LINE_MARKERS_AREA && e.getArea() != EditorMouseEventArea.FOLDING_OUTLINE_AREA) || ConsoleViewUtil.isConsoleViewEditor(editor) ||!isFromMyProject(editor)) { return; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XBreakpointActionsPanel.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XBreakpointActionsPanel.java index 36584d1105d4..de4d45f483bf 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XBreakpointActionsPanel.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XBreakpointActionsPanel.java @@ -122,6 +122,13 @@ public class XBreakpointActionsPanel<B extends XBreakpointBase<?,?,?>> extends X } } + JComponent getDefaultFocusComponent() { + if (myLogExpressionComboBox != null && myLogExpressionComboBox.getComboBox().isEnabled()) { + return myLogExpressionComboBox.getEditorComponent(); + } + return null; + } + public void dispose() { } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XLightBreakpointPropertiesPanel.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XLightBreakpointPropertiesPanel.java index 75cbb569ddfd..4e91c27f011d 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XLightBreakpointPropertiesPanel.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XLightBreakpointPropertiesPanel.java @@ -180,8 +180,15 @@ public class XLightBreakpointPropertiesPanel<B extends XBreakpointBase<?,?,?>> i myMainPanel.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent event) { - if (myConditionComboBox != null) { - IdeFocusManager.findInstance().requestFocus(myConditionComboBox.getEditorComponent(), false); + JComponent compToFocus; + if (myConditionComboBox != null && myConditionComboBox.getComboBox().isEnabled()) { + compToFocus = myConditionComboBox.getEditorComponent(); + } + else { + compToFocus = myActionsPanel.getDefaultFocusComponent(); + } + if (compToFocus != null) { + IdeFocusManager.findInstance().requestFocus(compToFocus, false); } } }); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/CodeFragmentInputComponent.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/CodeFragmentInputComponent.java index 141a56c9b721..be44e2c01d2b 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/CodeFragmentInputComponent.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/CodeFragmentInputComponent.java @@ -54,6 +54,7 @@ public class CodeFragmentInputComponent extends EvaluationInputComponent { myMainPanel.add(editorPanel, BorderLayout.CENTER); } + @NotNull protected XDebuggerEditorBase getInputEditor() { return myMultilineEditor; } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/EvaluationInputComponent.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/EvaluationInputComponent.java index c702cae00c6e..3803945f9598 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/EvaluationInputComponent.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/EvaluationInputComponent.java @@ -16,6 +16,7 @@ package com.intellij.xdebugger.impl.evaluate; import com.intellij.xdebugger.impl.ui.XDebuggerEditorBase; +import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -33,6 +34,7 @@ public abstract class EvaluationInputComponent { return myTitle; } + @NotNull protected abstract XDebuggerEditorBase getInputEditor(); public abstract void addComponent(JPanel contentPanel, JPanel resultPanel); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/ExpressionInputComponent.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/ExpressionInputComponent.java index 15a8bf6aed84..45b140ddf8e8 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/ExpressionInputComponent.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/ExpressionInputComponent.java @@ -63,6 +63,7 @@ public class ExpressionInputComponent extends EvaluationInputComponent { contentPanel.add(hint, BorderLayout.SOUTH); } + @NotNull protected XDebuggerEditorBase getInputEditor() { return myExpressionComboBox; } 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), ", "); + } + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java index 37da856156ea..74b3b5202dbd 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java @@ -18,6 +18,7 @@ package com.intellij.xdebugger.impl.evaluate; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CustomShortcutSet; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; @@ -79,13 +80,23 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { mySession.addSessionListener(new XDebugSessionAdapter() { @Override public void sessionStopped() { - SwingUtilities.invokeLater(new Runnable() { + ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { close(CANCEL_EXIT_CODE); } }); } + + @Override + public void stackFrameChanged() { + updateSourcePosition(); + } + + @Override + public void sessionPaused() { + updateSourcePosition(); + } }, myDisposable); myTreePanel = new XDebuggerTreePanel(session.getProject(), editorsProvider, myDisposable, sourcePosition, XDebuggerActions.EVALUATE_DIALOG_TREE_POPUP_GROUP, @@ -124,6 +135,15 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { init(); } + private void updateSourcePosition() { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + getInputEditor().setSourcePosition(mySession.getCurrentPosition()); + } + }); + } + @Override protected void doOKAction() { evaluate(); @@ -138,7 +158,7 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { super.actionPerformed(e); if (myMode == EvaluationMode.EXPRESSION && ((e.getModifiers() & InputEvent.CTRL_MASK) != 0)) { // add to watches - XExpression expression = myInputComponent.getInputEditor().getExpression(); + XExpression expression = getInputEditor().getExpression(); if (!XDebuggerUtilImpl.isEmptyExpression(expression)) { XDebugSessionTab tab = ((XDebugSessionImpl)mySession).getSessionTab(); if (tab != null) { @@ -179,7 +199,7 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { } public XExpression getExpression() { - return myInputComponent.getInputEditor().getExpression(); + return getInputEditor().getExpression(); } private static String getSwitchButtonText(EvaluationMode mode) { @@ -205,12 +225,16 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { } private void requestFocusInEditor() { - JComponent preferredFocusedComponent = myInputComponent.getInputEditor().getPreferredFocusedComponent(); + JComponent preferredFocusedComponent = getInputEditor().getPreferredFocusedComponent(); if (preferredFocusedComponent != null) { IdeFocusManager.getInstance(mySession.getProject()).requestFocus(preferredFocusedComponent, true); } } + private XDebuggerEditorBase getInputEditor() { + return myInputComponent.getInputEditor(); + } + private EvaluationInputComponent createInputComponent(EvaluationMode mode, XExpression text) { final Project project = mySession.getProject(); text = XExpressionImpl.changeMode(text, mode); @@ -223,7 +247,7 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { } private void evaluate() { - final XDebuggerEditorBase inputEditor = myInputComponent.getInputEditor(); + final XDebuggerEditorBase inputEditor = getInputEditor(); int offset = -1; //try to save caret position @@ -262,7 +286,7 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { } public void startEvaluation(@NotNull XDebuggerEvaluator.XEvaluationCallback evaluationCallback) { - final XDebuggerEditorBase inputEditor = myInputComponent.getInputEditor(); + final XDebuggerEditorBase inputEditor = getInputEditor(); inputEditor.saveTextInHistory(); XExpression expression = inputEditor.getExpression(); @@ -277,13 +301,13 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { @Override public JComponent getPreferredFocusedComponent() { - return myInputComponent.getInputEditor().getPreferredFocusedComponent(); + return getInputEditor().getPreferredFocusedComponent(); } private class SwitchModeAction extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { - XExpression text = myInputComponent.getInputEditor().getExpression(); + XExpression text = getInputEditor().getExpression(); if (myMode == EvaluationMode.EXPRESSION) { switchToMode(EvaluationMode.CODE_FRAGMENT, text); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java index b98440b5d69f..9999ac015b77 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java @@ -188,10 +188,10 @@ public class XFramesView extends XDebugView { return toolbar; } - private StackFramesListBuilder getOrCreateBuilder(XExecutionStack executionStack) { + private StackFramesListBuilder getOrCreateBuilder(XExecutionStack executionStack, XDebugSession session) { StackFramesListBuilder builder = myBuilders.get(executionStack); if (builder == null) { - builder = new StackFramesListBuilder(executionStack); + builder = new StackFramesListBuilder(executionStack, session); myBuilders.put(executionStack, builder); } return builder; @@ -244,7 +244,6 @@ public class XFramesView extends XDebugView { } myToolbar.setAddSeparatorFirst(!invisible); updateFrames(activeExecutionStack, session); - myListenersEnabled = true; } @Override @@ -270,19 +269,14 @@ public class XFramesView extends XDebugView { return; } if (mySelectedStack != null) { - getOrCreateBuilder(mySelectedStack).stop(); + getOrCreateBuilder(mySelectedStack, session).stop(); } mySelectedStack = executionStack; if (executionStack != null) { - StackFramesListBuilder builder = getOrCreateBuilder(executionStack); + StackFramesListBuilder builder = getOrCreateBuilder(executionStack, session); builder.initModel(myFramesList.getModel()); builder.start(); - XStackFrame topFrame = executionStack.getTopFrame(); - if (topFrame != null) { - myFramesList.setSelectedValue(topFrame, true); - session.setCurrentStackFrame(executionStack, topFrame); - } } } @@ -303,7 +297,7 @@ public class XFramesView extends XDebugView { if (selected instanceof XStackFrame) { XDebugSession session = getSession(e); if (session != null) { - session.setCurrentStackFrame(mySelectedStack, (XStackFrame)selected); + session.setCurrentStackFrame(mySelectedStack, (XStackFrame)selected, myFramesList.getSelectedIndex() == 0); } } } @@ -312,21 +306,15 @@ public class XFramesView extends XDebugView { private XExecutionStack myExecutionStack; private final List<XStackFrame> myStackFrames; private String myErrorMessage; - private int myNextFrameIndex; + private int myNextFrameIndex = 0; private boolean myRunning; private boolean myAllFramesLoaded; + private final XDebugSession mySession; - private StackFramesListBuilder(final XExecutionStack executionStack) { + private StackFramesListBuilder(final XExecutionStack executionStack, XDebugSession session) { myExecutionStack = executionStack; + mySession = session; myStackFrames = new ArrayList<XStackFrame>(); - XStackFrame topFrame = executionStack.getTopFrame(); - if (topFrame != null) { - myStackFrames.add(topFrame); - myNextFrameIndex = 1; - } - else { - myNextFrameIndex = 0; - } } @Override @@ -336,6 +324,9 @@ public class XFramesView extends XDebugView { public void run() { myStackFrames.addAll(stackFrames); addFrameListElements(stackFrames, last); + if (myNextFrameIndex == 0) { + selectTopFrame(); + } myNextFrameIndex += stackFrames.size(); myAllFramesLoaded = last; if (last) { @@ -399,6 +390,15 @@ public class XFramesView extends XDebugView { myRunning = false; } + private void selectTopFrame() { + if (!myStackFrames.isEmpty() && mySelectedStack != null) { + XStackFrame topFrame = myStackFrames.get(0); + myFramesList.setSelectedValue(topFrame, true); + mySession.setCurrentStackFrame(mySelectedStack, topFrame, true); + myListenersEnabled = true; + } + } + @SuppressWarnings("unchecked") public void initModel(final DefaultListModel model) { model.removeAllElements(); @@ -411,6 +411,7 @@ public class XFramesView extends XDebugView { else if (!myAllFramesLoaded) { model.addElement(null); } + selectTopFrame(); } } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java index df43b1147419..ea53645b57e5 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java @@ -36,7 +36,8 @@ import static com.intellij.xdebugger.impl.ui.tree.nodes.MessageTreeNode.createIn * @author nik */ public class XVariablesView extends XVariablesViewBase { - public static final Key<Map<Pair<VirtualFile, Integer>, Set<XValueNodeImpl>>> DEBUG_VARIABLES = Key.create("debug.frame"); + public static final Key<Map<Pair<VirtualFile, Integer>, Set<XValueNodeImpl>>> DEBUG_VARIABLES = Key.create("debug.variables"); + public static final Key<Map<VirtualFile, Long>> DEBUG_VARIABLES_TIMESTAMPS = Key.create("debug.variables.timestamps"); public XVariablesView(@NotNull XDebugSessionImpl session) { super(session.getProject(), session.getDebugProcess().getEditorsProvider(), session.getValueMarkers()); @@ -69,6 +70,7 @@ public class XVariablesView extends XVariablesViewBase { protected void clear() { XDebuggerTree tree = getTree(); tree.getProject().putUserData(DEBUG_VARIABLES, null); + tree.getProject().putUserData(DEBUG_VARIABLES_TIMESTAMPS, null); tree.setSourcePosition(null); XDebuggerTreeNode node; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesViewBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesViewBase.java index ace9938318df..d4bd27c30d9b 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesViewBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesViewBase.java @@ -15,20 +15,42 @@ */ package com.intellij.xdebugger.impl.frame; +import com.intellij.codeInsight.hint.HintManager; +import com.intellij.codeInsight.hint.HintUtil; import com.intellij.ide.dnd.DnDManager; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.event.SelectionEvent; +import com.intellij.openapi.editor.event.SelectionListener; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; +import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; 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.SimpleColoredComponent; +import com.intellij.ui.SimpleColoredText; import com.intellij.xdebugger.XDebuggerBundle; +import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; +import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; +import com.intellij.xdebugger.frame.XFullValueEvaluator; import com.intellij.xdebugger.frame.XStackFrame; +import com.intellij.xdebugger.frame.XValue; +import com.intellij.xdebugger.frame.XValuePlace; +import com.intellij.xdebugger.frame.presentation.XValuePresentation; import com.intellij.xdebugger.impl.actions.XDebuggerActions; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreePanel; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeRestorer; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeState; +import com.intellij.xdebugger.impl.ui.tree.nodes.XEvaluationCallbackBase; import com.intellij.xdebugger.impl.ui.tree.nodes.XStackFrameNode; import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; +import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodePresentationConfigurator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -51,17 +73,84 @@ public abstract class XVariablesViewBase extends XDebugView { DnDManager.getInstance().registerSource(myDebuggerTreePanel, myDebuggerTreePanel.getTree()); } - protected void buildTreeAndRestoreState(@NotNull XStackFrame stackFrame) { + protected void buildTreeAndRestoreState(@NotNull final XStackFrame stackFrame) { XDebuggerTree tree = myDebuggerTreePanel.getTree(); - tree.setSourcePosition(stackFrame.getSourcePosition()); + final XSourcePosition position = stackFrame.getSourcePosition(); + tree.setSourcePosition(position); tree.setRoot(new XStackFrameNode(tree, stackFrame), false); - tree.getProject().putUserData(XVariablesView.DEBUG_VARIABLES, new HashMap<Pair<VirtualFile, Integer>, Set<XValueNodeImpl>>()); + final Project project = tree.getProject(); + project.putUserData(XVariablesView.DEBUG_VARIABLES, new HashMap<Pair<VirtualFile, Integer>, Set<XValueNodeImpl>>()); + project.putUserData(XVariablesView.DEBUG_VARIABLES_TIMESTAMPS, new HashMap<VirtualFile, Long>()); Object newEqualityObject = stackFrame.getEqualityObject(); if (myFrameEqualityObject != null && newEqualityObject != null && myFrameEqualityObject.equals(newEqualityObject) && myTreeState != null) { disposeTreeRestorer(); myTreeRestorer = myTreeState.restoreState(tree); } + if (position != null && Registry.is("ide.debugger.inline")) { + final VirtualFile file = position.getFile(); + final FileEditor fileEditor = FileEditorManagerEx.getInstanceEx(project).getSelectedEditor(file); + if (fileEditor instanceof PsiAwareTextEditorImpl) { + final Editor editor = ((PsiAwareTextEditorImpl)fileEditor).getEditor(); + final SelectionListener listener = new SelectionListener() { + @Override + public void selectionChanged(SelectionEvent e) { + final String text = editor.getDocument().getText(e.getNewRange()); + final XDebuggerEvaluator evaluator = stackFrame.getEvaluator(); + if (evaluator != null && !StringUtil.isEmpty(text) + && !(text.contains("exec(") || text.contains("++") || text.contains("--") || text.contains("="))) { + evaluator.evaluate(text, new XEvaluationCallbackBase() { + @Override + public void evaluated(@NotNull XValue result) { + result.computePresentation(new XValueNodePresentationConfigurator.ConfigurableXValueNodeImpl() { + @Override + public void applyPresentation(@Nullable Icon icon, + @NotNull XValuePresentation valuePresenter, + boolean hasChildren) { + SimpleColoredText text = new SimpleColoredText(); + XValueNodeImpl.buildText(valuePresenter, text, false); + SimpleColoredComponent component = HintUtil.createInformationComponent(); + text.appendToComponent(component); + String str = text.toString(); + if ("undefined".equals(str) || str.startsWith("Cannot find local variable") + || str.startsWith("Invalid expression")) { + return; //todo[kb] this is temporary solution + } + HintManager.getInstance().hideAllHints(); + HintManager.getInstance().showInformationHint(editor, component); + } + + @Override + public void setFullValueEvaluator(@NotNull XFullValueEvaluator fullValueEvaluator) { + } + + @Override + public boolean isObsolete() { + return true; + } + }, XValuePlace.TOOLTIP); + } + + @Override + public void errorOccurred(@NotNull String errorMessage) { + System.out.println(errorMessage); + } + }, position); + } + } + }; + editor.getSelectionModel().addSelectionListener(listener); + Disposer.register(tree, new Disposable() { + @Override + public void dispose() { + final FileEditor fileEditor = FileEditorManagerEx.getInstanceEx(project).getSelectedEditor(file); + if (fileEditor instanceof PsiAwareTextEditorImpl) { + ((PsiAwareTextEditorImpl)fileEditor).getEditor().getSelectionModel().removeSelectionListener(listener); + } + } + }); + } + } } protected void saveCurrentTreeState(@Nullable XStackFrame stackFrame) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/GeneralConfigurableUi.form b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/GeneralConfigurableUi.form index 4d1f8e52d24f..1260cb3ff44a 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/GeneralConfigurableUi.form +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/GeneralConfigurableUi.form @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.xdebugger.impl.settings.GeneralConfigurableUi"> - <grid id="27dc6" binding="rootPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="27dc6" binding="rootPanel" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> <xy x="20" y="20" width="500" height="400"/> @@ -10,7 +10,7 @@ <children> <component id="4b50" class="javax.swing.JCheckBox" binding="hideDebugWindowCheckBox"> <constraints> - <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text resource-bundle="messages/XDebuggerBundle" key="setting.hide.window.label"/> @@ -18,7 +18,7 @@ </component> <vspacer id="8e2ed"> <constraints> - <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> + <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> </constraints> </vspacer> <component id="fc652" class="javax.swing.JCheckBox" binding="focusApplicationOnBreakpointCheckBox" default-binding="true"> @@ -29,6 +29,14 @@ <text resource-bundle="messages/XDebuggerBundle" key="setting.focus.app.on.breakpoint.label"/> </properties> </component> + <component id="4c3e" class="javax.swing.JCheckBox" binding="myShowDebugWindowOnCheckBox" default-binding="true"> + <constraints> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <text resource-bundle="messages/XDebuggerBundle" key="settings.show.window.label"/> + </properties> + </component> </children> </grid> </form> diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/GeneralConfigurableUi.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/GeneralConfigurableUi.java index 273c5490e35d..bab2c88465ad 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/GeneralConfigurableUi.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/GeneralConfigurableUi.java @@ -25,23 +25,27 @@ class GeneralConfigurableUi implements ConfigurableUi<XDebuggerGeneralSettings> private JPanel rootPanel; private JCheckBox hideDebugWindowCheckBox; private JCheckBox focusApplicationOnBreakpointCheckBox; + private JCheckBox myShowDebugWindowOnCheckBox; @Override public void reset(@NotNull XDebuggerGeneralSettings settings) { focusApplicationOnBreakpointCheckBox.setSelected(Registry.is("debugger.mayBringFrameToFrontOnBreakpoint")); hideDebugWindowCheckBox.setSelected(settings.isHideDebuggerOnProcessTermination()); + myShowDebugWindowOnCheckBox.setSelected(settings.isShowDebuggerOnBreakpoint()); } @Override public boolean isModified(@NotNull XDebuggerGeneralSettings settings) { return focusApplicationOnBreakpointCheckBox.isSelected() != Registry.is("debugger.mayBringFrameToFrontOnBreakpoint") || - hideDebugWindowCheckBox.isSelected() != settings.isHideDebuggerOnProcessTermination(); + hideDebugWindowCheckBox.isSelected() != settings.isHideDebuggerOnProcessTermination() || + myShowDebugWindowOnCheckBox.isSelected() != settings.isShowDebuggerOnBreakpoint(); } @Override public void apply(@NotNull XDebuggerGeneralSettings settings) { Registry.get("debugger.mayBringFrameToFrontOnBreakpoint").setValue(focusApplicationOnBreakpointCheckBox.isSelected()); settings.setHideDebuggerOnProcessTermination(hideDebugWindowCheckBox.isSelected()); + settings.setShowDebuggerOnBreakpoint(myShowDebugWindowOnCheckBox.isSelected()); } @NotNull diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/XDebuggerGeneralSettings.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/XDebuggerGeneralSettings.java index 9720d9517c51..205c1c3948ed 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/XDebuggerGeneralSettings.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/XDebuggerGeneralSettings.java @@ -27,6 +27,7 @@ public class XDebuggerGeneralSettings { private boolean myUnmuteOnStop = false; private boolean hideDebuggerOnProcessTermination; + private boolean myShowDebuggerOnBreakpoint = true; @Tag("evaluation-dialog-mode") public EvaluationMode getEvaluationDialogMode() { @@ -53,4 +54,12 @@ public class XDebuggerGeneralSettings { public void setHideDebuggerOnProcessTermination(boolean hideDebuggerOnProcessTermination) { this.hideDebuggerOnProcessTermination = hideDebuggerOnProcessTermination; } + + public boolean isShowDebuggerOnBreakpoint() { + return myShowDebuggerOnBreakpoint; + } + + public void setShowDebuggerOnBreakpoint(boolean showDebuggerOnBreakpoint) { + this.myShowDebuggerOnBreakpoint = showDebuggerOnBreakpoint; + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerCopyPastePreprocessor.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerCopyPastePreprocessor.java new file mode 100644 index 000000000000..7041b24f07fc --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerCopyPastePreprocessor.java @@ -0,0 +1,47 @@ +/* + * 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.intellij.xdebugger.impl.ui; + +import com.intellij.codeInsight.editorActions.CopyPastePreProcessor; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.RawText; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author egor + */ +public class DebuggerCopyPastePreprocessor implements CopyPastePreProcessor { + public static final Key<Boolean> REMOVE_NEWLINES_ON_PASTE = new Key<Boolean>("REMOVE_NEWLINES_ON_PASTE"); + + @Nullable + @Override + public String preprocessOnCopy(PsiFile file, int[] startOffsets, int[] endOffsets, String text) { + return null; + } + + @NotNull + @Override + public String preprocessOnPaste(Project project, PsiFile file, Editor editor, String text, RawText rawText) { + if (editor.getUserData(REMOVE_NEWLINES_ON_PASTE) != null) { + return text.replace("\n", " "); + } + return text; + } +} diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java index 4c3766f23f5d..1a4505f6d85b 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java @@ -227,6 +227,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { final Executor debugExecutor = DefaultDebugExecutor.getDebugExecutorInstance(); ExecutionEnvironment environment = getEnvironment(); if (environment != null) { + leftToolbar.add(ActionManager.getInstance().getAction(IdeActions.ACTION_RERUN)); List<AnAction> additionalRestartActions = session.getRestartActions(); if (!additionalRestartActions.isEmpty()) { leftToolbar.addAll(additionalRestartActions); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java index 991036b7f438..61a499ccf4dd 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java @@ -59,7 +59,7 @@ public abstract class XDebuggerEditorBase { private final XDebuggerEditorsProvider myDebuggerEditorsProvider; @NotNull private final EvaluationMode myMode; @Nullable private final String myHistoryId; - private final XSourcePosition mySourcePosition; + @Nullable private XSourcePosition mySourcePosition; private int myHistoryIndex; private final JLabel myChooseFactory = new JLabel(); @@ -124,6 +124,13 @@ public abstract class XDebuggerEditorBase { return panel; } + public void setSourcePosition(@Nullable XSourcePosition sourcePosition) { + if (mySourcePosition != sourcePosition) { + mySourcePosition = sourcePosition; + setExpression(getExpression(), false); + } + } + @NotNull public EvaluationMode getMode() { return myMode; @@ -137,10 +144,16 @@ public abstract class XDebuggerEditorBase { protected abstract void doSetText(XExpression text); public void setExpression(@Nullable XExpression text) { + setExpression(text, true); + } + + private void setExpression(@Nullable XExpression text, boolean saveInHistory) { if (text == null) { text = getMode() == EvaluationMode.EXPRESSION ? XExpressionImpl.EMPTY_EXPRESSION : XExpressionImpl.EMPTY_CODE_FRAGMENT; } - saveTextInHistory(text); + if (saveInHistory) { + saveTextInHistory(text); + } Language language = text.getLanguage(); if (language == null) { if (mySourcePosition != null) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerExpressionComboBox.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerExpressionComboBox.java index 051683b875c1..3039d2acda7f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerExpressionComboBox.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerExpressionComboBox.java @@ -17,9 +17,7 @@ package com.intellij.xdebugger.impl.ui; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.event.DocumentAdapter; -import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.editor.event.DocumentListener; +import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComboBox; import com.intellij.ui.EditorComboBoxEditor; @@ -101,6 +99,11 @@ public class XDebuggerExpressionComboBox extends XDebuggerEditorBase { } super.setItem(createDocument(((XExpression)anObject))); } + + @Override + protected void onEditorCreate(EditorEx editor) { + editor.putUserData(DebuggerCopyPastePreprocessor.REMOVE_NEWLINES_ON_PASTE, true); + } }; myEditor.getEditorComponent().setFontInheritedFromLAF(false); myComboBox.setEditor(myEditor); @@ -110,23 +113,6 @@ public class XDebuggerExpressionComboBox extends XDebuggerEditorBase { } @Override - protected Document createDocument(XExpression text) { - Document document = super.createDocument(text); - document.addDocumentListener(REPLACE_NEWLINES_LISTENER); - return document; - } - - private static DocumentListener REPLACE_NEWLINES_LISTENER = new DocumentAdapter() { - @Override - public void documentChanged(DocumentEvent e) { - String text = e.getNewFragment().toString(); - if (text.contains("\n")) { - e.getDocument().replaceString(e.getOffset(), e.getOffset() + e.getNewLength(), text.replace('\n', ' ')); - } - } - }; - - @Override protected void onHistoryChanged() { fillComboBox(); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerMultilineEditor.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerMultilineEditor.java index aa3445b4b421..3f06418ac8ac 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerMultilineEditor.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerMultilineEditor.java @@ -71,7 +71,7 @@ public class XDebuggerMultilineEditor extends XDebuggerEditorBase { @Override public XExpression getExpression() { - return XExpressionImpl.fromText(myEditorTextField.getText(), EvaluationMode.CODE_FRAGMENT); + return getEditorsProvider().createExpression(getProject(), myEditorTextField.getDocument(), myExpression.getLanguage(), EvaluationMode.CODE_FRAGMENT); } @Override diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/ShowReferringObjectsAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/ShowReferringObjectsAction.java new file mode 100644 index 000000000000..4c2962f7f576 --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/ShowReferringObjectsAction.java @@ -0,0 +1,51 @@ +/* + * 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.intellij.xdebugger.impl.ui.tree.actions; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.xdebugger.XDebuggerBundle; +import com.intellij.xdebugger.frame.XReferrersProvider; +import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; +import com.intellij.xdebugger.impl.ui.tree.XInspectDialog; +import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; +import org.jetbrains.annotations.NotNull; + +/** + * @author egor + */ +public class ShowReferringObjectsAction extends XDebuggerTreeActionBase { + + @Override + protected boolean isEnabled(@NotNull XValueNodeImpl node, @NotNull AnActionEvent e) { + return node.getValueContainer().getReferrersProvider() != null; + } + + @Override + protected void perform(XValueNodeImpl node, @NotNull String nodeName, AnActionEvent e) { + XReferrersProvider referrersProvider = node.getValueContainer().getReferrersProvider(); + if (referrersProvider != null) { + XDebuggerTree tree = XDebuggerTree.getTree(e.getDataContext()); + XInspectDialog dialog = new XInspectDialog(tree.getProject(), + tree.getEditorsProvider(), + tree.getSourcePosition(), + nodeName, + referrersProvider.getReferringObjectsValue(), + tree.getValueMarkers()); + dialog.setTitle(XDebuggerBundle.message("showReferring.dialog.title", nodeName)); + dialog.show(); + } + } +} diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesAction.java index 7c77bafc6553..211fddae40ea 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesAction.java @@ -23,6 +23,7 @@ import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.impl.XDebugSessionImpl; import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl; import com.intellij.xdebugger.impl.frame.XWatchesView; +import com.intellij.xdebugger.impl.ui.XDebugSessionTab; import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; import org.jetbrains.annotations.NotNull; @@ -41,10 +42,7 @@ class XAddToWatchesAction extends XDebuggerTreeActionBase { if (watchesView != null) { String expression = node.getValueContainer().getEvaluationExpression(); if (!StringUtil.isEmpty(expression)) { - XExpressionImpl watchExpression = XExpressionImpl.fromText(expression); - if (watchExpression != null) { - watchesView.addWatchExpression(watchExpression, -1, true); - } + watchesView.addWatchExpression(XExpressionImpl.fromText(expression), -1, true); } } } @@ -55,7 +53,10 @@ class XAddToWatchesAction extends XDebuggerTreeActionBase { if (view == null && project != null) { XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession(); if (session != null) { - return ((XDebugSessionImpl)session).getSessionTab().getWatchesView(); + XDebugSessionTab tab = ((XDebugSessionImpl)session).getSessionTab(); + if (tab != null) { + return tab.getWatchesView(); + } } } return view; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XStackFrameNode.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XStackFrameNode.java index fa32ebcc4d75..b7b21560f438 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XStackFrameNode.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XStackFrameNode.java @@ -15,7 +15,16 @@ */ package com.intellij.xdebugger.impl.ui.tree.nodes; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.xdebugger.XDebugSession; +import com.intellij.xdebugger.XExpression; +import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; import com.intellij.xdebugger.frame.XStackFrame; +import com.intellij.xdebugger.frame.XValue; +import com.intellij.xdebugger.frame.XValueChildrenList; +import com.intellij.xdebugger.impl.XDebugSessionImpl; +import com.intellij.xdebugger.impl.frame.XDebugView; +import com.intellij.xdebugger.impl.ui.XDebugSessionData; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; import org.jetbrains.annotations.NotNull; @@ -27,4 +36,32 @@ public class XStackFrameNode extends XValueContainerNode<XStackFrame> { super(tree, null, xStackFrame); setLeaf(false); } + + @Override + public void startComputingChildren() { + if (Registry.is("debugger.watches.in.variables")) { + XDebugSession session = XDebugView.getSession(getTree()); + XDebuggerEvaluator evaluator = getValueContainer().getEvaluator(); + if (session != null && evaluator != null) { + XDebugSessionData data = ((XDebugSessionImpl)session).getSessionData(); + XExpression[] expressions = data.getWatchExpressions(); + for (final XExpression expression : expressions) { + evaluator.evaluate(expression, new XDebuggerEvaluator.XEvaluationCallback() { + @Override + public void evaluated(@NotNull XValue result) { + XValueChildrenList watches = new XValueChildrenList(); + watches.add(expression.getExpression(), result); + addChildren(watches, false); + } + + @Override + public void errorOccurred(@NotNull String errorMessage) { + // do not add anything + } + }, getValueContainer().getSourcePosition()); + } + } + } + super.startComputingChildren(); + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java index b9f90fe86b2b..a2fb3d51d253 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -15,6 +15,7 @@ */ package com.intellij.xdebugger.impl.ui.tree.nodes; +import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.ObjectUtils; import com.intellij.util.SmartList; @@ -90,6 +91,11 @@ public abstract class XValueContainerNode<ValueContainer extends XValueContainer XValueNodeImpl node = new XValueNodeImpl(myTree, XValueContainerNode.this, children.getName(i), children.getValue(i)); myValueChildren.add(node); newChildren.add(node); + + if (Registry.is("ide.debugger.inline") && "this".equals(node.getName())) { //todo[kb]: try to generify this dirty hack + //initialize "this" fields to display in inline view + node.getChildren(); + } } myTopGroups = createGroupNodes(children.getTopGroups(), myTopGroups, newChildren); myBottomGroups = createGroupNodes(children.getBottomGroups(), myBottomGroups, newChildren); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java index 1f3d4c77e84f..292cca541699 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java @@ -16,6 +16,8 @@ package com.intellij.xdebugger.impl.ui.tree.nodes; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; @@ -24,9 +26,11 @@ import com.intellij.ui.AppUIUtil; import com.intellij.ui.ColoredTextContainer; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.NotNullFunction; +import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.frame.*; import com.intellij.xdebugger.frame.presentation.XValuePresentation; +import com.intellij.xdebugger.impl.frame.XDebugView; import com.intellij.xdebugger.impl.frame.XValueMarkers; import com.intellij.xdebugger.impl.frame.XVariablesView; import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; @@ -120,26 +124,7 @@ public class XValueNodeImpl extends XValueContainerNode<XValue> implements XValu myValuePresentation = valuePresentation; myRawValue = XValuePresentationUtil.computeValueText(valuePresentation); if (Registry.is("ide.debugger.inline")) { - try { - getValueContainer().computeSourcePosition(new XNavigatable() { - @Override - public void setSourcePosition(@Nullable XSourcePosition sourcePosition) { - Map<Pair<VirtualFile, Integer>, Set<XValueNodeImpl>> map = myTree.getProject().getUserData(XVariablesView.DEBUG_VARIABLES); - if (map == null || sourcePosition == null) return; - VirtualFile file = sourcePosition.getFile(); - int line = sourcePosition.getLine(); - Pair<VirtualFile, Integer> key = Pair.create(file, line); - Set<XValueNodeImpl> presentations = map.get(key); - if (presentations == null) { - presentations = new LinkedHashSet<XValueNodeImpl>(); - map.put(key, presentations); - } - presentations.add(XValueNodeImpl.this); - } - }); - } - catch (Exception ignore) { - } + updateInlineDebuggerData(); } updateText(); setLeaf(!hasChildren); @@ -147,6 +132,39 @@ public class XValueNodeImpl extends XValueContainerNode<XValue> implements XValu myTree.nodeLoaded(this, myName); } + public void updateInlineDebuggerData() { + try { + final XDebugSession session = XDebugView.getSession(getTree()); + if (session != null) { + final XSourcePosition position = session.getCurrentPosition(); + if (position != null) { + getValueContainer().computeSourcePosition(new XNearestSourcePosition() { + @Override + public void setSourcePosition(@Nullable XSourcePosition sourcePosition) { + final Map<Pair<VirtualFile, Integer>, Set<XValueNodeImpl>> map = myTree.getProject().getUserData(XVariablesView.DEBUG_VARIABLES); + final Map<VirtualFile, Long> timestamps = myTree.getProject().getUserData(XVariablesView.DEBUG_VARIABLES_TIMESTAMPS); + if (map == null || timestamps == null || sourcePosition == null) return; + VirtualFile file = sourcePosition.getFile(); + final Document doc = FileDocumentManager.getInstance().getDocument(file); + if (doc == null) return; + int line = sourcePosition.getLine(); + Pair<VirtualFile, Integer> key = Pair.create(file, line); + Set<XValueNodeImpl> presentations = map.get(key); + if (presentations == null) { + presentations = new LinkedHashSet<XValueNodeImpl>(); + map.put(key, presentations); + timestamps.put(file, doc.getModificationStamp()); + } + presentations.add(XValueNodeImpl.this); + } + }); + } + } + } + catch (Exception ignore) { + } + } + @Override public void setFullValueEvaluator(@NotNull final XFullValueEvaluator fullValueEvaluator) { AppUIUtil.invokeOnEdt(new Runnable() { @@ -179,7 +197,13 @@ public class XValueNodeImpl extends XValueContainerNode<XValue> implements XValu } public static void buildText(@NotNull XValuePresentation valuePresenter, @NotNull ColoredTextContainer text) { - XValuePresentationUtil.appendSeparator(text, valuePresenter.getSeparator()); + buildText(valuePresenter, text, true); + } + + public static void buildText(@NotNull XValuePresentation valuePresenter, @NotNull ColoredTextContainer text, boolean appendSeparator) { + if (appendSeparator) { + XValuePresentationUtil.appendSeparator(text, valuePresenter.getSeparator()); + } String type = valuePresenter.getType(); if (type != null) { text.append("{" + type + "} ", XDebuggerUIConstants.TYPE_ATTRIBUTES); |