/*=============================================================================#
# Copyright (c) 2010-2016 Stephan Wahlbrink (WalWare.de) and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
#
# Contributors:
# Stephan Wahlbrink - initial API and implementation
#=============================================================================*/
package de.walware.statet.r.nico;
import java.net.URI;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.Version;
import de.walware.ecommons.io.FileUtil;
import de.walware.ecommons.ltk.LTK;
import de.walware.ecommons.ltk.core.model.ISourceUnit;
import de.walware.ecommons.ltk.core.model.IWorkspaceSourceUnit;
import de.walware.ecommons.ts.ISystemRunnable;
import de.walware.ecommons.ts.ITool;
import de.walware.ecommons.ts.IToolRunnable;
import de.walware.ecommons.ts.IToolService;
import de.walware.statet.nico.core.runtime.Prompt;
import de.walware.statet.nico.core.runtime.SubmitType;
import de.walware.statet.nico.core.runtime.ToolStatus;
import de.walware.statet.nico.core.runtime.ToolStreamProxy;
import de.walware.rj.data.RDataUtil;
import de.walware.rj.data.RObject;
import de.walware.rj.data.RReference;
import de.walware.rj.data.UnexpectedRDataException;
import de.walware.rj.data.defaultImpl.RReferenceImpl;
import de.walware.rj.server.dbg.CallStack;
import de.walware.rj.server.dbg.CtrlReport;
import de.walware.rj.server.dbg.DbgEnablement;
import de.walware.rj.server.dbg.DbgFilterState;
import de.walware.rj.server.dbg.DbgRequest;
import de.walware.rj.server.dbg.ElementTracepointInstallationRequest;
import de.walware.rj.server.dbg.Frame;
import de.walware.rj.server.dbg.FrameContext;
import de.walware.rj.server.dbg.FrameRef;
import de.walware.rj.server.dbg.SetDebugReport;
import de.walware.rj.server.dbg.SetDebugRequest;
import de.walware.rj.server.dbg.SrcfileData;
import de.walware.rj.server.dbg.TracepointEvent;
import de.walware.rj.server.dbg.TracepointInstallationReport;
import de.walware.rj.server.dbg.TracepointInstallationRequest;
import de.walware.rj.server.dbg.TracepointStatesUpdate;
import de.walware.statet.r.console.core.AbstractRController;
import de.walware.statet.r.console.core.ContinuePrompt;
import de.walware.statet.r.console.core.IRDataAdapter;
import de.walware.statet.r.console.core.RDbg;
import de.walware.statet.r.console.core.RProcess;
import de.walware.statet.r.core.RUtil;
import de.walware.statet.r.core.model.IRSourceUnit;
import de.walware.statet.r.core.model.IRWorkspaceSourceUnit;
import de.walware.statet.r.core.tool.IRConsoleService;
import de.walware.statet.r.internal.console.core.RConsoleCorePlugin;
/**
* For implementations supporting debug features
*/
public abstract class AbstractRDbgController extends AbstractRController
implements IRDataAdapter, ICombinedRDataAdapter {
public interface IRControllerTracepointAdapter {
boolean matchScriptBreakpoint(IRModelSrcref srcref, IProgressMonitor monitor);
ElementTracepointInstallationRequest getElementTracepoints(SrcfileData srcfile,
IRModelSrcref su, IProgressMonitor monitor );
ElementTracepointInstallationRequest prepareFileElementTracepoints(SrcfileData srcfile,
IRSourceUnit su, IProgressMonitor monitor );
void finishFileElementTracepoints(SrcfileData srcfileData, IRSourceUnit su,
ElementTracepointInstallationRequest request, IProgressMonitor monitor );
void installElementTracepoints(ElementTracepointInstallationRequest request,
IProgressMonitor monitor );
Object toEclipseData(TracepointEvent hit);
}
private static final int TOPLEVELBROWSER_ENABLE_COMMANDS= 1;
private static final int TOPLEVELBROWSER_CHECK_SUSPENDED= 3;
private static final int TOPLEVELBROWSER_CHECK_SUBMIT= 4;
protected static final RReference TOPLEVEL_ENV_FRAME= new RReferenceImpl(0, RObject.TYPE_ENV, null);
private IRControllerTracepointAdapter breakpointAdapter;
private CallStack callStack;
private int callStackStamp;
private RReference globalEnv;
private boolean suspendScheduled;
private final IToolRunnable suspendRunnable= new ControllerSystemRunnable(SUSPEND_TYPE_ID,
"Suspend") {
@Override
public boolean changed(final int event, final ITool tool) {
switch (event) {
case MOVING_FROM:
return false;
case REMOVING_FROM:
case BEING_ABANDONED:
case FINISHING_OK:
case FINISHING_ERROR:
case FINISHING_CANCEL:
synchronized (AbstractRDbgController.this.suspendRunnable) {
AbstractRDbgController.this.suspendScheduled= false;
}
break;
default:
break;
}
return true;
}
@Override
public void run(final IToolService service,
final IProgressMonitor monitor) throws CoreException {
if (getStatusL() == ToolStatus.STARTED_SUSPENDED
|| (getHotTasksState() <= 1 && (AbstractRDbgController.this.fCurrentPrompt.meta & META_PROMPT_SUSPENDED) != 0) ) {
return;
}
// if (!canSuspend(monitor)) {
// scheduleControllerRunnable(this);
// return;
// }
if (AbstractRDbgController.this.topLevelBrowserAction == 0) {
AbstractRDbgController.this.topLevelBrowserAction= TOPLEVELBROWSER_CHECK_SUBMIT;
}
doRequestSuspend(monitor);
}
};
private boolean topLevelBrowserEnabled;
private int topLevelBrowserAction;
private final ISystemRunnable fTopLevelBrowserRunnable= new ControllerSystemRunnable(
"r/debug", "Debugging") { //$NON-NLS-1$
@Override
public void run(final IToolService service,
final IProgressMonitor monitor) throws CoreException {
if (getCurrentLevelL() == 0) {
if ((AbstractRDbgController.this.fCurrentPrompt.meta & META_PROMPT_SUSPENDED) != 0) {
setSuspended(getBrowserLevel(AbstractRDbgController.this.fCurrentPrompt.text), 0, null);
}
else if ((AbstractRDbgController.this.fCurrentPrompt.meta & META_PROMPT_DEFAULT) != 0) {
switch (AbstractRDbgController.this.topLevelBrowserAction) {
case TOPLEVELBROWSER_ENABLE_COMMANDS:
initTopLevelBrowser(monitor);
break;
case TOPLEVELBROWSER_CHECK_SUSPENDED:
if (getQueue().size() > 0) {
AbstractRDbgController.this.topLevelBrowserAction= TOPLEVELBROWSER_CHECK_SUBMIT;
break;
}
setDebugBrowser(TOPLEVEL_ENV_FRAME, false, false, monitor);
//$FALL-THROUGH$
default:
removePostControllerRunnable(AbstractRDbgController.this.fTopLevelBrowserRunnable);
}
}
}
}
};
// private int fStepFilterAction;
// private final IToolRunnable fStepFilterRunnable= new IToolRunnable() {
//
// public String getTypeId() {
// return "r/debug/";
// }
//
// public SubmitType getSubmitType() {
// return SubmitType.OTHER;
// }
//
// public String getLabel() {
// return "Step Filter";
// }
//
// public boolean changed(final int event, final ToolProcess process) {
// return true;
// }
//
// public void run(final IToolRunnableControllerAdapter adapter,
// final IProgressMonitor monitor) throws CoreException {
// if (DebugPlugin.isUseStepFilters()
// && (fCurrentPrompt.meta & META_PROMPT_SUSPENDED) != 0) {
// if (fStepFilterAction == STEPFILTER_STEP1) {
// fStepFilterAction= 0;
// debugStepOver(true);
// }
// }
// }
//
// };
private String lastSrcfile;
private String lastSrcfilePath;
private TracepointEvent breakpointHit;
/**
*
* @param process the R process the controller belongs to
* @param initData the initialization data
* @param enableDebug if debug features should be enabled
*/
public AbstractRDbgController(final RProcess process, final Map<String, Object> initData) {
super(process, initData);
}
public void initDebug(final IRControllerTracepointAdapter breakpointAdapter) {
if (breakpointAdapter == null) {
throw new NullPointerException("breakpointAdapter");
}
setDebugEnabled(true);
this.breakpointAdapter= breakpointAdapter;
class LoadCallstackRunnable extends ControllerSystemRunnable implements ISystemRunnable {
public LoadCallstackRunnable() {
super("r/callstack", "Load Callstack"); //$NON-NLS-1$
}
@Override
public void run(final IToolService service,
final IProgressMonitor monitor) throws CoreException {
getCallStack(monitor);
}
}
addSuspendUpdateRunnable(new LoadCallstackRunnable());
addToolStatusListener(new IToolStatusListener() {
@Override
public void controllerStatusChanged(final ToolStatus oldStatus, final ToolStatus newStatus,
final List<DebugEvent> eventCollection) {
switch (newStatus) {
case STARTED_IDLING:
case STARTED_PROCESSING:
case TERMINATED:
AbstractRDbgController.this.callStack= null;
}
}
});
}
protected final void setCurrentPromptL(final String text, final boolean addToHistory) {
final TracepointEvent hit= this.breakpointHit;
this.breakpointHit= null;
if (this.defaultPromptText.equals(text)) {
if (isDebugEnabled() && getRequestedLevelL() != 0) {
setSuspended(0, 0, null);
}
if (addToHistory) {
setCurrentPromptL(this.fDefaultPrompt);
return;
}
setCurrentPromptL(new Prompt(this.defaultPromptText, META_HISTORY_DONTADD | META_PROMPT_DEFAULT));
return;
}
else if (this.continuePromptText.equals(text)) {
setCurrentPromptL(new ContinuePrompt(
this.fCurrentPrompt, this.fCurrentInput+this.fLineSeparator, this.continuePromptText,
addToHistory ? 0 : META_HISTORY_DONTADD));
return;
}
else if (text != null) {
if (isDebugEnabled() && text.startsWith("Browse[") && text.endsWith("]> ")) { //$NON-NLS-1$ //$NON-NLS-2$
this.callStack= null;
setSuspended(getBrowserLevel(text),
(hit != null) ? DebugEvent.BREAKPOINT : 0,
(hit != null) ? this.breakpointAdapter.toEclipseData(hit) : null );
setCurrentPromptL(new Prompt(text, addToHistory ? (META_PROMPT_SUSPENDED) :
(META_PROMPT_SUSPENDED | META_HISTORY_DONTADD)));
return;
}
setCurrentPromptL(new Prompt(text, addToHistory ? 0 : META_HISTORY_DONTADD));
return;
}
else { // TODO log warning / exception?
setCurrentPromptL(new Prompt("", addToHistory ? 0 : META_HISTORY_DONTADD)); //$NON-NLS-1$
return;
}
}
private int getBrowserLevel(final String prompt) {
return Integer.parseInt(prompt.substring(7, prompt.indexOf(']')));
}
@Override
protected boolean runConsoleCommandInSuspend(final String input) {
final ToolStreamProxy streams= getStreams();
if ((getPrompt().meta & META_PROMPT_SUSPENDED) != 0) {
final String trimmed= input.trim();
if (trimmed.isEmpty()) {
streams.getOutputStreamMonitor().append(this.fLineSeparator, SubmitType.TOOLS, 0);
// revert counter?
return false;
}
else if (trimmed.length() == 1) {
try {
switch(trimmed.charAt(0)) {
case 'Q':
debugCancel();
return false;
case 'c':
if (exec(new DbgRequest.Resume())) {
return false;
}
break;
case 'n':
if (exec(new DbgRequest.StepOver())) {
return false;
}
break;
case 's':
if (exec(new DbgRequest.StepInto())) {
return false;
}
break;
default:
break;
}
}
catch (final CoreException e) {
RConsoleCorePlugin.log(new Status(IStatus.INFO, RConsoleCorePlugin.PLUGIN_ID, 0,
"An error occurred when executing debug request in the R engine.", e ));
return false;
}
}
}
return true;
}
public void debugSuspend() {
synchronized (this.suspendRunnable) {
if (this.suspendScheduled) {
return;
}
this.suspendScheduled= true;
}
getQueue().addHot(this.suspendRunnable);
}
public boolean exec(final DbgRequest request) throws CoreException {
class DbgRequestResumeRunnable<R extends DbgRequest> extends SuspendResumeRunnable {
public DbgRequestResumeRunnable(final String id, final String label) {
super(id, label, RDbg.getResumeEventDetail(request.getOp()));
}
protected DbgRequest check(final R request, final IProgressMonitor monitor) {
return request;
}
@Override
public void run(final IToolService adapter,
final IProgressMonitor monitor) throws CoreException {
if ((getPrompt().meta & META_PROMPT_SUSPENDED) == 0) {
return;
}
final DbgRequest checkedRequest= check((R) request, monitor);
if (checkedRequest == null) {
return;
}
final CtrlReport report= AbstractRDbgController.this.doExec(checkedRequest, monitor);
if (!report.isEngineSuspended()) {
super.run(adapter, monitor);
submitToConsole(getResumeRCommand(report.getOp()), null, monitor);
setDetail(RDbg.getResumeEventDetail(report.getOp()));
}
}
@Override
protected void doExec(final IProgressMonitor monitor) throws CoreException {
briefChanged(IRConsoleService.AUTO_CHANGE);
}
protected String getResumeRCommand(final byte op) {
switch (op) {
case DbgRequest.RESUME:
return "c"; //$NON-NLS-1$
case DbgRequest.STEP_INTO:
return "s"; //$NON-NLS-1$
case DbgRequest.STEP_OVER:
return "n"; //$NON-NLS-1$
case DbgRequest.STEP_RETURN:
default:
return "c"; //$NON-NLS-1$
}
}
}
switch (request.getOp()) {
case DbgRequest.RESUME:
scheduleSuspendExitRunnable(new DbgRequestResumeRunnable<DbgRequest.Resume>(
RESUME_TYPE_ID, "Resume" ) {
@Override
protected void doExec(final IProgressMonitor monitor) throws CoreException {
super.doExec(monitor);
AbstractRDbgController.this.topLevelBrowserEnabled= false;
}
});
return true;
case DbgRequest.STEP_OVER:
scheduleSuspendExitRunnable(new DbgRequestResumeRunnable<DbgRequest.StepOver>(
STEP_OVER_TYPE_ID, "Step Over" ));
return true;
case DbgRequest.STEP_INTO:
if ((getPlatform().getRVersion().compareTo(new Version(3, 1, 0)) < 0)) {
return false;
}
scheduleSuspendExitRunnable(new DbgRequestResumeRunnable<DbgRequest.StepInto>(
STEP_INTO_TYPE_ID, "Step Into" ));
return true;
case DbgRequest.STEP_RETURN:
scheduleSuspendExitRunnable(new DbgRequestResumeRunnable<DbgRequest.StepReturn>(
STEP_RETURN_TYPE_ID, "Step Return" ) {
private Frame targetFrame;
@Override
protected DbgRequest check(final DbgRequest.StepReturn request, final IProgressMonitor monitor) {
final CallStack callStack= getCallStack(monitor);
if (request.getTarget() instanceof FrameRef.ByPosition) {
final int targetPosition= ((FrameRef.ByPosition) request.getTarget()).getPosition();
final int n= callStack.getFrames().size();
if (targetPosition >= 0 && targetPosition < n - 1) {
this.targetFrame= callStack.getFrames().get(targetPosition);
}
}
else if (request.getTarget() instanceof FrameRef.ByHandle) {
final long targetHandle= ((FrameRef.ByHandle) request.getTarget()).getHandle();
this.targetFrame= callStack.findFrame(targetHandle);
}
return (this.targetFrame != null) ?
new DbgRequest.StepReturn(new FrameRef.ByHandle(this.targetFrame.getHandle())) :
null;
}
@Override
protected void doExec(final IProgressMonitor monitor) throws CoreException {
super.doExec(monitor);
// if (targetPosition == 0) {
// fTopLevelBrowserAction= TOPLEVELBROWSER_ENABLE_COMMANDS;
// }
}
});
return true;
default:
throw new UnsupportedOperationException(request.toString());
}
}
public void debugStepInto(final int position, final String fRefCode) throws CoreException {
scheduleSuspendExitRunnable(new SuspendResumeRunnable(STEP_INTO_TYPE_ID,
"Step Into", DebugEvent.STEP_OVER) {
@Override
protected boolean canExec(final IProgressMonitor monitor) throws CoreException {
if ((getPrompt().meta & META_PROMPT_SUSPENDED) != 0) {
final CallStack stack= getCallStack(monitor);
if (stack != null) {
final int n= stack.getFrames().size();
if (n == 0 || position > n) {
return false;
}
final int pos= (position >= 0) ? position : stack.getFrames().size() - 1;
try {
final SetDebugReport report= AbstractRDbgController.this.doExec(
new SetDebugRequest(pos, fRefCode, true, true), monitor);
return (report != null);
}
catch (final Exception e) {
RConsoleCorePlugin.log(new Status(IStatus.INFO, RConsoleCorePlugin.PLUGIN_ID, 0,
"A problem occurred when stepping into the specified function call: " +
"Could not prepare debug for '"+fRefCode+"'.", e ));
return false;
}
}
}
return false;
}
@Override
protected void doExec(final IProgressMonitor monitor) throws CoreException {
briefChanged(IRConsoleService.AUTO_CHANGE);
submitToConsole("c", "c", monitor); //$NON-NLS-1$ //$NON-NLS-2$
return;
}
});
}
public void debugCancel() throws CoreException {
scheduleSuspendExitRunnable(new SuspendResumeRunnable(RESUME_TYPE_ID,
"Cancel", DebugEvent.CLIENT_REQUEST) {
@Override
protected boolean canExec(final IProgressMonitor monitor) throws CoreException {
return ((getPrompt().meta & META_PROMPT_SUSPENDED) != 0);
}
@Override
protected void doExec(final IProgressMonitor monitor) throws CoreException {
briefChanged(IRConsoleService.AUTO_CHANGE);
AbstractRDbgController.this.topLevelBrowserEnabled= false;
AbstractRDbgController.this.topLevelBrowserAction= TOPLEVELBROWSER_CHECK_SUBMIT;
submitToConsole("Q", "Q", monitor); //$NON-NLS-1$ //$NON-NLS-2$
}
});
}
@Override
protected QuitRunnable createQuitRunnable() {
return new QuitRunnable() {
@Override
protected void doExec(final IProgressMonitor monitor) throws CoreException {
if ((getPrompt().meta & META_PROMPT_SUSPENDED) != 0) {
briefChanged(IRConsoleService.AUTO_CHANGE);
AbstractRDbgController.this.topLevelBrowserEnabled= false;
AbstractRDbgController.this.topLevelBrowserAction= TOPLEVELBROWSER_CHECK_SUBMIT;
submitToConsole("Q", "Q", monitor); //$NON-NLS-1$ //$NON-NLS-2$
}
// getQueue().add(createQuitRunnable());
}
};
}
@Override
protected void doQuitL(final IProgressMonitor monitor) throws CoreException {
if ((getPrompt().meta & META_PROMPT_SUSPENDED) == 0) {
super.doQuitL(monitor);
}
}
@Override
protected void runSuspendedLoopL(final int o) {
if (this.topLevelBrowserAction == TOPLEVELBROWSER_CHECK_SUBMIT) {
this.topLevelBrowserAction= 0;
}
removePostControllerRunnable(this.fTopLevelBrowserRunnable);
super.runSuspendedLoopL(o);
if (getCurrentLevelL() == 0) {
if (this.topLevelBrowserAction == 0) {
this.topLevelBrowserAction= TOPLEVELBROWSER_CHECK_SUBMIT;
}
addPostControllerRunnable(this.fTopLevelBrowserRunnable);
}
}
public CallStack getCallStack(final IProgressMonitor monitor) {
if (this.callStack == null || this.callStackStamp != getChangeStamp()) {
this.callStackStamp= getChangeStamp();
try {
this.callStack= doEvalCallStack(monitor);
}
catch (final Exception e) {
this.callStack= null;
RConsoleCorePlugin.log(new Status(IStatus.ERROR, RConsoleCorePlugin.PLUGIN_ID, 0,
"An error occurred when loading the R call stack.", e ));
}
}
return this.callStack;
}
public FrameContext evalFrameContext(final int position, final IProgressMonitor monitor) throws CoreException {
try {
return doEvalFrameContext(position, monitor);
}
catch (final Exception e) {
throw new CoreException(new Status(IStatus.ERROR, RConsoleCorePlugin.PLUGIN_ID, 0,
NLS.bind("An error occurred when loading detail of R stack frame {0}.", position),
e ));
}
}
public abstract void exec(DbgEnablement request) throws CoreException;
public abstract void exec(DbgFilterState request) throws CoreException;
public abstract void exec(TracepointStatesUpdate request) throws CoreException;
public abstract void exec(TracepointStatesUpdate request,
IProgressMonitor monitor) throws CoreException;
public abstract TracepointInstallationReport exec(
TracepointInstallationRequest request,
IProgressMonitor monitor) throws CoreException;
@Override
public Set<Long> getLazyEnvironments(final IProgressMonitor monitor) {
Set<Long> list= super.getLazyEnvironments(monitor);
if (isSuspendedL()) {
final CallStack stack= getCallStack(monitor);
if (stack != null) {
final List<? extends Frame> frames= stack.getFrames();
if (list == null) {
list= new HashSet<>(frames.size());
}
for (int i= 0; i < frames.size(); i++) {
final long handle= frames.get(i).getHandle();
if (handle != 0) {
list.add(Long.valueOf(handle));
}
}
}
}
return list;
}
protected CallStack doEvalCallStack(final IProgressMonitor monitor) throws CoreException {
return null;
}
protected FrameContext doEvalFrameContext(final int position,
final IProgressMonitor monitor) throws Exception {
return null;
}
public void initTopLevelBrowser(final IProgressMonitor monitor) throws CoreException {
if ((this.fCurrentPrompt.meta & META_PROMPT_DEFAULT) == 0) {
return;
}
if (this.topLevelBrowserAction != TOPLEVELBROWSER_CHECK_SUSPENDED) {
this.topLevelBrowserAction= TOPLEVELBROWSER_CHECK_SUBMIT;
}
setDebugBrowser(TOPLEVEL_ENV_FRAME, true, false, monitor);
// fStepFilterAction= STEPFILTER_STEP1;
// submitCommandToConsole(new String[] { "browser(skipCalls= 3L)" }, null, monitor);
}
private void checkInit(final IProgressMonitor monitor) throws CoreException {
if (this.globalEnv == null) {
try {
this.globalEnv= RDataUtil.checkRReference(
evalData(".GlobalEnv", null, 0, DEPTH_REFERENCE, monitor) ); //$NON-NLS-1$
}
catch (final UnexpectedRDataException e) {
throw new CoreException(new Status(IStatus.ERROR, RConsoleCorePlugin.PLUGIN_ID, 0,
"Init debug data failed.", e));
}
}
}
protected boolean setDebugBrowser(final RReference environment, final boolean enable,
final boolean temp,
final IProgressMonitor monitor) throws CoreException {
checkInit(monitor);
if (environment == TOPLEVEL_ENV_FRAME || environment.getHandle() == this.globalEnv.getHandle()) {
this.topLevelBrowserEnabled= enable;
if (enable) {
if (this.topLevelBrowserAction == 0) {
this.topLevelBrowserAction= TOPLEVELBROWSER_CHECK_SUBMIT;
}
}
else {
if (this.topLevelBrowserAction != TOPLEVELBROWSER_ENABLE_COMMANDS) {
this.topLevelBrowserAction= 0;
}
}
}
try {
final SetDebugReport report= doExec(
new SetDebugRequest(environment.getHandle(), enable, temp), monitor );
return (report != null && report.isChanged());
}
catch (final CoreException e) {
throw e;
}
catch (final Exception e) {
throw new CoreException(new Status(IStatus.ERROR, RConsoleCorePlugin.PLUGIN_ID, -1,
"An error occurred when changing the R debug browser state.", e));
}
}
protected SetDebugReport doExec(final SetDebugRequest request,
final IProgressMonitor monitor) throws CoreException {
return null;
}
protected boolean canSuspend(final IProgressMonitor monitor) {
return true;
}
protected void doRequestSuspend(final IProgressMonitor monitor) throws CoreException {
}
protected void handle(final TracepointEvent event) {
if (event.getKind() == TracepointEvent.KIND_ABOUT_TO_HIT) {
this.breakpointHit= event;
}
}
protected CtrlReport doExec(final DbgRequest request,
final IProgressMonitor monitor) throws CoreException {
return null;
}
@Override
public boolean acceptNewConsoleCommand() {
return ((this.fCurrentPrompt.meta & (META_PROMPT_DEFAULT | META_PROMPT_SUSPENDED)) != 0);
}
@Override
public void submitToConsole(final String input,
final IProgressMonitor monitor) throws CoreException {
if (input.indexOf('\n') >= 0) {
// TODO progress
final String[] lines= RUtil.LINE_SEPARATOR_PATTERN.split(input);
for (int i= 0; i < lines.length; i++) {
if (this.topLevelBrowserAction != 0 && getCurrentLevelL() == 0 && (this.fCurrentPrompt.meta & META_PROMPT_DEFAULT) != 0) {
this.topLevelBrowserAction= 0;
setDebugBrowser(TOPLEVEL_ENV_FRAME, false, false, monitor);
}
super.submitToConsole(lines[i], monitor);
}
return;
}
if (this.topLevelBrowserAction != 0 && getCurrentLevelL() == 0 && (this.fCurrentPrompt.meta & META_PROMPT_DEFAULT) != 0) {
this.topLevelBrowserAction= 0;
setDebugBrowser(TOPLEVEL_ENV_FRAME, false, false, monitor);
}
super.submitToConsole(input, monitor);
}
@Override
public void submitCommandToConsole(final String[] lines, final IRSrcref srcref,
final IProgressMonitor monitor) throws CoreException {
if (isDebugEnabled() && getCurrentLevelL() == 0
&& (this.fCurrentPrompt.meta & META_PROMPT_DEFAULT) != 0) {
if (this.topLevelBrowserAction == TOPLEVELBROWSER_ENABLE_COMMANDS) {
initTopLevelBrowser(monitor);
}
else if (!this.topLevelBrowserEnabled && srcref instanceof IRModelSrcref
&& this.breakpointAdapter.matchScriptBreakpoint((IRModelSrcref) srcref, monitor) ) {
initTopLevelBrowser(monitor);
}
}
final SrcfileData srcfile= getSrcfile(srcref, monitor);
doSubmitCommandL(lines, srcfile, srcref, monitor);
if (isDebugEnabled() && srcfile != null && srcref instanceof IRModelSrcref) {
final ElementTracepointInstallationRequest breakpointsRequest= this.breakpointAdapter
.getElementTracepoints(srcfile, (IRModelSrcref) srcref, monitor );
if (breakpointsRequest != null) {
this.breakpointAdapter.installElementTracepoints(breakpointsRequest, monitor);
}
}
}
protected void doSubmitCommandL(final String[] lines, final SrcfileData srcfile,
final IRSrcref srcref,
final IProgressMonitor monitor) throws CoreException {
super.submitCommandToConsole(lines, srcref, monitor);
}
@Override
public void submitFileCommandToConsole(final String[] lines, final ISourceUnit su,
final IProgressMonitor monitor) throws CoreException {
if (su == null) {
super.submitFileCommandToConsole(lines, null, monitor);
return;
}
SrcfileData srcfile= getSrcfile(su, monitor);
final ElementTracepointInstallationRequest breakpointsRequest =
(isDebugEnabled() && su instanceof IRWorkspaceSourceUnit) ?
this.breakpointAdapter.prepareFileElementTracepoints(srcfile, (IRSourceUnit) su, monitor ) :
null;
try {
doSubmitFileCommandToConsole(lines, srcfile, su, monitor);
}
finally {
if (breakpointsRequest != null) {
if (srcfile.getTimestamp() != getRTimestamp((IRWorkspaceSourceUnit) su, monitor)) {
srcfile= null;
}
this.breakpointAdapter.finishFileElementTracepoints(srcfile, (IRSourceUnit) su,
breakpointsRequest, monitor );
}
}
}
public void doSubmitFileCommandToConsole(final String[] lines,
final SrcfileData srcfile, final ISourceUnit su,
final IProgressMonitor monitor) throws CoreException {
super.submitFileCommandToConsole(lines, su, monitor);
}
protected SrcfileData getSrcfile(final IRSrcref srcref,
final IProgressMonitor monitor) throws CoreException {
if (srcref instanceof IRModelSrcref) {
return getSrcfile(((IRModelSrcref) srcref).getFile(), monitor);
}
return null;
}
private long getRTimestamp(final IWorkspaceSourceUnit su, final IProgressMonitor monitor) {
return (su.getWorkingContext() == LTK.PERSISTENCE_CONTEXT) ?
su.getResource().getLocalTimeStamp()/1000 :
RDbg.getTimestamp(su, monitor);
}
protected SrcfileData getSrcfile(final ISourceUnit su,
final IProgressMonitor monitor) throws CoreException {
String fileName= null;
if (su != null && su.getResource() != null) {
URI uri= null;
final FileUtil fileUtil= FileUtil.getFileUtil(su.getResource());
if (fileUtil != null) {
uri= fileUtil.getURI();
}
if (uri != null) {
fileName= uri.toString();
try {
final IFileStore store= EFS.getStore(uri);
if (store != null) {
fileName= getWorkspaceData().toToolPath(store);
}
}
catch (final CoreException e) {
}
}
if (fileName == null) {
return null;
}
if (su instanceof IWorkspaceSourceUnit) {
final IWorkspaceSourceUnit wsu= (IWorkspaceSourceUnit) su;
final IPath path= wsu.getResource().getFullPath();
prepareSrcfile(fileName, path, monitor);
return new SrcfileData(
(this.lastSrcfile == fileName) ? this.lastSrcfilePath : path.toPortableString(),
fileName, getRTimestamp(wsu, monitor) );
}
else {
return new SrcfileData(null, fileName, RDbg.getTimestamp(su, monitor));
}
}
return null;
}
private void prepareSrcfile(final String srcfile, final IPath path,
final IProgressMonitor monitor) {
try {
if (srcfile == null || path == null) {
return;
}
final String statetPath= path.toPortableString();
if (!srcfile.equals(this.lastSrcfile) || !statetPath.equals(this.lastSrcfilePath) ) {
doPrepareSrcfile(srcfile, statetPath, monitor);
}
this.lastSrcfile= srcfile;
this.lastSrcfilePath= statetPath;
}
catch (final Exception e) {
this.lastSrcfile= null;
this.lastSrcfilePath= null;
RConsoleCorePlugin.log(new Status(IStatus.ERROR, RConsoleCorePlugin.PLUGIN_ID, 0,
"An error occurred when preparing srcfile information in R." , e ));
}
}
protected void doPrepareSrcfile(final String srcfile, final String statetPath,
final IProgressMonitor monitor) throws Exception {
}
}