2 * Copyright 2000-2016 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.xdebugger.impl;
18 import com.intellij.execution.ExecutionManager;
19 import com.intellij.execution.configurations.RunConfiguration;
20 import com.intellij.execution.configurations.RunProfile;
21 import com.intellij.execution.executors.DefaultDebugExecutor;
22 import com.intellij.execution.filters.HyperlinkInfo;
23 import com.intellij.execution.filters.OpenFileHyperlinkInfo;
24 import com.intellij.execution.process.ProcessAdapter;
25 import com.intellij.execution.process.ProcessEvent;
26 import com.intellij.execution.process.ProcessHandler;
27 import com.intellij.execution.runners.ExecutionEnvironment;
28 import com.intellij.execution.ui.ConsoleView;
29 import com.intellij.execution.ui.ConsoleViewContentType;
30 import com.intellij.execution.ui.RunContentDescriptor;
31 import com.intellij.execution.ui.RunnerLayoutUi;
32 import com.intellij.ide.DataManager;
33 import com.intellij.notification.NotificationGroup;
34 import com.intellij.notification.NotificationListener;
35 import com.intellij.openapi.Disposable;
36 import com.intellij.openapi.actionSystem.AnAction;
37 import com.intellij.openapi.application.ApplicationManager;
38 import com.intellij.openapi.application.ReadAction;
39 import com.intellij.openapi.application.Result;
40 import com.intellij.openapi.diagnostic.Logger;
41 import com.intellij.openapi.editor.markup.GutterIconRenderer;
42 import com.intellij.openapi.project.Project;
43 import com.intellij.openapi.ui.MessageType;
44 import com.intellij.openapi.util.Comparing;
45 import com.intellij.openapi.util.Computable;
46 import com.intellij.openapi.util.Disposer;
47 import com.intellij.openapi.wm.ToolWindowId;
48 import com.intellij.ui.AppUIUtil;
49 import com.intellij.util.EventDispatcher;
50 import com.intellij.util.SmartList;
51 import com.intellij.util.containers.SmartHashSet;
52 import com.intellij.util.ui.UIUtil;
53 import com.intellij.xdebugger.*;
54 import com.intellij.xdebugger.breakpoints.*;
55 import com.intellij.xdebugger.frame.XExecutionStack;
56 import com.intellij.xdebugger.frame.XStackFrame;
57 import com.intellij.xdebugger.frame.XSuspendContext;
58 import com.intellij.xdebugger.frame.XValueMarkerProvider;
59 import com.intellij.xdebugger.impl.breakpoints.*;
60 import com.intellij.xdebugger.impl.evaluate.XDebuggerEditorLinePainter;
61 import com.intellij.xdebugger.impl.evaluate.quick.common.ValueLookupManager;
62 import com.intellij.xdebugger.impl.frame.XValueMarkers;
63 import com.intellij.xdebugger.impl.frame.XWatchesViewImpl;
64 import com.intellij.xdebugger.impl.settings.XDebuggerSettingManagerImpl;
65 import com.intellij.xdebugger.impl.ui.XDebugSessionData;
66 import com.intellij.xdebugger.impl.ui.XDebugSessionTab;
67 import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants;
68 import com.intellij.xdebugger.stepping.XSmartStepIntoHandler;
69 import com.intellij.xdebugger.stepping.XSmartStepIntoVariant;
70 import gnu.trove.THashMap;
71 import gnu.trove.THashSet;
72 import org.jetbrains.annotations.NotNull;
73 import org.jetbrains.annotations.Nullable;
76 import javax.swing.event.HyperlinkEvent;
77 import javax.swing.event.HyperlinkListener;
79 import java.util.concurrent.atomic.AtomicBoolean;
84 public class XDebugSessionImpl implements XDebugSession {
85 private static final Logger LOG = Logger.getInstance("#com.intellij.xdebugger.impl.XDebugSessionImpl");
86 public static final NotificationGroup NOTIFICATION_GROUP = NotificationGroup.toolWindowGroup("Debugger messages", ToolWindowId.DEBUG,
88 private XDebugProcess myDebugProcess;
89 private final Map<XBreakpoint<?>, CustomizedBreakpointPresentation> myRegisteredBreakpoints =
91 private final Set<XBreakpoint<?>> myInactiveSlaveBreakpoints = Collections.synchronizedSet(new SmartHashSet<>());
92 private boolean myBreakpointsDisabled;
93 private final XDebuggerManagerImpl myDebuggerManager;
94 private MyBreakpointListener myBreakpointListener;
95 private XSuspendContext mySuspendContext;
96 private XExecutionStack myCurrentExecutionStack;
97 private XStackFrame myCurrentStackFrame;
98 private boolean myIsTopFrame;
99 private volatile XSourcePosition myTopFramePosition;
100 private final AtomicBoolean myPaused = new AtomicBoolean();
101 private MyDependentBreakpointListener myDependentBreakpointListener;
102 private XValueMarkers<?, ?> myValueMarkers;
103 private final String mySessionName;
104 private @Nullable XDebugSessionTab mySessionTab;
105 private final XDebugSessionData mySessionData;
106 private XBreakpoint<?> myActiveNonLineBreakpoint;
107 private final EventDispatcher<XDebugSessionListener> myDispatcher = EventDispatcher.create(XDebugSessionListener.class);
108 private final Project myProject;
109 private final @Nullable ExecutionEnvironment myEnvironment;
110 private final AtomicBoolean myStopped = new AtomicBoolean();
111 private boolean myPauseActionSupported;
112 private final AtomicBoolean myShowTabOnSuspend;
113 private final List<AnAction> myRestartActions = new SmartList<>();
114 private final List<AnAction> myExtraStopActions = new SmartList<>();
115 private final List<AnAction> myExtraActions = new SmartList<>();
116 private ConsoleView myConsoleView;
117 private final Icon myIcon;
119 private volatile boolean breakpointsInitialized;
121 public XDebugSessionImpl(@NotNull ExecutionEnvironment environment, @NotNull XDebuggerManagerImpl debuggerManager) {
122 this(environment, debuggerManager, environment.getRunProfile().getName(), environment.getRunProfile().getIcon(), false, null);
125 public XDebugSessionImpl(@Nullable ExecutionEnvironment environment,
126 @NotNull XDebuggerManagerImpl debuggerManager,
127 @NotNull String sessionName,
129 boolean showTabOnSuspend,
130 @Nullable RunContentDescriptor contentToReuse) {
131 myEnvironment = environment;
132 mySessionName = sessionName;
133 myDebuggerManager = debuggerManager;
134 myShowTabOnSuspend = new AtomicBoolean(showTabOnSuspend);
135 myProject = debuggerManager.getProject();
136 ValueLookupManager.getInstance(myProject).startListening();
139 XDebugSessionData oldSessionData = null;
140 if (contentToReuse == null) {
141 contentToReuse = environment != null ? environment.getContentToReuse() : null;
143 if (contentToReuse != null) {
144 JComponent component = contentToReuse.getComponent();
145 if (component != null) {
146 oldSessionData = XDebugSessionData.DATA_KEY.getData(DataManager.getInstance().getDataContext(component));
150 String currentConfigurationName = getConfigurationName();
151 if (oldSessionData == null || !oldSessionData.getConfigurationName().equals(currentConfigurationName)) {
152 oldSessionData = new XDebugSessionData(getWatchExpressions(), currentConfigurationName);
154 mySessionData = oldSessionData;
159 public String getSessionName() {
160 return mySessionName;
165 public RunContentDescriptor getRunContentDescriptor() {
166 assertSessionTabInitialized();
167 //noinspection ConstantConditions
168 return mySessionTab.getRunContentDescriptor();
171 private void assertSessionTabInitialized() {
172 if (myShowTabOnSuspend.get()) {
173 LOG.error("Debug tool window isn't shown yet because debug process isn't suspended");
176 LOG.assertTrue(mySessionTab != null, "Debug tool window not initialized yet!");
181 public void setPauseActionSupported(final boolean isSupported) {
182 myPauseActionSupported = isSupported;
186 public List<AnAction> getRestartActions() {
187 return myRestartActions;
190 public void addRestartActions(AnAction... restartActions) {
191 if (restartActions != null) {
192 Collections.addAll(myRestartActions, restartActions);
197 public List<AnAction> getExtraActions() {
198 return myExtraActions;
201 public void addExtraActions(AnAction... extraActions) {
202 if (extraActions != null) {
203 Collections.addAll(myExtraActions, extraActions);
207 public List<AnAction> getExtraStopActions() {
208 return myExtraStopActions;
211 public void addExtraStopActions(AnAction... extraStopActions) {
212 if (extraStopActions != null) {
213 Collections.addAll(myExtraStopActions, extraStopActions);
218 public void rebuildViews() {
219 if (!myShowTabOnSuspend.get() && mySessionTab != null) {
220 mySessionTab.rebuildViews();
226 public RunProfile getRunProfile() {
227 return myEnvironment != null ? myEnvironment.getRunProfile() : null;
230 public boolean isPauseActionSupported() {
231 return myPauseActionSupported;
236 public Project getProject() {
237 return myDebuggerManager.getProject();
242 public XDebugProcess getDebugProcess() {
243 return myDebugProcess;
247 public boolean isSuspended() {
248 return myPaused.get() && mySuspendContext != null;
252 public boolean isPaused() {
253 return myPaused.get();
258 public XStackFrame getCurrentStackFrame() {
259 return myCurrentStackFrame;
263 public XSuspendContext getSuspendContext() {
264 return mySuspendContext;
269 public XSourcePosition getCurrentPosition() {
270 return myCurrentStackFrame != null ? myCurrentStackFrame.getSourcePosition() : null;
275 public XSourcePosition getTopFramePosition() {
276 return myTopFramePosition;
279 XDebugSessionTab init(@NotNull XDebugProcess process, @Nullable RunContentDescriptor contentToReuse) {
280 LOG.assertTrue(myDebugProcess == null);
281 myDebugProcess = process;
283 if (myDebugProcess.checkCanInitBreakpoints()) {
287 myDebugProcess.getProcessHandler().addProcessListener(new ProcessAdapter() {
289 public void processTerminated(final ProcessEvent event) {
291 myDebugProcess.getProcessHandler().removeProcessListener(this);
294 //todo[nik] make 'createConsole()' method return ConsoleView
295 myConsoleView = (ConsoleView)myDebugProcess.createConsole();
296 if (!myShowTabOnSuspend.get()) {
297 initSessionTab(contentToReuse);
303 public void reset() {
304 breakpointsInitialized = false;
308 public void initBreakpoints() {
309 ApplicationManager.getApplication().assertReadAccessAllowed();
310 LOG.assertTrue(!breakpointsInitialized);
311 breakpointsInitialized = true;
313 XBreakpointManagerImpl breakpointManager = myDebuggerManager.getBreakpointManager();
314 XDependentBreakpointManager dependentBreakpointManager = breakpointManager.getDependentBreakpointManager();
315 disableSlaveBreakpoints(dependentBreakpointManager);
316 processAllBreakpoints(true, false);
318 if (myBreakpointListener == null) {
319 myBreakpointListener = new MyBreakpointListener();
320 breakpointManager.addBreakpointListener(myBreakpointListener);
322 if (myDependentBreakpointListener == null) {
323 myDependentBreakpointListener = new MyDependentBreakpointListener();
324 dependentBreakpointManager.addListener(myDependentBreakpointListener);
329 public ConsoleView getConsoleView() {
330 return myConsoleView;
334 public XDebugSessionTab getSessionTab() {
339 public RunnerLayoutUi getUI() {
340 assertSessionTabInitialized();
341 assert mySessionTab != null;
342 return mySessionTab.getUi();
345 private void initSessionTab(@Nullable RunContentDescriptor contentToReuse) {
346 mySessionTab = XDebugSessionTab.create(this, myIcon, myEnvironment, contentToReuse);
347 myDebugProcess.sessionInitialized();
350 public XDebugSessionData getSessionData() {
351 return mySessionData;
354 private void disableSlaveBreakpoints(final XDependentBreakpointManager dependentBreakpointManager) {
355 Set<XBreakpoint<?>> slaveBreakpoints = dependentBreakpointManager.getAllSlaveBreakpoints();
356 if (slaveBreakpoints.isEmpty()) {
360 Set<XBreakpointType<?, ?>> breakpointTypes = new THashSet<>();
361 for (XBreakpointHandler<?> handler : myDebugProcess.getBreakpointHandlers()) {
362 breakpointTypes.add(getBreakpointTypeClass(handler));
364 for (XBreakpoint<?> slaveBreakpoint : slaveBreakpoints) {
365 if (breakpointTypes.contains(slaveBreakpoint.getType())) {
366 myInactiveSlaveBreakpoints.add(slaveBreakpoint);
371 public void showSessionTab() {
372 RunContentDescriptor descriptor = getRunContentDescriptor();
373 ExecutionManager.getInstance(getProject()).getContentManager()
374 .showRunContent(DefaultDebugExecutor.getDebugExecutorInstance(), descriptor);
378 public XValueMarkers<?, ?> getValueMarkers() {
379 if (myValueMarkers == null) {
380 XValueMarkerProvider<?, ?> provider = myDebugProcess.createValueMarkerProvider();
381 if (provider != null) {
382 myValueMarkers = XValueMarkers.createValueMarkers(provider);
385 return myValueMarkers;
388 @SuppressWarnings("unchecked") //need to compile under 1.8, please do not remove before checking
389 private static XBreakpointType getBreakpointTypeClass(final XBreakpointHandler handler) {
390 return XDebuggerUtil.getInstance().findBreakpointType(handler.getBreakpointTypeClass());
393 private <B extends XBreakpoint<?>> void processBreakpoints(final XBreakpointHandler<B> handler,
395 final boolean temporary) {
396 Collection<? extends B> breakpoints = myDebuggerManager.getBreakpointManager().getBreakpoints(handler.getBreakpointTypeClass());
397 for (B b : breakpoints) {
398 handleBreakpoint(handler, b, register, temporary);
402 private <B extends XBreakpoint<?>> void handleBreakpoint(final XBreakpointHandler<B> handler, final B b, final boolean register,
403 final boolean temporary) {
405 boolean active = ApplicationManager.getApplication().runReadAction((Computable<Boolean>)() -> isBreakpointActive(b));
407 synchronized (myRegisteredBreakpoints) {
408 myRegisteredBreakpoints.put(b, new CustomizedBreakpointPresentation());
410 handler.registerBreakpoint(b);
415 synchronized (myRegisteredBreakpoints) {
416 removed = myRegisteredBreakpoints.remove(b) != null;
419 handler.unregisterBreakpoint(b, temporary);
425 public CustomizedBreakpointPresentation getBreakpointPresentation(@NotNull XBreakpoint<?> breakpoint) {
426 synchronized (myRegisteredBreakpoints) {
427 return myRegisteredBreakpoints.get(breakpoint);
431 private void processAllHandlers(final XBreakpoint<?> breakpoint, final boolean register) {
432 for (XBreakpointHandler<?> handler : myDebugProcess.getBreakpointHandlers()) {
433 processBreakpoint(breakpoint, handler, register);
437 private <B extends XBreakpoint<?>> void processBreakpoint(final XBreakpoint<?> breakpoint,
438 final XBreakpointHandler<B> handler,
440 XBreakpointType<?, ?> type = breakpoint.getType();
441 if (handler.getBreakpointTypeClass().equals(type.getClass())) {
442 //noinspection unchecked
444 handleBreakpoint(handler, b, register, false);
448 public boolean isBreakpointActive(@NotNull XBreakpoint<?> b) {
449 ApplicationManager.getApplication().assertReadAccessAllowed();
450 return !areBreakpointsMuted() && b.isEnabled() && !isInactiveSlaveBreakpoint(b) && !((XBreakpointBase)b).isDisposed();
454 public boolean areBreakpointsMuted() {
455 return mySessionData.isBreakpointsMuted();
459 public void addSessionListener(@NotNull XDebugSessionListener listener, @NotNull Disposable parentDisposable) {
460 myDispatcher.addListener(listener, parentDisposable);
464 public void addSessionListener(@NotNull final XDebugSessionListener listener) {
465 myDispatcher.addListener(listener);
469 public void removeSessionListener(@NotNull final XDebugSessionListener listener) {
470 myDispatcher.removeListener(listener);
474 public void setBreakpointMuted(boolean muted) {
475 ApplicationManager.getApplication().assertReadAccessAllowed();
476 if (areBreakpointsMuted() == muted) return;
477 mySessionData.setBreakpointsMuted(muted);
478 processAllBreakpoints(!muted, muted);
479 myDebuggerManager.getBreakpointManager().getLineBreakpointManager().queueAllBreakpointsUpdate();
483 public void stepOver(final boolean ignoreBreakpoints) {
484 if (!myDebugProcess.checkCanPerformCommands()) return;
486 if (ignoreBreakpoints) {
487 disableBreakpoints();
489 myDebugProcess.startStepOver(doResume());
493 public void stepInto() {
494 if (!myDebugProcess.checkCanPerformCommands()) return;
496 myDebugProcess.startStepInto(doResume());
500 public void stepOut() {
501 if (!myDebugProcess.checkCanPerformCommands()) return;
503 myDebugProcess.startStepOut(doResume());
507 public <V extends XSmartStepIntoVariant> void smartStepInto(XSmartStepIntoHandler<V> handler, V variant) {
508 if (!myDebugProcess.checkCanPerformCommands()) return;
511 handler.startStepInto(variant);
515 public void forceStepInto() {
516 if (!myDebugProcess.checkCanPerformCommands()) return;
518 myDebugProcess.startForceStepInto(doResume());
522 public void runToPosition(@NotNull final XSourcePosition position, final boolean ignoreBreakpoints) {
523 if (!myDebugProcess.checkCanPerformCommands()) return;
525 if (ignoreBreakpoints) {
526 disableBreakpoints();
528 myDebugProcess.runToPosition(position, doResume());
532 public void pause() {
533 if (!myDebugProcess.checkCanPerformCommands()) return;
535 myDebugProcess.startPausing();
538 private void processAllBreakpoints(final boolean register, final boolean temporary) {
539 for (XBreakpointHandler<?> handler : myDebugProcess.getBreakpointHandlers()) {
540 processBreakpoints(handler, register, temporary);
544 private void disableBreakpoints() {
545 myBreakpointsDisabled = true;
546 processAllBreakpoints(false, true);
550 public void resume() {
551 if (!myDebugProcess.checkCanPerformCommands()) return;
553 myDebugProcess.resume(doResume());
557 private XSuspendContext doResume() {
558 if (!myPaused.getAndSet(false)) {
562 myDispatcher.getMulticaster().beforeSessionResume();
563 XSuspendContext context = mySuspendContext;
564 mySuspendContext = null;
565 myCurrentExecutionStack = null;
566 myCurrentStackFrame = null;
567 myTopFramePosition = null;
568 myActiveNonLineBreakpoint = null;
569 updateExecutionPosition();
570 UIUtil.invokeLaterIfNeeded(() -> {
571 if (mySessionTab != null) {
572 mySessionTab.getUi().clearAttractionBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION);
575 myDispatcher.getMulticaster().sessionResumed();
580 public void updateExecutionPosition() {
581 // allowed only for the active session
582 if (myDebuggerManager.getCurrentSession() == this) {
583 boolean isTopFrame = isTopFrameSelected();
584 myDebuggerManager.updateExecutionPoint(getCurrentPosition(), !isTopFrame, getPositionIconRenderer(isTopFrame));
588 public boolean isTopFrameSelected() {
589 return myCurrentExecutionStack != null && myIsTopFrame;
594 public void showExecutionPoint() {
595 if (mySuspendContext != null) {
596 XExecutionStack executionStack = mySuspendContext.getActiveExecutionStack();
597 if (executionStack != null) {
598 XStackFrame topFrame = executionStack.getTopFrame();
599 if (topFrame != null) {
600 setCurrentStackFrame(executionStack, topFrame, true);
601 myDebuggerManager.showExecutionPosition();
608 public void setCurrentStackFrame(@NotNull XExecutionStack executionStack, @NotNull XStackFrame frame, boolean isTopFrame) {
609 if (mySuspendContext == null) return;
611 boolean frameChanged = myCurrentStackFrame != frame;
612 myCurrentExecutionStack = executionStack;
613 myCurrentStackFrame = frame;
614 myIsTopFrame = isTopFrame;
618 myDispatcher.getMulticaster().stackFrameChanged();
622 void activateSession() {
623 myDebuggerManager.setCurrentSession(this);
624 updateExecutionPosition();
627 public XBreakpoint<?> getActiveNonLineBreakpoint() {
628 if (myActiveNonLineBreakpoint != null) {
629 XSourcePosition breakpointPosition = myActiveNonLineBreakpoint.getSourcePosition();
630 XSourcePosition position = getTopFramePosition();
631 if (breakpointPosition == null ||
632 (position != null && !(breakpointPosition.getFile().equals(position.getFile()) && breakpointPosition.getLine() == position.getLine()))) {
633 return myActiveNonLineBreakpoint;
640 private GutterIconRenderer getPositionIconRenderer(boolean isTopFrame) {
644 XBreakpoint<?> activeNonLineBreakpoint = getActiveNonLineBreakpoint();
645 if (activeNonLineBreakpoint != null) {
646 return ((XBreakpointBase<?, ?, ?>)activeNonLineBreakpoint).createGutterIconRenderer();
648 if (myCurrentExecutionStack != null) {
649 return myCurrentExecutionStack.getExecutionLineIconRenderer();
655 public void updateBreakpointPresentation(@NotNull final XLineBreakpoint<?> breakpoint,
656 @Nullable final Icon icon,
657 @Nullable final String errorMessage) {
658 CustomizedBreakpointPresentation presentation;
659 synchronized (myRegisteredBreakpoints) {
660 presentation = myRegisteredBreakpoints.get(breakpoint);
661 if (presentation == null ||
662 (Comparing.equal(presentation.getIcon(), icon) && Comparing.strEqual(presentation.getErrorMessage(), errorMessage))) {
666 presentation.setErrorMessage(errorMessage);
667 presentation.setIcon(icon);
669 myDebuggerManager.getBreakpointManager().getLineBreakpointManager().queueBreakpointUpdate((XLineBreakpointImpl<?>)breakpoint);
673 public boolean breakpointReached(@NotNull final XBreakpoint<?> breakpoint, @NotNull final XSuspendContext suspendContext) {
674 return breakpointReached(breakpoint, null, suspendContext);
678 public boolean breakpointReached(@NotNull final XBreakpoint<?> breakpoint, @Nullable String evaluatedLogExpression,
679 @NotNull XSuspendContext suspendContext) {
680 return breakpointReached(breakpoint, evaluatedLogExpression, suspendContext, true);
683 public void breakpointReachedNoProcessing(@NotNull final XBreakpoint<?> breakpoint, @NotNull XSuspendContext suspendContext) {
684 breakpointReached(breakpoint, null, suspendContext, false);
687 private boolean breakpointReached(@NotNull final XBreakpoint<?> breakpoint, @Nullable String evaluatedLogExpression,
688 @NotNull XSuspendContext suspendContext, boolean doProcessing) {
690 if (breakpoint.isLogMessage()) {
691 XSourcePosition position = breakpoint.getSourcePosition();
692 OpenFileHyperlinkInfo hyperlinkInfo =
693 position != null ? new OpenFileHyperlinkInfo(myProject, position.getFile(), position.getLine()) : null;
694 printMessage(XDebuggerBundle.message("xbreakpoint.reached.text") + " ", XBreakpointUtil.getShortText(breakpoint), hyperlinkInfo);
697 if (evaluatedLogExpression != null) {
698 printMessage(evaluatedLogExpression, null, null);
701 processDependencies(breakpoint);
703 if (breakpoint.getSuspendPolicy() == SuspendPolicy.NONE) {
708 myActiveNonLineBreakpoint =
709 (!(breakpoint instanceof XLineBreakpoint) || ((XLineBreakpoint)breakpoint).getType().canBeHitInOtherPlaces()) ? breakpoint : null;
711 // set this session active on breakpoint, update execution position will be called inside positionReached
712 myDebuggerManager.setCurrentSession(this);
714 positionReachedInternal(suspendContext, true);
716 if (doProcessing && breakpoint instanceof XLineBreakpoint<?> && ((XLineBreakpoint)breakpoint).isTemporary()) {
717 handleTemporaryBreakpointHit(breakpoint);
722 private void handleTemporaryBreakpointHit(final XBreakpoint<?> breakpoint) {
723 addSessionListener(new XDebugSessionListener() {
724 private void removeBreakpoint() {
725 XDebuggerUtil.getInstance().removeBreakpoint(myProject, breakpoint);
726 removeSessionListener(this);
730 public void sessionResumed() {
735 public void sessionStopped() {
741 public void processDependencies(final XBreakpoint<?> breakpoint) {
742 XDependentBreakpointManager dependentBreakpointManager = myDebuggerManager.getBreakpointManager().getDependentBreakpointManager();
743 if (!dependentBreakpointManager.isMasterOrSlave(breakpoint)) return;
745 List<XBreakpoint<?>> breakpoints = dependentBreakpointManager.getSlaveBreakpoints(breakpoint);
746 myInactiveSlaveBreakpoints.removeAll(breakpoints);
747 for (XBreakpoint<?> slaveBreakpoint : breakpoints) {
748 processAllHandlers(slaveBreakpoint, true);
751 if (dependentBreakpointManager.getMasterBreakpoint(breakpoint) != null && !dependentBreakpointManager.isLeaveEnabled(breakpoint)) {
752 boolean added = myInactiveSlaveBreakpoints.add(breakpoint);
754 processAllHandlers(breakpoint, false);
755 myDebuggerManager.getBreakpointManager().getLineBreakpointManager().queueBreakpointUpdate(breakpoint);
760 private void printMessage(final String message, final String hyperLinkText, @Nullable final HyperlinkInfo info) {
761 AppUIUtil.invokeOnEdt(() -> {
762 myConsoleView.print(message, ConsoleViewContentType.SYSTEM_OUTPUT);
764 myConsoleView.printHyperlink(hyperLinkText, info);
766 else if (hyperLinkText != null) {
767 myConsoleView.print(hyperLinkText, ConsoleViewContentType.SYSTEM_OUTPUT);
769 myConsoleView.print("\n", ConsoleViewContentType.SYSTEM_OUTPUT);
773 public void unsetPaused() {
777 private void positionReachedInternal(@NotNull final XSuspendContext suspendContext, boolean attract) {
779 mySuspendContext = suspendContext;
780 myCurrentExecutionStack = suspendContext.getActiveExecutionStack();
781 myCurrentStackFrame = myCurrentExecutionStack != null ? myCurrentExecutionStack.getTopFrame() : null;
783 myTopFramePosition = myCurrentStackFrame != null ? myCurrentStackFrame.getSourcePosition() : null;
787 updateExecutionPosition();
789 final boolean showOnSuspend = myShowTabOnSuspend.compareAndSet(true, false);
790 if (showOnSuspend || attract) {
791 AppUIUtil.invokeLaterIfProjectAlive(myProject, () -> {
793 initSessionTab(null);
797 // user attractions should only be made if event happens independently (e.g. program paused/suspended)
798 // and should not be made when user steps in the code
800 if (mySessionTab == null) {
801 LOG.debug("Cannot request focus because Session Tab is not initialized yet");
805 if (XDebuggerSettingManagerImpl.getInstanceImpl().getGeneralSettings().isShowDebuggerOnBreakpoint()) {
806 mySessionTab.toFront(true, this::updateExecutionPosition);
809 if (myTopFramePosition == null) {
810 // if there is no source position available, we should somehow tell the user that session is stopped.
811 // the best way is to show the stack frames.
812 XDebugSessionTab.showFramesView(this);
815 mySessionTab.getUi().attractBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION);
820 myDispatcher.getMulticaster().sessionPaused();
824 public void positionReached(@NotNull final XSuspendContext suspendContext) {
825 positionReached(suspendContext, false);
828 public void positionReached(@NotNull XSuspendContext suspendContext, boolean attract) {
829 myActiveNonLineBreakpoint = null;
830 positionReachedInternal(suspendContext, attract);
834 public void sessionResumed() {
838 private void enableBreakpoints() {
839 if (myBreakpointsDisabled) {
840 myBreakpointsDisabled = false;
843 protected void run(@NotNull Result result) {
844 processAllBreakpoints(true, false);
851 public boolean isStopped() {
852 return myStopped.get();
855 private void stopImpl() {
856 if (!myStopped.compareAndSet(false, true)) {
861 if (breakpointsInitialized) {
862 XBreakpointManagerImpl breakpointManager = myDebuggerManager.getBreakpointManager();
863 if (myBreakpointListener != null) {
864 breakpointManager.removeBreakpointListener(myBreakpointListener);
866 if (myDependentBreakpointListener != null) {
867 breakpointManager.getDependentBreakpointManager().removeListener(myDependentBreakpointListener);
872 //noinspection unchecked
873 myDebugProcess.stopAsync().done(aVoid -> {
874 if (!myProject.isDisposed()) {
875 myProject.getMessageBus().syncPublisher(XDebuggerManager.TOPIC).processStopped(myDebugProcess);
878 if (mySessionTab != null) {
879 ((XWatchesViewImpl)mySessionTab.getWatchesView()).updateSessionData();
880 mySessionTab.detachFromSession();
882 else if (myConsoleView != null) {
883 AppUIUtil.invokeOnEdt(() -> Disposer.dispose(myConsoleView));
886 myTopFramePosition = null;
887 myCurrentExecutionStack = null;
888 myCurrentStackFrame = null;
889 mySuspendContext = null;
891 updateExecutionPosition();
893 if (myValueMarkers != null) {
894 myValueMarkers.clear();
896 if (XDebuggerSettingManagerImpl.getInstanceImpl().getGeneralSettings().isUnmuteOnStop()) {
897 mySessionData.setBreakpointsMuted(false);
899 myDebuggerManager.removeSession(this);
900 myDispatcher.getMulticaster().sessionStopped();
901 myProject.putUserData(XDebuggerEditorLinePainter.CACHE, null);
903 synchronized (myRegisteredBreakpoints) {
904 myRegisteredBreakpoints.clear();
910 public boolean isInactiveSlaveBreakpoint(final XBreakpoint<?> breakpoint) {
911 return myInactiveSlaveBreakpoints.contains(breakpoint);
916 ProcessHandler processHandler = myDebugProcess.getProcessHandler();
917 if (processHandler.isProcessTerminated() || processHandler.isProcessTerminating()) return;
919 if (processHandler.detachIsDefault()) {
920 processHandler.detachProcess();
923 processHandler.destroyProcess();
928 public void reportError(@NotNull final String message) {
929 reportMessage(message, MessageType.ERROR);
933 public void reportMessage(@NotNull final String message, @NotNull final MessageType type) {
934 reportMessage(message, type, null);
938 public void reportMessage(@NotNull final String message, @NotNull final MessageType type, @Nullable final HyperlinkListener listener) {
939 NotificationListener notificationListener = listener == null ? null : (notification, event) -> {
940 if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
941 listener.hyperlinkUpdate(event);
944 NOTIFICATION_GROUP.createNotification("", message, type.toNotificationType(), notificationListener).notify(myProject);
947 private class MyBreakpointListener implements XBreakpointListener<XBreakpoint<?>> {
949 public void breakpointAdded(@NotNull final XBreakpoint<?> breakpoint) {
950 if (!myBreakpointsDisabled) {
951 processAllHandlers(breakpoint, true);
956 public void breakpointRemoved(@NotNull final XBreakpoint<?> breakpoint) {
957 if (getActiveNonLineBreakpoint() == breakpoint) {
958 myActiveNonLineBreakpoint = null;
960 processAllHandlers(breakpoint, false);
964 public void breakpointChanged(@NotNull final XBreakpoint<?> breakpoint) {
965 breakpointRemoved(breakpoint);
966 breakpointAdded(breakpoint);
970 private class MyDependentBreakpointListener implements XDependentBreakpointListener {
972 public void dependencySet(final XBreakpoint<?> slave, final XBreakpoint<?> master) {
973 boolean added = myInactiveSlaveBreakpoints.add(slave);
975 processAllHandlers(slave, false);
980 public void dependencyCleared(final XBreakpoint<?> breakpoint) {
981 boolean removed = myInactiveSlaveBreakpoints.remove(breakpoint);
983 processAllHandlers(breakpoint, true);
989 private String getConfigurationName() {
990 if (myEnvironment != null) {
991 RunProfile profile = myEnvironment.getRunProfile();
992 if (profile instanceof RunConfiguration) {
993 return ((RunConfiguration)profile).getType().getId();
996 return getSessionName();
999 public void setWatchExpressions(@NotNull XExpression[] watchExpressions) {
1000 mySessionData.setWatchExpressions(watchExpressions);
1001 myDebuggerManager.getWatchesManager().setWatches(getConfigurationName(), watchExpressions);
1004 XExpression[] getWatchExpressions() {
1005 return myDebuggerManager.getWatchesManager().getWatches(getConfigurationName());
1009 public ExecutionEnvironment getExecutionEnvironment() {
1010 return myEnvironment;