blob: dbcf43fd6168c8d76c66233c82ad2ad1a30679a1 [file] [log] [blame]
/*
* Copyright 2000-2009 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.debugger.impl;
import com.intellij.debugger.DebugEnvironment;
import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.DebuggerInvocationUtil;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.*;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationListener;
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
import com.intellij.debugger.engine.jdi.StackFrameProxy;
import com.intellij.debugger.engine.requests.RequestManagerImpl;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
import com.intellij.debugger.ui.breakpoints.Breakpoint;
import com.intellij.debugger.ui.breakpoints.BreakpointWithHighlighter;
import com.intellij.debugger.ui.breakpoints.LineBreakpoint;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.ExecutionResult;
import com.intellij.execution.configurations.RemoteConnection;
import com.intellij.execution.configurations.RemoteState;
import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.PsiCompiledElement;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.unscramble.ThreadState;
import com.intellij.util.Alarm;
import com.intellij.xdebugger.AbstractDebuggerSession;
import com.intellij.xdebugger.XDebugProcess;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerManager;
import com.intellij.xdebugger.impl.actions.XDebuggerActions;
import com.intellij.xdebugger.impl.evaluate.quick.common.ValueLookupManager;
import com.sun.jdi.ObjectCollectedException;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.event.Event;
import com.sun.jdi.request.EventRequest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DebuggerSession implements AbstractDebuggerSession {
private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.DebuggerSession");
// flags
private final MyDebuggerStateManager myContextManager;
public static final int STATE_STOPPED = 0;
public static final int STATE_RUNNING = 1;
public static final int STATE_WAITING_ATTACH = 2;
public static final int STATE_PAUSED = 3;
public static final int STATE_WAIT_EVALUATION = 5;
public static final int STATE_DISPOSED = 6;
public static final int EVENT_ATTACHED = 0;
public static final int EVENT_DETACHED = 1;
public static final int EVENT_RESUME = 4;
public static final int EVENT_STEP = 5;
public static final int EVENT_PAUSE = 6;
public static final int EVENT_REFRESH = 7;
public static final int EVENT_CONTEXT = 8;
public static final int EVENT_START_WAIT_ATTACH = 9;
public static final int EVENT_DISPOSE = 10;
public static final int EVENT_REFRESH_VIEWS_ONLY = 11;
public static final int EVENT_THREADS_REFRESH = 12;
private volatile boolean myIsEvaluating;
private volatile int myIgnoreFiltersFrameCountThreshold = 0;
private DebuggerSessionState myState = null;
private final String mySessionName;
private final DebugProcessImpl myDebugProcess;
private @NotNull GlobalSearchScope mySearchScope;
private final DebuggerContextImpl SESSION_EMPTY_CONTEXT;
//Thread, user is currently stepping through
private final Set<ThreadReferenceProxyImpl> mySteppingThroughThreads = new HashSet<ThreadReferenceProxyImpl>();
protected final Alarm myUpdateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
private boolean myModifiedClassesScanRequired = false;
public boolean isSteppingThrough(ThreadReferenceProxyImpl threadProxy) {
return mySteppingThroughThreads.contains(threadProxy);
}
@NotNull
public GlobalSearchScope getSearchScope() {
//noinspection ConstantConditions
LOG.assertTrue(mySearchScope != null, "Accessing Session's search scope before its initialization");
return mySearchScope;
}
public boolean isModifiedClassesScanRequired() {
return myModifiedClassesScanRequired;
}
public void setModifiedClassesScanRequired(boolean modifiedClassesScanRequired) {
myModifiedClassesScanRequired = modifiedClassesScanRequired;
}
private class MyDebuggerStateManager extends DebuggerStateManager {
private DebuggerContextImpl myDebuggerContext;
MyDebuggerStateManager() {
myDebuggerContext = SESSION_EMPTY_CONTEXT;
}
@Override
public DebuggerContextImpl getContext() {
return myDebuggerContext;
}
/**
* actually state changes not in the same sequence as you call setState
* the 'resuming' setState with context.getSuspendContext() == null may be set prior to
* the setState for the context with context.getSuspendContext()
*
* in this case we assume that the latter setState is ignored
* since the thread was resumed
*/
@Override
public void setState(final DebuggerContextImpl context, final int state, final int event, final String description) {
ApplicationManager.getApplication().assertIsDispatchThread();
final DebuggerSession session = context.getDebuggerSession();
LOG.assertTrue(session == DebuggerSession.this || session == null);
final Runnable setStateRunnable = new Runnable() {
@Override
public void run() {
LOG.assertTrue(myDebuggerContext.isInitialised());
myDebuggerContext = context;
if (LOG.isDebugEnabled()) {
LOG.debug("DebuggerSession state = " + state + ", event = " + event);
}
myIsEvaluating = false;
myState = new DebuggerSessionState(state, description);
fireStateChanged(context, event);
}
};
if(context.getSuspendContext() == null) {
setStateRunnable.run();
}
else {
getProcess().getManagerThread().schedule(new SuspendContextCommandImpl(context.getSuspendContext()) {
@Override
public void contextAction() throws Exception {
context.initCaches();
DebuggerInvocationUtil.swingInvokeLater(getProject(), setStateRunnable);
}
});
}
}
}
protected DebuggerSession(String sessionName, final DebugProcessImpl debugProcess) {
mySessionName = sessionName;
myDebugProcess = debugProcess;
SESSION_EMPTY_CONTEXT = DebuggerContextImpl.createDebuggerContext(this, null, null, null);
myContextManager = new MyDebuggerStateManager();
myState = new DebuggerSessionState(STATE_STOPPED, null);
myDebugProcess.addDebugProcessListener(new MyDebugProcessListener(debugProcess));
myDebugProcess.addEvaluationListener(new MyEvaluationListener());
ValueLookupManager.getInstance(getProject()).startListening();
}
@NotNull
public DebuggerStateManager getContextManager() {
return myContextManager;
}
public Project getProject() {
return getProcess().getProject();
}
public String getSessionName() {
return mySessionName;
}
public DebugProcessImpl getProcess() {
return myDebugProcess;
}
private static class DebuggerSessionState {
final int myState;
final String myDescription;
public DebuggerSessionState(int state, String description) {
myState = state;
myDescription = description;
}
}
public int getState() {
return myState.myState;
}
public String getStateDescription() {
if (myState.myDescription != null) {
return myState.myDescription;
}
switch (myState.myState) {
case STATE_STOPPED:
return DebuggerBundle.message("status.debug.stopped");
case STATE_RUNNING:
return DebuggerBundle.message("status.app.running");
case STATE_WAITING_ATTACH:
RemoteConnection connection = getProcess().getConnection();
final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection);
final String transportName = DebuggerBundle.getTransportName(connection);
return connection.isServerMode() ? DebuggerBundle.message("status.listening", addressDisplayName, transportName) : DebuggerBundle.message("status.connecting", addressDisplayName, transportName);
case STATE_PAUSED:
return DebuggerBundle.message("status.paused");
case STATE_WAIT_EVALUATION:
return DebuggerBundle.message("status.waiting.evaluation.result");
case STATE_DISPOSED:
return DebuggerBundle.message("status.debug.stopped");
}
return null;
}
/* Stepping */
private void resumeAction(final DebugProcessImpl.ResumeCommand command, int event) {
getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_WAIT_EVALUATION, event, null);
myDebugProcess.getManagerThread().schedule(command);
}
public void stepOut() {
final SuspendContextImpl suspendContext = getSuspendContext();
final DebugProcessImpl.ResumeCommand cmd = myDebugProcess.createStepOutCommand(suspendContext);
mySteppingThroughThreads.add(cmd.getContextThread());
resumeAction(cmd, EVENT_STEP);
}
public void stepOver(boolean ignoreBreakpoints) {
final SuspendContextImpl suspendContext = getSuspendContext();
final DebugProcessImpl.ResumeCommand cmd = myDebugProcess.createStepOverCommand(suspendContext, ignoreBreakpoints);
mySteppingThroughThreads.add(cmd.getContextThread());
resumeAction(cmd, EVENT_STEP);
}
public void stepInto(final boolean ignoreFilters, final @Nullable MethodFilter smartStepFilter) {
final SuspendContextImpl suspendContext = getSuspendContext();
final DebugProcessImpl.ResumeCommand cmd = myDebugProcess.createStepIntoCommand(suspendContext, ignoreFilters, smartStepFilter);
mySteppingThroughThreads.add(cmd.getContextThread());
resumeAction(cmd, EVENT_STEP);
}
public void runToCursor(Document document, int line, final boolean ignoreBreakpoints) {
try {
DebugProcessImpl.ResumeCommand runToCursorCommand = myDebugProcess.createRunToCursorCommand(getSuspendContext(), document, line, ignoreBreakpoints);
mySteppingThroughThreads.add(runToCursorCommand.getContextThread());
resumeAction(runToCursorCommand, EVENT_STEP);
}
catch (EvaluateException e) {
Messages.showErrorDialog(e.getMessage(), ActionsBundle.actionText(XDebuggerActions.RUN_TO_CURSOR));
}
}
public void resume() {
final SuspendContextImpl suspendContext = getSuspendContext();
if(suspendContext != null) {
if (suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_ALL) {
mySteppingThroughThreads.clear();
}
else {
mySteppingThroughThreads.remove(suspendContext.getThread());
}
resetIgnoreStepFiltersFlag();
resumeAction(myDebugProcess.createResumeCommand(suspendContext), EVENT_RESUME);
}
}
private void resetIgnoreStepFiltersFlag() {
myIgnoreFiltersFrameCountThreshold = 0;
}
public void setIgnoreStepFiltersFlag(int currentStackFrameCount) {
myIgnoreFiltersFrameCountThreshold = currentStackFrameCount;
}
public boolean shouldIgnoreSteppingFilters() {
return myIgnoreFiltersFrameCountThreshold > 0;
}
public void pause() {
myDebugProcess.getManagerThread().schedule(myDebugProcess.createPauseCommand());
}
/*Presentation*/
public void showExecutionPoint() {
getContextManager().setState(DebuggerContextUtil.createDebuggerContext(this, getSuspendContext()), STATE_PAUSED, EVENT_REFRESH, null);
}
public void refresh(final boolean refreshViewsOnly) {
final int state = getState();
DebuggerContextImpl context = myContextManager.getContext();
DebuggerContextImpl newContext = DebuggerContextImpl.createDebuggerContext(this, context.getSuspendContext(), context.getThreadProxy(), context.getFrameProxy());
myContextManager.setState(newContext, state, refreshViewsOnly? EVENT_REFRESH_VIEWS_ONLY : EVENT_REFRESH, null);
}
public void dispose() {
getProcess().dispose();
Disposer.dispose(myUpdateAlarm);
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
public void run() {
getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_DISPOSED, EVENT_DISPOSE, null);
}
});
}
// ManagerCommands
@Override
public boolean isStopped() {
return getState() == STATE_STOPPED;
}
public boolean isAttached() {
return !isStopped() && getState() != STATE_WAITING_ATTACH;
}
@Override
public boolean isPaused() {
return getState() == STATE_PAUSED;
}
public boolean isConnecting() {
return getState() == STATE_WAITING_ATTACH;
}
public boolean isEvaluating() {
return myIsEvaluating;
}
public boolean isRunning() {
return getState() == STATE_RUNNING && !getProcess().getProcessHandler().isProcessTerminated();
}
private SuspendContextImpl getSuspendContext() {
ApplicationManager.getApplication().assertIsDispatchThread();
return getContextManager().getContext().getSuspendContext();
}
@Nullable
protected ExecutionResult attach(DebugEnvironment environment) throws ExecutionException {
RemoteConnection remoteConnection = environment.getRemoteConnection();
final String addressDisplayName = DebuggerBundle.getAddressDisplayName(remoteConnection);
final String transportName = DebuggerBundle.getTransportName(remoteConnection);
mySearchScope = environment.getSearchScope();
final ExecutionResult executionResult = myDebugProcess.attachVirtualMachine(environment, this);
getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_WAITING_ATTACH, EVENT_START_WAIT_ATTACH, DebuggerBundle.message("status.waiting.attach", addressDisplayName, transportName));
return executionResult;
}
private class MyDebugProcessListener extends DebugProcessAdapterImpl {
private final DebugProcessImpl myDebugProcess;
public MyDebugProcessListener(final DebugProcessImpl debugProcess) {
myDebugProcess = debugProcess;
}
//executed in manager thread
@Override
public void connectorIsReady() {
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
public void run() {
RemoteConnection connection = myDebugProcess.getConnection();
final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection);
final String transportName = DebuggerBundle.getTransportName(connection);
final String connectionStatusMessage = connection.isServerMode() ? DebuggerBundle.message("status.listening", addressDisplayName, transportName) : DebuggerBundle.message("status.connecting", addressDisplayName, transportName);
getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_WAITING_ATTACH, EVENT_START_WAIT_ATTACH, connectionStatusMessage);
}
});
}
@Override
public void paused(final SuspendContextImpl suspendContext) {
if (LOG.isDebugEnabled()) {
LOG.debug("paused");
}
if (!shouldSetAsActiveContext(suspendContext)) {
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
public void run() {
getContextManager().fireStateChanged(getContextManager().getContext(), EVENT_THREADS_REFRESH);
}
});
return;
}
ThreadReferenceProxyImpl currentThread = suspendContext.getThread();
final StackFrameContext positionContext;
if (currentThread == null) {
//Pause pressed
LOG.assertTrue(suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_ALL);
SuspendContextImpl oldContext = getProcess().getSuspendManager().getPausedContext();
if (oldContext != null) {
currentThread = oldContext.getThread();
}
if(currentThread == null) {
final Collection<ThreadReferenceProxyImpl> allThreads = getProcess().getVirtualMachineProxy().allThreads();
// heuristics: try to pre-select EventDispatchThread
for (final ThreadReferenceProxyImpl thread : allThreads) {
if (ThreadState.isEDT(thread.name())) {
currentThread = thread;
break;
}
}
if (currentThread == null) {
// heuristics: display the first thread with RUNNABLE status
for (final ThreadReferenceProxyImpl thread : allThreads) {
currentThread = thread;
if (currentThread.status() == ThreadReference.THREAD_STATUS_RUNNING) {
break;
}
}
}
}
StackFrameProxyImpl proxy = null;
if (currentThread != null) {
try {
while (!currentThread.isSuspended()) {
// wait until thread is considered suspended. Querying data from a thread immediately after VM.suspend()
// may result in IncompatibleThreadStateException, most likely some time after suspend() VM erroneously thinks that thread is still running
try {
Thread.sleep(10);
}
catch (InterruptedException ignored) {}
}
proxy = (currentThread.frameCount() > 0) ? currentThread.frame(0) : null;
}
catch (ObjectCollectedException ignored) {
proxy = null;
}
catch (EvaluateException e) {
proxy = null;
LOG.error(e);
}
}
positionContext = new SimpleStackFrameContext(proxy, myDebugProcess);
}
else {
positionContext = suspendContext;
}
if (currentThread != null) {
try {
final int frameCount = currentThread.frameCount();
if (frameCount == 0 || (frameCount <= myIgnoreFiltersFrameCountThreshold)) {
resetIgnoreStepFiltersFlag();
}
}
catch (EvaluateException e) {
LOG.info(e);
resetIgnoreStepFiltersFlag();
}
}
SourcePosition position = PsiDocumentManager.getInstance(getProject()).commitAndRunReadAction(new Computable<SourcePosition>() {
@Override
public @Nullable SourcePosition compute() {
return ContextUtil.getSourcePosition(positionContext);
}
});
if (position != null) {
final List<Pair<Breakpoint, Event>> eventDescriptors = DebuggerUtilsEx.getEventDescriptors(suspendContext);
final RequestManagerImpl requestsManager = suspendContext.getDebugProcess().getRequestsManager();
final PsiFile foundFile = position.getFile();
final boolean sourceMissing = foundFile instanceof PsiCompiledElement;
for (Pair<Breakpoint, Event> eventDescriptor : eventDescriptors) {
Breakpoint breakpoint = eventDescriptor.getFirst();
if (breakpoint instanceof LineBreakpoint) {
final SourcePosition breakpointPosition = ((BreakpointWithHighlighter)breakpoint).getSourcePosition();
if (breakpointPosition == null || (!sourceMissing && breakpointPosition.getLine() != position.getLine())) {
requestsManager.deleteRequest(breakpoint);
requestsManager.setInvalid(breakpoint, DebuggerBundle.message("error.invalid.breakpoint.source.changed"));
breakpoint.updateUI();
}
else if (sourceMissing) {
// adjust position to be position of the breakpoint in order to show the real originator of the event
position = breakpointPosition;
final StackFrameProxy frameProxy = positionContext.getFrameProxy();
String className;
try {
className = frameProxy != null? frameProxy.location().declaringType().name() : "";
}
catch (EvaluateException ignored) {
className = "";
}
requestsManager.setInvalid(breakpoint, DebuggerBundle.message("error.invalid.breakpoint.source.not.found", className));
breakpoint.updateUI();
}
}
}
}
final DebuggerContextImpl debuggerContext = DebuggerContextImpl.createDebuggerContext(DebuggerSession.this, suspendContext, currentThread, null);
debuggerContext.setPositionCache(position);
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
public void run() {
getContextManager().setState(debuggerContext, STATE_PAUSED, EVENT_PAUSE, null);
}
});
}
private boolean shouldSetAsActiveContext(final SuspendContextImpl suspendContext) {
final ThreadReferenceProxyImpl newThread = suspendContext.getThread();
if (newThread == null || suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_ALL || isSteppingThrough(newThread)) {
return true;
}
final SuspendContextImpl currentSuspendContext = getContextManager().getContext().getSuspendContext();
if (currentSuspendContext == null) {
return true;
}
if (enableBreakpointsDuringEvaluation()) {
final ThreadReferenceProxyImpl currentThread = currentSuspendContext.getThread();
return currentThread == null || Comparing.equal(currentThread.getThreadReference(), newThread.getThreadReference());
}
return false;
}
@Override
public void resumed(final SuspendContextImpl suspendContext) {
final SuspendContextImpl currentContext = getProcess().getSuspendManager().getPausedContext();
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
public void run() {
if (currentContext != null) {
getContextManager().setState(DebuggerContextUtil.createDebuggerContext(DebuggerSession.this, currentContext), STATE_PAUSED, EVENT_CONTEXT, null);
}
else {
getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_RUNNING, EVENT_CONTEXT, null);
}
}
});
}
@Override
public void processAttached(final DebugProcessImpl process) {
final RemoteConnection connection = getProcess().getConnection();
final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection);
final String transportName = DebuggerBundle.getTransportName(connection);
final String message = DebuggerBundle.message("status.connected", addressDisplayName, transportName);
process.printToConsole(message + "\n");
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
public void run() {
getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_RUNNING, EVENT_ATTACHED, message);
}
});
}
@Override
public void attachException(final RunProfileState state, final ExecutionException exception, final RemoteConnection remoteConnection) {
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
public void run() {
String message = "";
if (state instanceof RemoteState) {
message = DebuggerBundle.message("status.connect.failed", DebuggerBundle.getAddressDisplayName(remoteConnection), DebuggerBundle.getTransportName(remoteConnection));
}
message += exception.getMessage();
getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_STOPPED, EVENT_DETACHED, message);
}
});
}
@Override
public void processDetached(final DebugProcessImpl debugProcess, boolean closedByUser) {
if (!closedByUser) {
ProcessHandler processHandler = debugProcess.getProcessHandler();
if(processHandler != null) {
final RemoteConnection connection = getProcess().getConnection();
final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection);
final String transportName = DebuggerBundle.getTransportName(connection);
processHandler.notifyTextAvailable(DebuggerBundle.message("status.disconnected", addressDisplayName, transportName) + "\n", ProcessOutputTypes.SYSTEM);
}
}
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
public void run() {
final RemoteConnection connection = getProcess().getConnection();
final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection);
final String transportName = DebuggerBundle.getTransportName(connection);
getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_STOPPED, EVENT_DETACHED, DebuggerBundle.message("status.disconnected", addressDisplayName, transportName));
}
});
mySteppingThroughThreads.clear();
}
@Override
public void threadStarted(DebugProcess proc, ThreadReference thread) {
notifyThreadsRefresh();
}
@Override
public void threadStopped(DebugProcess proc, ThreadReference thread) {
notifyThreadsRefresh();
}
private void notifyThreadsRefresh() {
if (!myUpdateAlarm.isDisposed()) {
myUpdateAlarm.cancelAllRequests();
myUpdateAlarm.addRequest(new Runnable() {
@Override
public void run() {
final DebuggerStateManager contextManager = getContextManager();
contextManager.fireStateChanged(contextManager.getContext(), EVENT_THREADS_REFRESH);
}
}, 100, ModalityState.NON_MODAL);
}
}
}
private class MyEvaluationListener implements EvaluationListener {
@Override
public void evaluationStarted(SuspendContextImpl context) {
myIsEvaluating = true;
}
@Override
public void evaluationFinished(final SuspendContextImpl context) {
myIsEvaluating = false;
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
public void run() {
if (context != getSuspendContext()) {
getContextManager().setState(DebuggerContextUtil.createDebuggerContext(DebuggerSession.this, context), STATE_PAUSED, EVENT_REFRESH, null);
}
}
});
}
}
public static boolean enableBreakpointsDuringEvaluation() {
return Registry.is("debugger.enable.breakpoints.during.evaluation");
}
@Nullable
public XDebugSession getXDebugSession() {
for (XDebugSession xDebugSession : XDebuggerManager.getInstance(getProject()).getDebugSessions()) {
XDebugProcess process = xDebugSession.getDebugProcess();
if (process instanceof JavaDebugProcess && ((JavaDebugProcess)process).getDebuggerSession() == this) {
return xDebugSession;
}
}
return null;
}
}