/**
* Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package org.python.pydev.debug.model;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IBreakpointManager;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchListener;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IMemoryBlock;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.internal.console.IOConsolePartition;
import org.eclipse.ui.views.properties.IPropertySource;
import org.eclipse.ui.views.tasklist.ITaskListResourceAdapter;
import org.python.pydev.core.ExtensionHelper;
import org.python.pydev.core.log.Log;
import org.python.pydev.debug.core.IConsoleInputListener;
import org.python.pydev.debug.core.PydevDebugPlugin;
import org.python.pydev.debug.core.PydevDebugPreferencesInitializer;
import org.python.pydev.debug.curr_exception.CurrentExceptionView;
import org.python.pydev.debug.model.XMLUtils.StoppedStack;
import org.python.pydev.debug.model.remote.AbstractDebuggerCommand;
import org.python.pydev.debug.model.remote.AbstractRemoteDebugger;
import org.python.pydev.debug.model.remote.AddIgnoreThrownExceptionIn;
import org.python.pydev.debug.model.remote.RemoveBreakpointCommand;
import org.python.pydev.debug.model.remote.RunCommand;
import org.python.pydev.debug.model.remote.SendPyExceptionCommand;
import org.python.pydev.debug.model.remote.SetBreakpointCommand;
import org.python.pydev.debug.model.remote.SetDjangoExceptionBreakpointCommand;
import org.python.pydev.debug.model.remote.SetDontTraceEnabledCommand;
import org.python.pydev.debug.model.remote.SetPropertyTraceCommand;
import org.python.pydev.debug.model.remote.SetShowReturnValuesEnabledCommand;
import org.python.pydev.debug.model.remote.ThreadListCommand;
import org.python.pydev.debug.model.remote.VersionCommand;
import org.python.pydev.debug.ui.launching.PythonRunnerConfig;
import org.python.pydev.editor.preferences.PydevEditorPrefs;
import org.python.pydev.editorinput.PySourceLocatorBase;
import org.python.pydev.plugin.PydevPlugin;
import org.python.pydev.shared_core.string.FastStringBuffer;
import org.python.pydev.shared_core.string.StringUtils;
import org.python.pydev.shared_core.structure.Tuple;
import org.python.pydev.shared_core.utils.ArrayUtils;
import org.python.pydev.shared_ui.utils.RunInUiThread;
/**
* This is the target for the debug (
*
* @author Fabio
*/
@SuppressWarnings("restriction")
public abstract class AbstractDebugTarget extends AbstractDebugTargetWithTransmission implements IDebugTarget,
ILaunchListener, IExceptionsBreakpointListener, IPropertyTraceListener {
private static final boolean DEBUG = false;
/**
* Path pointing to the file that started the debug (e.g.: file with __name__ == '__main__')
*/
protected IPath[] file;
/**
* The threads found in the debugger.
*/
protected PyThread[] threads;
/**
* Indicates whether we've already disconnected from the debugger.
*/
protected boolean disconnected = false;
/**
* This is the instance used to pass messages to the debugger.
*/
protected AbstractRemoteDebugger debugger;
/**
* Launch that triggered the debug session.
*/
protected ILaunch launch;
private PyRunToLineTarget runToLineTarget;
public AbstractDebugTarget() {
}
@Override
public abstract boolean canTerminate();
@Override
public abstract boolean isTerminated();
@Override
public void terminate() {
PydevPlugin plugin = PydevPlugin.getDefault();
if (plugin != null) {
IPreferenceStore preferenceStore = plugin.getPreferenceStore();
if (preferenceStore != null) {
preferenceStore.removePropertyChangeListener(listener);
}
}
if (socket != null) {
try {
socket.shutdownInput(); // trying to make my pydevd notice that the socket is gone
} catch (Exception e) {
// ok, ignore
}
try {
socket.shutdownOutput();
} catch (Exception e) {
// ok, ignore
}
try {
socket.close();
} catch (Exception e) {
// ok, ignore
}
}
socket = null;
disconnected = true;
if (writer != null) {
writer.done();
writer = null;
}
if (reader != null) {
reader.done();
reader = null;
}
if (DEBUG) {
System.out.println("TERMINATE");
}
threads = new PyThread[0];
fireEvent(new DebugEvent(this, DebugEvent.TERMINATE));
}
public AbstractRemoteDebugger getDebugger() {
return debugger;
}
@Override
public void launchAdded(ILaunch launch) {
// noop
}
@Override
public void launchChanged(ILaunch launch) {
// noop
}
// From IDebugElement
@Override
public String getModelIdentifier() {
return PyDebugModelPresentation.PY_DEBUG_MODEL_ID;
}
// From IDebugElement
@Override
public IDebugTarget getDebugTarget() {
return this;
}
@Override
public String getName() throws DebugException {
if (file != null) {
return PythonRunnerConfig.getRunningName(file);
} else {
return "unknown"; //TODO: SHOW PROPER PROCESS ID!
}
}
@Override
public boolean canResume() {
for (int i = 0; i < threads.length; i++) {
if (threads[i].canResume()) {
return true;
}
}
return false;
}
@Override
public boolean canSuspend() {
for (int i = 0; i < threads.length; i++) {
if (threads[i].canSuspend()) {
return true;
}
}
return false;
}
@Override
public boolean isSuspended() {
return false;
}
@Override
public void resume() throws DebugException {
for (int i = 0; i < threads.length; i++) {
threads[i].resume();
}
}
@Override
public void suspend() throws DebugException {
for (int i = 0; i < threads.length; i++) {
threads[i].suspend();
}
}
@Override
public IThread[] getThreads() throws DebugException {
if (debugger == null) {
return null;
}
if (threads == null) {
ThreadListCommand cmd = new ThreadListCommand(this);
this.postCommand(cmd);
try {
cmd.waitUntilDone(1000);
threads = cmd.getThreads();
} catch (InterruptedException e) {
threads = new PyThread[0];
}
}
return threads;
}
@Override
public boolean hasThreads() throws DebugException {
return true;
}
//Breakpoints ------------------------------------------------------------------------------------------------------
/* (non-Javadoc)
* @see org.python.pydev.debug.model.IExceptionsBreakpointListener#onSetConfiguredExceptions()
*/
@Override
public void onSetConfiguredExceptions() {
// Sending python exceptions to the debugger
SendPyExceptionCommand sendCmd = new SendPyExceptionCommand(this);
this.postCommand(sendCmd);
}
/**
* Same as onAddIgnoreThrownExceptionIn, but bulk-created with all available.
*/
@Override
public void onUpdateIgnoreThrownExceptions() {
AddIgnoreThrownExceptionIn cmd = new AddIgnoreThrownExceptionIn(this);
this.postCommand(cmd);
}
@Override
public void onAddIgnoreThrownExceptionIn(File file, int lineNumber) {
AddIgnoreThrownExceptionIn cmd = new AddIgnoreThrownExceptionIn(this, file, lineNumber);
this.postCommand(cmd);
}
/*
* (non-Javadoc)
* @see org.python.pydev.debug.model.IPropertyTraceListener#onSetPropertyTraceConfiguration()
*/
@Override
public void onSetPropertyTraceConfiguration() {
// Sending whether to trace python property
SetPropertyTraceCommand sendCmd = new SetPropertyTraceCommand(this);
this.postCommand(sendCmd);
}
/**
* @return true if the given breakpoint is supported by this target
*/
@Override
public boolean supportsBreakpoint(IBreakpoint breakpoint) {
return breakpoint instanceof PyBreakpoint;
}
/**
* @return true if all the breakpoints should be skipped. Patch from bug:
* http://sourceforge.net/tracker/index.php?func=detail&aid=1960983&group_id=85796&atid=577329
*/
private boolean shouldSkipBreakpoints() {
DebugPlugin manager = DebugPlugin.getDefault();
return manager != null && !manager.getBreakpointManager().isEnabled();
}
/**
* Adds a breakpoint if it's enabled.
*/
@Override
public void breakpointAdded(IBreakpoint breakpoint) {
try {
if (breakpoint instanceof PyBreakpoint) {
PyBreakpoint b = (PyBreakpoint) breakpoint;
if (b.isEnabled() && !shouldSkipBreakpoints()) {
String condition = null;
if (b.isConditionEnabled()) {
condition = b.getCondition();
if (condition != null) {
condition = StringUtils.replaceAll(condition, "\n",
"@_@NEW_LINE_CHAR@_@");
condition = StringUtils.replaceAll(condition, "\t",
"@_@TAB_CHAR@_@");
}
}
String file2 = b.getFile();
Object line = b.getLine();
if (file2 == null || line == null) {
Log.log("Trying to add breakpoint with invalid file: " + file2 + " or line: " + line);
} else {
SetBreakpointCommand cmd = new SetBreakpointCommand(this, b.breakpointId, file2, line,
condition, b.getFunctionName(), b.getType());
this.postCommand(cmd);
}
}
}
} catch (CoreException e) {
Log.log(e);
}
}
/**
* Removes an existing breakpoint from the debug target.
*/
@Override
public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
if (breakpoint instanceof PyBreakpoint) {
PyBreakpoint b = (PyBreakpoint) breakpoint;
RemoveBreakpointCommand cmd = new RemoveBreakpointCommand(this, b.breakpointId, b.getFile(), b.getType());
this.postCommand(cmd);
}
}
/**
* Called when a breakpoint is changed.
* E.g.:
* - When line numbers change in the file
* - When the manager decides to enable/disable all existing markers
* - When the breakpoint properties (hit condition) are edited
*/
@Override
public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
if (breakpoint instanceof PyBreakpoint) {
breakpointRemoved(breakpoint, null);
breakpointAdded(breakpoint);
}
}
//End Breakpoints --------------------------------------------------------------------------------------------------
// Storage retrieval is not supported
@Override
public boolean supportsStorageRetrieval() {
return false;
}
@Override
public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException {
return null;
}
/**
* When a command that originates from daemon is received,
* this routine processes it.
* The responses to commands originating from here
* are processed by commands themselves
*/
public void processCommand(String sCmdCode, String sSeqCode, String payload) {
if (DEBUG) {
System.out.println("process command:" + sCmdCode +
"\tseq:" + sSeqCode +
"\tpayload:" + payload +
"\n\n");
}
try {
int cmdCode = Integer.parseInt(sCmdCode);
if (cmdCode == AbstractDebuggerCommand.CMD_THREAD_CREATED) {
processThreadCreated(payload);
} else if (cmdCode == AbstractDebuggerCommand.CMD_THREAD_KILL) {
processThreadKilled(payload);
} else if (cmdCode == AbstractDebuggerCommand.CMD_THREAD_SUSPEND) {
processThreadSuspended(payload);
} else if (cmdCode == AbstractDebuggerCommand.CMD_THREAD_RUN) {
processThreadRun(payload);
} else if (cmdCode == AbstractDebuggerCommand.CMD_GET_BREAKPOINT_EXCEPTION) {
processBreakpointException(payload);
} else if (cmdCode == AbstractDebuggerCommand.CMD_SEND_CURR_EXCEPTION_TRACE) {
processCaughtExceptionTraceSent(payload);
} else if (cmdCode == AbstractDebuggerCommand.CMD_SEND_CURR_EXCEPTION_TRACE_PROCEEDED) {
processCaughtExceptionTraceProceededSent(payload);
} else if (cmdCode == AbstractDebuggerCommand.CMD_INPUT_REQUESTED) {
if ("true".equalsIgnoreCase(payload.trim())) {
this.setWaitingForInput(true);
} else if ("false".equalsIgnoreCase(payload.trim())) {
this.setWaitingForInput(false);
} else {
PydevDebugPlugin.log(IStatus.WARNING, "Unexpected payload for CMD_INPUT_REQUESTED" +
"\npayload:" + payload, null);
}
} else if (cmdCode == AbstractDebuggerCommand.CMD_PROCESS_CREATED) {
// We don't really need to handle process created for now.
} else {
PydevDebugPlugin.log(IStatus.WARNING, "Unexpected debugger command:" + sCmdCode +
"\nseq:" + sSeqCode
+
"\npayload:" + payload, null);
}
} catch (Exception e) {
PydevDebugPlugin.log(IStatus.ERROR, "Error processing: " + sCmdCode +
"\npayload: " + payload, e);
}
}
public void fireEvent(DebugEvent event) {
DebugPlugin manager = DebugPlugin.getDefault();
if (manager != null) {
manager.fireDebugEventSet(new DebugEvent[] { event });
}
}
/**
* @return an existing thread with a given id (null if none)
*/
protected PyThread findThreadByID(String thread_id) {
for (IThread thread : threads) {
if (thread_id.equals(((PyThread) thread).getId())) {
return (PyThread) thread;
}
}
return null;
}
/**
* Add it to the list of threads
*/
private void processThreadCreated(String payload) {
PyThread[] newThreads;
try {
newThreads = XMLUtils.ThreadsFromXML(this, payload);
} catch (CoreException e) {
PydevDebugPlugin.errorDialog("Error in processThreadCreated", e);
return;
}
// Hide Pydevd threads if requested
if (PydevDebugPlugin.getDefault().getPreferenceStore()
.getBoolean(PydevDebugPreferencesInitializer.HIDE_PYDEVD_THREADS)) {
int removeThisMany = 0;
for (int i = 0; i < newThreads.length; i++) {
if (newThreads[i].isPydevThread()) {
removeThisMany++;
}
}
if (removeThisMany > 0) {
int newSize = newThreads.length - removeThisMany;
if (newSize == 0) { // no threads to add
return;
} else {
PyThread[] newnewThreads = new PyThread[newSize];
int i = 0;
for (PyThread newThread : newThreads) {
if (!newThread.isPydevThread()) {
newnewThreads[i] = newThread;
i += 1;
}
}
newThreads = newnewThreads;
}
}
}
// add threads to the thread list, and fire event
if (threads == null) {
threads = newThreads;
} else {
threads = ArrayUtils.concatArrays(threads, newThreads);
}
// Now notify debugger that new threads were added
for (int i = 0; i < newThreads.length; i++) {
fireEvent(new DebugEvent(newThreads[i], DebugEvent.CREATE));
}
}
// Remote this from our thread list
private void processThreadKilled(String thread_id) {
PyThread threadToDelete = findThreadByID(thread_id);
if (threadToDelete != null) {
int j = 0;
PyThread[] newThreads = new PyThread[threads.length - 1];
for (int i = 0; i < threads.length; i++) {
if (threads[i] != threadToDelete) {
newThreads[j++] = threads[i];
}
}
threads = newThreads;
fireEvent(new DebugEvent(threadToDelete, DebugEvent.TERMINATE));
}
}
private void processThreadSuspended(String payload) {
StoppedStack threadNstack;
try {
threadNstack = XMLUtils.XMLToStack(this, payload);
} catch (CoreException e) {
PydevDebugPlugin.errorDialog("Error reading ThreadSuspended", e);
return;
}
PyThread t = threadNstack.thread;
int reason = DebugEvent.UNSPECIFIED;
String stopReason = threadNstack.stopReason;
if (stopReason != null) {
int stopReason_i = Integer.parseInt(stopReason);
if (stopReason_i == AbstractDebuggerCommand.CMD_STEP_OVER
|| stopReason_i == AbstractDebuggerCommand.CMD_STEP_INTO
|| stopReason_i == AbstractDebuggerCommand.CMD_STEP_CAUGHT_EXCEPTION
|| stopReason_i == AbstractDebuggerCommand.CMD_STEP_RETURN
|| stopReason_i == AbstractDebuggerCommand.CMD_RUN_TO_LINE
|| stopReason_i == AbstractDebuggerCommand.CMD_SET_NEXT_STATEMENT) {
//Code which could be used to know where a caught exception broke the debugger.
//if (stopReason_i == AbstractDebuggerCommand.CMD_STEP_CAUGHT_EXCEPTION) {
// System.out.println("Stopped: caught exception");
// IStackFrame stackFrame[] = (IStackFrame[]) threadNstack[2];
// if (stackFrame.length > 0) {
// IStackFrame currStack = stackFrame[0];
// if (currStack instanceof PyStackFrame) {
// PyStackFrame pyStackFrame = (PyStackFrame) currStack;
// try {
// System.out.println(pyStackFrame.getPath() + " " + pyStackFrame.getLineNumber());
// } catch (DebugException e) {
// Log.log(e);
// }
// }
// }
//
//}
reason = DebugEvent.STEP_END;
} else if (stopReason_i == AbstractDebuggerCommand.CMD_THREAD_SUSPEND) {
reason = DebugEvent.CLIENT_REQUEST;
} else if (stopReason_i == AbstractDebuggerCommand.CMD_SET_BREAK) {
reason = DebugEvent.BREAKPOINT;
} else {
PydevDebugPlugin.log(IStatus.ERROR, "Unexpected reason for suspension", null);
reason = DebugEvent.UNSPECIFIED;
}
}
if (t != null) {
IStackFrame stackFrame[] = threadNstack.stack;
t.setSuspended(true, stackFrame);
fireEvent(new DebugEvent(t, DebugEvent.SUSPEND, reason));
}
}
/**
* @param payload a string in the format: thread_id\tresume_reason
* E.g.: pid3720_zad_seq1\t108
*
* @return a tuple with the thread id and the reason it stopped.
* @throws CoreException
*/
public static Tuple<String, String> getThreadIdAndReason(String payload) throws CoreException {
List<String> split = StringUtils.split(payload.trim(), '\t');
if (split.size() != 2) {
String msg = "Unexpected threadRun payload " + payload +
"(unable to match)";
throw new CoreException(PydevDebugPlugin.makeStatus(IStatus.ERROR, msg, new RuntimeException(msg)));
}
return new Tuple<String, String>(split.get(0), split.get(1));
}
/**
* ThreadRun event processing
*/
private void processThreadRun(String payload) {
try {
Tuple<String, String> threadIdAndReason = getThreadIdAndReason(payload);
int resumeReason = DebugEvent.UNSPECIFIED;
try {
int raw_reason = Integer.parseInt(threadIdAndReason.o2);
if (raw_reason == AbstractDebuggerCommand.CMD_STEP_OVER) {
resumeReason = DebugEvent.STEP_OVER;
} else if (raw_reason == AbstractDebuggerCommand.CMD_STEP_RETURN) {
resumeReason = DebugEvent.STEP_RETURN;
} else if (raw_reason == AbstractDebuggerCommand.CMD_STEP_INTO
|| raw_reason == AbstractDebuggerCommand.CMD_STEP_CAUGHT_EXCEPTION) {
resumeReason = DebugEvent.STEP_INTO;
} else if (raw_reason == AbstractDebuggerCommand.CMD_RUN_TO_LINE) {
resumeReason = DebugEvent.UNSPECIFIED;
} else if (raw_reason == AbstractDebuggerCommand.CMD_SET_NEXT_STATEMENT) {
resumeReason = DebugEvent.UNSPECIFIED;
} else if (raw_reason == AbstractDebuggerCommand.CMD_THREAD_RUN || raw_reason == -1) {
resumeReason = DebugEvent.CLIENT_REQUEST;
} else {
PydevDebugPlugin.log(IStatus.ERROR,
"Unexpected resume reason code: " + raw_reason + " payload: " + payload, null);
resumeReason = DebugEvent.UNSPECIFIED;
}
} catch (NumberFormatException e) {
// expected, when pydevd reports "None"
resumeReason = DebugEvent.UNSPECIFIED;
}
String threadID = threadIdAndReason.o1;
PyThread t = findThreadByID(threadID);
if (t != null) {
t.setSuspended(false, null);
fireEvent(new DebugEvent(t, DebugEvent.RESUME, resumeReason));
} else {
FastStringBuffer buf = new FastStringBuffer();
for (PyThread thread : threads) {
if (buf.length() > 0) {
buf.append(", ");
}
buf.append("id: " + thread.getId());
}
String msg = "Unable to find thread: " + threadID +
" available: " + buf;
PydevDebugPlugin.log(IStatus.ERROR, msg, new RuntimeException(msg));
}
} catch (CoreException e1) {
Log.log(e1);
}
}
/**
* Handle the exception received while evaluating the breakpoint condition
*
* @param payload
*/
private void processBreakpointException(String payload) {
PyConditionalBreakPointManager.getInstance().handleBreakpointException(this, payload);
}
private Object currExceptionsLock = new Object();
private List<CaughtException> currExceptions = new ArrayList<>();
public List<CaughtException> getCurrExceptions() {
synchronized (currExceptionsLock) {
return new ArrayList<>(currExceptions);
}
}
public boolean hasCurrExceptions() {
synchronized (currExceptionsLock) {
return currExceptions.size() > 0;
}
}
private void processCaughtExceptionTraceProceededSent(String payload) {
synchronized (currExceptionsLock) {
for (Iterator<CaughtException> it = currExceptions.iterator(); it.hasNext();) {
CaughtException s = it.next();
if (payload.equals(s.threadNstack.thread.getId())) {
it.remove();
break;
}
}
}
updateView();
}
/**
* Handle the exception received while evaluating the breakpoint condition
*
* @param payload
*/
private void processCaughtExceptionTraceSent(String payload) {
List<String> split = StringUtils.split(payload, '\t', 4);
StoppedStack threadNstack;
try {
threadNstack = XMLUtils.XMLToStack(this, split.get(3));
} catch (CoreException e) {
PydevDebugPlugin.errorDialog("Error on processCaughtExceptionTraceSent", e);
return;
}
synchronized (currExceptionsLock) {
//payload is: currentFrameId, excType, msg, xml with thread/stack
currExceptions.add(new CaughtException(split.get(0), split.get(1), split.get(2), threadNstack));
}
updateView();
}
private void updateView() {
RunInUiThread.async(new Runnable() {
@Override
public void run() {
CurrentExceptionView view = CurrentExceptionView.getView(true);
view.update();
}
});
}
/**
* Listens to the (org) PydevPlugin preferences.
*/
private final IPropertyChangeListener listener = new IPropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
String property = event.getProperty();
if (property.equals(PydevEditorPrefs.DONT_TRACE_ENABLED)) {
sendDontTraceEnabledCommand();
} else if (property.equals(PydevEditorPrefs.SHOW_RETURN_VALUES)) {
sendShowReturnValuesEnabledCommand();
} else if (property.equals(PydevEditorPrefs.TRACE_DJANGO_TEMPLATE_RENDER_EXCEPTIONS)) {
sendSetDjangoExceptionBreakpointCommand();
}
}
};
/**
* Called after debugger has been connected.
*
* Here we send all the initialization commands
* and exceptions on which pydev debugger needs to break
*/
public void initialize() {
// we post version command just for fun
// it establishes the connection
this.postCommand(new VersionCommand(this));
// now, register all the breakpoints in all projects
addBreakpointsFor(ResourcesPlugin.getWorkspace().getRoot());
// Sending python exceptions and property trace state before sending run command
this.onSetConfiguredExceptions();
this.onSetPropertyTraceConfiguration();
this.onUpdateIgnoreThrownExceptions();
this.sendSetDjangoExceptionBreakpointCommand();
this.sendDontTraceEnabledCommand();
this.sendShowReturnValuesEnabledCommand();
IPreferenceStore pyPrefsStore = PydevPlugin.getDefault().getPreferenceStore();
pyPrefsStore.addPropertyChangeListener(listener);
// Send the run command, and we are off
RunCommand run = new RunCommand(this);
this.postCommand(run);
}
private void sendDontTraceEnabledCommand() {
IPreferenceStore pyPrefsStore = PydevPlugin.getDefault().getPreferenceStore();
SetDontTraceEnabledCommand cmd = new SetDontTraceEnabledCommand(this,
pyPrefsStore.getBoolean(PydevEditorPrefs.DONT_TRACE_ENABLED));
this.postCommand(cmd);
}
private void sendShowReturnValuesEnabledCommand() {
IPreferenceStore pyPrefsStore = PydevPlugin.getDefault().getPreferenceStore();
SetShowReturnValuesEnabledCommand cmd = new SetShowReturnValuesEnabledCommand(this,
pyPrefsStore.getBoolean(PydevEditorPrefs.SHOW_RETURN_VALUES));
this.postCommand(cmd);
}
private void sendSetDjangoExceptionBreakpointCommand() {
IPreferenceStore pyPrefsStore = PydevPlugin.getDefault().getPreferenceStore();
SetDjangoExceptionBreakpointCommand cmd = new SetDjangoExceptionBreakpointCommand(
this, pyPrefsStore.getBoolean(PydevEditorPrefs.TRACE_DJANGO_TEMPLATE_RENDER_EXCEPTIONS));
this.postCommand(cmd);
}
/**
* Adds the breakpoints associated with a container.
* @param container the container we're interested in (usually workspace root)
*/
private void addBreakpointsFor(IContainer container) {
try {
IMarker[] markers = container.findMarkers(PyBreakpoint.PY_BREAK_MARKER, true, IResource.DEPTH_INFINITE);
IMarker[] condMarkers = container.findMarkers(PyBreakpoint.PY_CONDITIONAL_BREAK_MARKER, true,
IResource.DEPTH_INFINITE);
IMarker[] djangoMarkers = container.findMarkers(PyBreakpoint.DJANGO_BREAK_MARKER, true,
IResource.DEPTH_INFINITE);
IBreakpointManager breakpointManager = DebugPlugin.getDefault().getBreakpointManager();
for (IMarker marker : markers) {
PyBreakpoint brk = (PyBreakpoint) breakpointManager.getBreakpoint(marker);
breakpointAdded(brk);
}
for (IMarker marker : condMarkers) {
PyBreakpoint brk = (PyBreakpoint) breakpointManager.getBreakpoint(marker);
breakpointAdded(brk);
}
for (IMarker marker : djangoMarkers) {
PyBreakpoint brk = (PyBreakpoint) breakpointManager.getBreakpoint(marker);
breakpointAdded(brk);
}
} catch (Throwable t) {
PydevDebugPlugin.errorDialog("Error setting breakpoints", t);
}
}
/**
* This function adds the input listener extension point, so that plugins that only care about
* the input in the console can know about it.
*/
@SuppressWarnings({ "unchecked" })
public void addConsoleInputListener() {
IConsole console = DebugUITools.getConsole(this.getProcess());
if (console instanceof ProcessConsole) {
final ProcessConsole c = (ProcessConsole) console;
final List<IConsoleInputListener> participants = ExtensionHelper
.getParticipants(ExtensionHelper.PYDEV_DEBUG_CONSOLE_INPUT_LISTENER);
final AbstractDebugTarget target = this;
target.addProcessConsole(c);
//let's listen the doc for the changes
c.getDocument().addDocumentListener(new IDocumentListener() {
@Override
public void documentAboutToBeChanged(DocumentEvent event) {
if (target.isWaitingForInput()) {
return;
}
//only report when we have a new line
if (event.fText.indexOf('\r') != -1 || event.fText.indexOf('\n') != -1) {
try {
ITypedRegion partition = event.fDocument.getPartition(event.fOffset);
if (partition instanceof IOConsolePartition) {
IOConsolePartition p = (IOConsolePartition) partition;
//we only communicate about inputs (because we only care about what the user writes)
if (p.getType().equals(IOConsolePartition.INPUT_PARTITION_TYPE)) {
if (event.fText.length() <= 2) {
//the user typed something
final String inputFound = p.getString();
for (IConsoleInputListener listener : participants) {
listener.newLineReceived(inputFound, target);
}
}
}
}
} catch (Exception e) {
Log.log(e);
}
}
}
@Override
public void documentChanged(DocumentEvent event) {
if (target.isWaitingForInput()) {
return;
}
//only report when we have a new line
if (event.fText.indexOf('\r') != -1 || event.fText.indexOf('\n') != -1) {
try {
ITypedRegion partition = event.fDocument.getPartition(event.fOffset);
if (partition instanceof IOConsolePartition) {
IOConsolePartition p = (IOConsolePartition) partition;
//we only communicate about inputs (because we only care about what the user writes)
if (p.getType().equals(IOConsolePartition.INPUT_PARTITION_TYPE)) {
if (event.fText.length() > 2) {
//the user pasted something
for (IConsoleInputListener listener : participants) {
listener.pasteReceived(event.fText, target);
}
}
}
}
} catch (Exception e) {
Log.log(e);
}
}
}
});
}
}
@Override
public boolean canDisconnect() {
return !disconnected;
}
@Override
public void disconnect() throws DebugException {
this.terminate();
}
@Override
public boolean isDisconnected() {
return disconnected;
}
@SuppressWarnings("unchecked")
@Override
public <T> T getAdapter(Class<T> adapter) {
AdapterDebug.print(this, adapter);
// Not really sure what to do here, but I am trying
if (adapter.equals(ILaunch.class)) {
return (T) launch;
} else if (adapter.equals(IResource.class)) {
// used by Variable ContextManager, and Project:Properties menu item
if (file != null && file.length > 0) {
return (T) new PySourceLocatorBase().getFileForLocation(file[0], null);
} else {
return null;
}
} else if (adapter.equals(org.eclipse.debug.ui.actions.IRunToLineTarget.class)) {
return (T) this.getRunToLineTarget();
} else if (adapter.equals(IPropertySource.class)) {
return launch.getAdapter(adapter);
} else if (adapter.equals(ITaskListResourceAdapter.class)
|| adapter.equals(org.eclipse.debug.ui.actions.IToggleBreakpointsTarget.class)) {
return super.getAdapter(adapter);
}
AdapterDebug.printDontKnow(this, adapter);
return super.getAdapter(adapter);
}
public PyRunToLineTarget getRunToLineTarget() {
if (this.runToLineTarget == null) {
this.runToLineTarget = new PyRunToLineTarget();
}
return this.runToLineTarget;
}
//From IDebugElement
@Override
public ILaunch getLaunch() {
return launch;
}
}