js debugger: load source from cache and other fixes
[fedora-idea.git] / platform / xdebugger-impl / src / com / intellij / xdebugger / impl / XDebugSessionImpl.java
blob1df891c4430a2d4a8f4e990015a7e10b981dac26
1 /*
2 * Copyright 2000-2009 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.configurations.RunProfile;
19 import com.intellij.execution.filters.HyperlinkInfo;
20 import com.intellij.execution.filters.OpenFileHyperlinkInfo;
21 import com.intellij.execution.process.ProcessHandler;
22 import com.intellij.execution.runners.ExecutionEnvironment;
23 import com.intellij.execution.runners.ProgramRunner;
24 import com.intellij.execution.ui.ConsoleView;
25 import com.intellij.execution.ui.ConsoleViewContentType;
26 import com.intellij.execution.ui.RunContentDescriptor;
27 import com.intellij.openapi.application.ReadAction;
28 import com.intellij.openapi.application.Result;
29 import com.intellij.openapi.diagnostic.Logger;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.util.Disposer;
32 import com.intellij.openapi.util.text.StringUtil;
33 import com.intellij.util.EventDispatcher;
34 import com.intellij.xdebugger.*;
35 import com.intellij.xdebugger.stepping.XSmartStepIntoVariant;
36 import com.intellij.xdebugger.stepping.XSmartStepIntoHandler;
37 import com.intellij.xdebugger.breakpoints.*;
38 import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
39 import com.intellij.xdebugger.frame.XExecutionStack;
40 import com.intellij.xdebugger.frame.XStackFrame;
41 import com.intellij.xdebugger.frame.XSuspendContext;
42 import com.intellij.xdebugger.impl.breakpoints.*;
43 import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
44 import com.intellij.xdebugger.impl.ui.XDebugSessionData;
45 import com.intellij.xdebugger.impl.ui.XDebugSessionTab;
46 import org.jetbrains.annotations.NotNull;
47 import org.jetbrains.annotations.Nullable;
49 import javax.swing.*;
50 import java.util.*;
52 /**
53 * @author nik
55 public class XDebugSessionImpl implements XDebugSession {
56 private static final Logger LOG = Logger.getInstance("#com.intellij.xdebugger.impl.XDebugSessionImpl");
57 private XDebugProcess myDebugProcess;
58 private final Map<XBreakpoint<?>, CustomizedBreakpointPresentation> myRegisteredBreakpoints = new HashMap<XBreakpoint<?>, CustomizedBreakpointPresentation>();
59 private final Set<XBreakpoint<?>> myDisabledSlaveBreakpoints = new HashSet<XBreakpoint<?>>();
60 private boolean myBreakpointsMuted;
61 private boolean myBreakpointsDisabled;
62 private final XDebuggerManagerImpl myDebuggerManager;
63 private MyBreakpointListener myBreakpointListener;
64 private XSuspendContext mySuspendContext;
65 private XStackFrame myCurrentStackFrame;
66 private XSourcePosition myCurrentPosition;
67 private boolean myPaused;
68 private MyDependentBreakpointListener myDependentBreakpointListener;
69 private String mySessionName;
70 private XDebugSessionTab mySessionTab;
71 private final EventDispatcher<XDebugSessionListener> myDispatcher = EventDispatcher.create(XDebugSessionListener.class);
72 private Project myProject;
73 private @Nullable ExecutionEnvironment myEnvironment;
74 private ProgramRunner myRunner;
75 private boolean myStopped;
76 private boolean myPauseActionSupported;
78 public XDebugSessionImpl(final @NotNull ExecutionEnvironment env, final @NotNull ProgramRunner runner, XDebuggerManagerImpl debuggerManager) {
79 this(env, runner, debuggerManager, env.getRunProfile().getName());
82 public XDebugSessionImpl(final @Nullable ExecutionEnvironment env, final @Nullable ProgramRunner runner, XDebuggerManagerImpl debuggerManager,
83 final @NotNull String sessionName) {
84 myEnvironment = env;
85 myRunner = runner;
86 mySessionName = sessionName;
87 myDebuggerManager = debuggerManager;
88 myProject = debuggerManager.getProject();
91 @NotNull
92 public String getSessionName() {
93 return mySessionName;
96 @NotNull
97 public RunContentDescriptor getRunContentDescriptor() {
98 LOG.assertTrue(mySessionTab != null, "Call init() first!");
99 return mySessionTab.getRunContentDescriptor();
102 public void setPauseActionSupported(final boolean isSupported) {
103 myPauseActionSupported = isSupported;
106 public void rebuildViews() {
107 mySessionTab.rebuildViews();
110 @Nullable
111 public RunProfile getRunProfile() {
112 return myEnvironment != null ? myEnvironment.getRunProfile() : null;
115 public boolean isPauseActionSupported() {
116 return myPauseActionSupported;
119 @NotNull
120 public Project getProject() {
121 return myDebuggerManager.getProject();
124 @NotNull
125 public XDebugProcess getDebugProcess() {
126 return myDebugProcess;
129 public boolean isSuspended() {
130 return myPaused && mySuspendContext != null;
133 public boolean isPaused() {
134 return myPaused;
137 @Nullable
138 public XStackFrame getCurrentStackFrame() {
139 return myCurrentStackFrame;
142 public XSuspendContext getSuspendContext() {
143 return mySuspendContext;
146 @Nullable
147 public XSourcePosition getCurrentPosition() {
148 return myCurrentPosition;
151 public XDebugSessionTab init(final XDebugProcess process, @NotNull final XDebugSessionData sessionData) {
152 LOG.assertTrue(myDebugProcess == null);
153 myDebugProcess = process;
155 XBreakpointManagerImpl breakpointManager = myDebuggerManager.getBreakpointManager();
156 XDependentBreakpointManager dependentBreakpointManager = breakpointManager.getDependentBreakpointManager();
157 disableSlaveBreakpoints(dependentBreakpointManager);
158 processAllBreakpoints(true, false);
160 myBreakpointListener = new MyBreakpointListener();
161 breakpointManager.addBreakpointListener(myBreakpointListener);
162 myDependentBreakpointListener = new MyDependentBreakpointListener();
163 dependentBreakpointManager.addListener(myDependentBreakpointListener);
165 initSessionTab(sessionData);
166 process.sessionInitialized();
168 return mySessionTab;
171 public XDebugSessionTab getSessionTab() {
172 return mySessionTab;
175 private void initSessionTab(@NotNull XDebugSessionData sessionData) {
176 mySessionTab = new XDebugSessionTab(myProject, mySessionName);
177 if (myEnvironment != null) {
178 mySessionTab.setEnvironment(myEnvironment);
180 Disposer.register(myProject, mySessionTab);
181 mySessionTab.attachToSession(this, myRunner, myEnvironment, sessionData);
184 private void disableSlaveBreakpoints(final XDependentBreakpointManager dependentBreakpointManager) {
185 Set<XBreakpoint<?>> slaveBreakpoints = dependentBreakpointManager.getAllSlaveBreakpoints();
186 Set<XBreakpointType<?,?>> breakpointTypes = new HashSet<XBreakpointType<?,?>>();
187 for (XBreakpointHandler<?> handler : myDebugProcess.getBreakpointHandlers()) {
188 breakpointTypes.add(getBreakpointTypeClass(handler));
190 for (XBreakpoint<?> slaveBreakpoint : slaveBreakpoints) {
191 if (breakpointTypes.contains(slaveBreakpoint.getType())) {
192 myDisabledSlaveBreakpoints.add(slaveBreakpoint);
197 private static <B extends XBreakpoint<?>> XBreakpointType<?, ?> getBreakpointTypeClass(final XBreakpointHandler<B> handler) {
198 return XDebuggerUtil.getInstance().findBreakpointType(handler.getBreakpointTypeClass());
201 private <B extends XBreakpoint<?>> void processBreakpoints(final XBreakpointHandler<B> handler, boolean register, final boolean temporary) {
202 XBreakpointType<B,?> type = XDebuggerUtil.getInstance().findBreakpointType(handler.getBreakpointTypeClass());
203 Collection<? extends B> breakpoints = myDebuggerManager.getBreakpointManager().getBreakpoints(type);
204 for (B b : breakpoints) {
205 handleBreakpoint(handler, b, register, temporary);
209 private <B extends XBreakpoint<?>> void handleBreakpoint(final XBreakpointHandler<B> handler, final B b, final boolean register,
210 final boolean temporary) {
211 if (register && isBreakpointActive(b)) {
212 synchronized (myRegisteredBreakpoints) {
213 myRegisteredBreakpoints.put(b, new CustomizedBreakpointPresentation());
215 handler.registerBreakpoint(b);
217 if (!register) {
218 boolean removed = false;
219 synchronized (myRegisteredBreakpoints) {
220 if (myRegisteredBreakpoints.containsKey(b)) {
221 myRegisteredBreakpoints.remove(b);
222 removed = true;
225 if (removed) {
226 handler.unregisterBreakpoint(b, temporary);
231 @Nullable
232 public CustomizedBreakpointPresentation getBreakpointPresentation(@NotNull XLineBreakpoint<?> breakpoint) {
233 synchronized (myRegisteredBreakpoints) {
234 return myRegisteredBreakpoints.get(breakpoint);
238 private void processAllHandlers(final XBreakpoint<?> breakpoint, final boolean register) {
239 for (XBreakpointHandler<?> handler : myDebugProcess.getBreakpointHandlers()) {
240 processBreakpoint(breakpoint, handler, register);
244 private <B extends XBreakpoint<?>> void processBreakpoint(final XBreakpoint<?> breakpoint, final XBreakpointHandler<B> handler, boolean register) {
245 XBreakpointType<?, ?> type = breakpoint.getType();
246 if (handler.getBreakpointTypeClass().equals(type.getClass())) {
247 //noinspection unchecked
248 B b = (B)breakpoint;
249 handleBreakpoint(handler, b, register, false);
253 private boolean isBreakpointActive(final XBreakpoint<?> b) {
254 return !myBreakpointsMuted && b.isEnabled() && !myDisabledSlaveBreakpoints.contains(b);
257 public boolean areBreakpointsMuted() {
258 return myBreakpointsMuted;
261 public void addSessionListener(@NotNull final XDebugSessionListener listener) {
262 myDispatcher.addListener(listener);
265 public void removeSessionListener(@NotNull final XDebugSessionListener listener) {
266 myDispatcher.removeListener(listener);
269 public void setBreakpointMuted(boolean muted) {
270 if (myBreakpointsMuted == muted) return;
271 myBreakpointsMuted = muted;
272 processAllBreakpoints(!muted, muted);
273 myDebuggerManager.getBreakpointManager().getLineBreakpointManager().queueAllBreakpointsUpdate();
276 public void stepOver(final boolean ignoreBreakpoints) {
277 if (ignoreBreakpoints) {
278 disableBreakpoints();
280 doResume();
281 myDebugProcess.startStepOver();
284 public void stepInto() {
285 doResume();
286 myDebugProcess.startStepInto();
289 public void stepOut() {
290 doResume();
291 myDebugProcess.startStepOut();
294 public <V extends XSmartStepIntoVariant> void smartStepInto(XSmartStepIntoHandler<V> handler, V variant) {
295 doResume();
296 handler.startStepInto(variant);
299 public void forceStepInto() {
300 stepInto();
303 public void runToPosition(@NotNull final XSourcePosition position, final boolean ignoreBreakpoints) {
304 if (ignoreBreakpoints) {
305 disableBreakpoints();
307 doResume();
308 myDebugProcess.runToPosition(position);
311 public void pause() {
312 myDebugProcess.startPausing();
315 private void processAllBreakpoints(final boolean register, final boolean temporary) {
316 for (XBreakpointHandler<?> handler : myDebugProcess.getBreakpointHandlers()) {
317 processBreakpoints(handler, register, temporary);
321 private void disableBreakpoints() {
322 myBreakpointsDisabled = true;
323 processAllBreakpoints(false, true);
326 public void resume() {
327 doResume();
328 myDebugProcess.resume();
331 private void doResume() {
332 myDispatcher.getMulticaster().beforeSessionResume();
333 myDebuggerManager.updateExecutionPosition(this, null, false);
334 mySuspendContext = null;
335 myCurrentStackFrame = null;
336 myCurrentPosition = null;
337 myPaused = false;
338 myDispatcher.getMulticaster().sessionResumed();
341 public void showExecutionPoint() {
342 if (mySuspendContext != null) {
343 XExecutionStack executionStack = mySuspendContext.getActiveExecutionStack();
344 if (executionStack != null) {
345 XStackFrame topFrame = executionStack.getTopFrame();
346 if (topFrame != null) {
347 setCurrentStackFrame(topFrame);
348 myDebuggerManager.showExecutionPosition();
354 public void setCurrentStackFrame(@NotNull final XStackFrame frame) {
355 if (mySuspendContext == null) return;
357 boolean frameChanged = myCurrentStackFrame != frame;
358 myCurrentStackFrame = frame;
359 XSourcePosition position = frame.getSourcePosition();
360 if (position != null) {
361 XExecutionStack activeExecutionStack = mySuspendContext.getActiveExecutionStack();
362 boolean isTopFrame = activeExecutionStack != null && activeExecutionStack.getTopFrame() == frame;
363 myDebuggerManager.updateExecutionPosition(this, position, !isTopFrame);
366 if (frameChanged) {
367 myDispatcher.getMulticaster().stackFrameChanged();
371 public void updateBreakpointPresentation(@NotNull final XLineBreakpoint<?> breakpoint, @Nullable final Icon icon, @Nullable final String errorMessage) {
372 CustomizedBreakpointPresentation presentation;
373 synchronized (myRegisteredBreakpoints) {
374 presentation = myRegisteredBreakpoints.get(breakpoint);
375 if (presentation != null) {
376 presentation.setErrorMessage(errorMessage);
377 presentation.setIcon(icon);
380 if (presentation != null) {
381 myDebuggerManager.getBreakpointManager().getLineBreakpointManager().queueBreakpointUpdate((XLineBreakpointImpl<?>)breakpoint);
385 public boolean breakpointReached(@NotNull final XBreakpoint<?> breakpoint, @NotNull final XSuspendContext suspendContext) {
386 return breakpointReached(breakpoint, null, suspendContext);
389 public boolean breakpointReached(@NotNull XBreakpoint<?> breakpoint, @Nullable String evaluatedLogExpression,
390 @NotNull XSuspendContext suspendContext) {
391 XDebuggerEvaluator evaluator = XDebuggerUtilImpl.getEvaluator(suspendContext);
392 String condition = breakpoint.getCondition();
393 if (condition != null && evaluator != null) {
394 LOG.debug("evaluating condition: " + condition);
395 boolean result = evaluator.evaluateCondition(condition);
396 LOG.debug("condition evaluates to " + result);
397 if (!result) {
398 return false;
402 if (breakpoint.isLogMessage()) {
403 String text = StringUtil.decapitalize(XBreakpointUtil.getDisplayText(breakpoint));
404 final XSourcePosition position = breakpoint.getSourcePosition();
405 final OpenFileHyperlinkInfo hyperlinkInfo = position != null ? new OpenFileHyperlinkInfo(myProject, position.getFile(), position.getLine()) : null;
406 printMessage(XDebuggerBundle.message("xbreakpoint.reached.text") + " ", text, hyperlinkInfo);
409 if (evaluatedLogExpression != null) {
410 printMessage(evaluatedLogExpression, null, null);
412 else {
413 String expression = breakpoint.getLogExpression();
414 if (expression != null && evaluator != null) {
415 LOG.debug("evaluating log expression: " + expression);
416 final String message = evaluator.evaluateMessage(expression);
417 if (message != null) {
418 printMessage(message, null, null);
423 processDependencies(breakpoint);
425 if (breakpoint.getSuspendPolicy() == SuspendPolicy.NONE) {
426 return false;
429 positionReached(suspendContext);
430 return true;
433 private void processDependencies(final XBreakpoint<?> breakpoint) {
434 XDependentBreakpointManager dependentBreakpointManager = myDebuggerManager.getBreakpointManager().getDependentBreakpointManager();
435 if (!dependentBreakpointManager.isMasterOrSlave(breakpoint)) return;
437 List<XBreakpoint<?>> breakpoints = dependentBreakpointManager.getSlaveBreakpoints(breakpoint);
438 myDisabledSlaveBreakpoints.removeAll(breakpoints);
439 for (XBreakpoint<?> slaveBreakpoint : breakpoints) {
440 processAllHandlers(slaveBreakpoint, true);
443 if (dependentBreakpointManager.getMasterBreakpoint(breakpoint) != null && !dependentBreakpointManager.isLeaveEnabled(breakpoint)) {
444 boolean added = myDisabledSlaveBreakpoints.add(breakpoint);
445 if (added) {
446 processAllHandlers(breakpoint, false);
447 myDebuggerManager.getBreakpointManager().getLineBreakpointManager().queueBreakpointUpdate(breakpoint);
452 private void printMessage(final String message, final String hyperLinkText, @Nullable final HyperlinkInfo info) {
453 DebuggerUIUtil.invokeOnEventDispatch(new Runnable() {
454 public void run() {
455 final ConsoleView consoleView = getConsoleView();
456 consoleView.print(message, ConsoleViewContentType.SYSTEM_OUTPUT);
457 if (info != null) {
458 consoleView.printHyperlink(hyperLinkText, info);
460 else if (hyperLinkText != null) {
461 consoleView.print(hyperLinkText, ConsoleViewContentType.SYSTEM_OUTPUT);
463 consoleView.print("\n", ConsoleViewContentType.SYSTEM_OUTPUT);
468 private ConsoleView getConsoleView() {
469 return (ConsoleView)mySessionTab.getConsole();
472 public void positionReached(@NotNull final XSuspendContext suspendContext) {
473 enableBreakpoints();
474 mySuspendContext = suspendContext;
475 XExecutionStack executionStack = suspendContext.getActiveExecutionStack();
476 myCurrentStackFrame = executionStack != null ? executionStack.getTopFrame() : null;
477 myCurrentPosition = myCurrentStackFrame != null ? myCurrentStackFrame.getSourcePosition() : null;
479 myPaused = true;
480 if (myCurrentPosition != null) {
481 myDebuggerManager.updateExecutionPosition(this, myCurrentPosition, false);
483 mySessionTab.toFront();
484 myDispatcher.getMulticaster().sessionPaused();
487 private void enableBreakpoints() {
488 if (myBreakpointsDisabled) {
489 myBreakpointsDisabled = false;
490 new ReadAction() {
491 protected void run(final Result result) {
492 processAllBreakpoints(true, false);
494 }.execute();
498 public boolean isStopped() {
499 return myStopped;
502 public void stopImpl() {
503 if (myStopped) return;
505 myDebugProcess.stop();
506 myCurrentPosition = null;
507 myCurrentStackFrame = null;
508 mySuspendContext = null;
509 myDebuggerManager.updateExecutionPosition(this, null, false);
510 XBreakpointManagerImpl breakpointManager = myDebuggerManager.getBreakpointManager();
511 breakpointManager.removeBreakpointListener(myBreakpointListener);
512 breakpointManager.getDependentBreakpointManager().removeListener(myDependentBreakpointListener);
513 myStopped = true;
514 myDebuggerManager.removeSession(this);
515 myDispatcher.getMulticaster().sessionStopped();
518 public boolean isDisabledSlaveBreakpoint(final XBreakpoint<?> breakpoint) {
519 return myDisabledSlaveBreakpoints.contains(breakpoint);
522 public void stop() {
523 ProcessHandler processHandler = myDebugProcess.getProcessHandler();
524 if (processHandler.isProcessTerminated() || processHandler.isProcessTerminating()) return;
526 if (processHandler.detachIsDefault()) {
527 processHandler.detachProcess();
529 else {
530 processHandler.destroyProcess();
534 private class MyBreakpointListener implements XBreakpointListener<XBreakpoint<?>> {
535 public void breakpointAdded(@NotNull final XBreakpoint<?> breakpoint) {
536 if (!myBreakpointsDisabled) {
537 processAllHandlers(breakpoint, true);
541 public void breakpointRemoved(@NotNull final XBreakpoint<?> breakpoint) {
542 processAllHandlers(breakpoint, false);
545 public void breakpointChanged(@NotNull final XBreakpoint<?> breakpoint) {
546 breakpointRemoved(breakpoint);
547 breakpointAdded(breakpoint);
551 private class MyDependentBreakpointListener implements XDependentBreakpointListener {
552 public void dependencySet(final XBreakpoint<?> slave, final XBreakpoint<?> master) {
553 boolean added = myDisabledSlaveBreakpoints.add(slave);
554 if (added) {
555 processAllHandlers(slave, false);
559 public void dependencyCleared(final XBreakpoint<?> breakpoint) {
560 boolean removed = myDisabledSlaveBreakpoints.remove(breakpoint);
561 if (removed) {
562 processAllHandlers(breakpoint, true);