blob: 4667c3809eb5ef0838746d69da444e4b2e9f7ff9 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2010, 2021 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.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.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.osgi.util.NLS;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.status.ErrorStatus;
import org.eclipse.statet.jcommons.status.ProgressMonitor;
import org.eclipse.statet.jcommons.status.StatusException;
import org.eclipse.statet.jcommons.ts.core.SystemRunnable;
import org.eclipse.statet.jcommons.ts.core.Tool;
import org.eclipse.statet.jcommons.ts.core.ToolRunnable;
import org.eclipse.statet.jcommons.ts.core.ToolService;
import org.eclipse.statet.ecommons.io.FileUtil;
import org.eclipse.statet.internal.r.console.core.RConsoleCorePlugin;
import org.eclipse.statet.ltk.core.Ltk;
import org.eclipse.statet.ltk.model.core.element.SourceUnit;
import org.eclipse.statet.ltk.model.core.element.WorkspaceSourceUnit;
import org.eclipse.statet.nico.core.runtime.Prompt;
import org.eclipse.statet.nico.core.runtime.SubmitType;
import org.eclipse.statet.nico.core.runtime.ToolStatus;
import org.eclipse.statet.nico.core.runtime.ToolStreamProxy;
import org.eclipse.statet.r.console.core.AbstractRController;
import org.eclipse.statet.r.console.core.ContinuePrompt;
import org.eclipse.statet.r.console.core.IRDataAdapter;
import org.eclipse.statet.r.console.core.RDbg;
import org.eclipse.statet.r.console.core.RProcess;
import org.eclipse.statet.r.core.RUtil;
import org.eclipse.statet.r.core.model.RSourceUnit;
import org.eclipse.statet.r.core.model.RWorkspaceSourceUnit;
import org.eclipse.statet.r.core.tool.IRConsoleService;
import org.eclipse.statet.rj.data.RDataUtils;
import org.eclipse.statet.rj.data.RObject;
import org.eclipse.statet.rj.data.RReference;
import org.eclipse.statet.rj.data.UnexpectedRDataException;
import org.eclipse.statet.rj.data.impl.RReferenceImpl;
import org.eclipse.statet.rj.server.dbg.CallStack;
import org.eclipse.statet.rj.server.dbg.CtrlReport;
import org.eclipse.statet.rj.server.dbg.DbgEnablement;
import org.eclipse.statet.rj.server.dbg.DbgFilterState;
import org.eclipse.statet.rj.server.dbg.DbgRequest;
import org.eclipse.statet.rj.server.dbg.ElementTracepointInstallationRequest;
import org.eclipse.statet.rj.server.dbg.Frame;
import org.eclipse.statet.rj.server.dbg.FrameContext;
import org.eclipse.statet.rj.server.dbg.FrameRef;
import org.eclipse.statet.rj.server.dbg.SetDebugReport;
import org.eclipse.statet.rj.server.dbg.SetDebugRequest;
import org.eclipse.statet.rj.server.dbg.SrcfileData;
import org.eclipse.statet.rj.server.dbg.TracepointEvent;
import org.eclipse.statet.rj.server.dbg.TracepointInstallationRequest;
import org.eclipse.statet.rj.server.dbg.TracepointStatesUpdate;
import org.eclipse.statet.rj.services.RVersion;
/**
* For implementations supporting debug features
*/
public abstract class AbstractRDbgController extends AbstractRController
implements IRDataAdapter, ICombinedRDataAdapter {
@NonNullByDefault
public interface IRControllerTracepointAdapter {
void handle(final TracepointEvent event);
boolean matchScriptBreakpoint(IRModelSrcref srcref,
final ProgressMonitor m );
@Nullable ElementTracepointInstallationRequest getElementTracepoints(
SrcfileData srcfile, IRModelSrcref su,
final ProgressMonitor m );
@Nullable ElementTracepointInstallationRequest prepareFileElementTracepoints(
SrcfileData srcfile, RSourceUnit su,
final ProgressMonitor m );
void finishFileElementTracepoints(SrcfileData srcfileData, RSourceUnit su,
ElementTracepointInstallationRequest request,
final ProgressMonitor m );
void installElementTracepoints(ElementTracepointInstallationRequest request,
final ProgressMonitor m );
@Nullable 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_ENVIRONMENT, null);
private IRControllerTracepointAdapter breakpointAdapter;
private CallStack callStack;
private int callStackStamp;
private RReference globalEnv;
private boolean suspendScheduled;
private final ToolRunnable suspendRunnable= new ControllerSystemRunnable(SUSPEND_TYPE_ID,
"Suspend") {
@Override
public boolean changed(final int event, final Tool 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 ToolService service, final ProgressMonitor m) throws StatusException {
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(m);
}
};
private boolean topLevelBrowserEnabled;
private int topLevelBrowserAction;
private final SystemRunnable fTopLevelBrowserRunnable= new ControllerSystemRunnable(
"r/debug", "Debugging") { //$NON-NLS-1$
@Override
public void run(final ToolService service, final ProgressMonitor m) throws StatusException {
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(m);
break;
case TOPLEVELBROWSER_CHECK_SUSPENDED:
if (getQueue().getCurrentSize() > 0) {
AbstractRDbgController.this.topLevelBrowserAction= TOPLEVELBROWSER_CHECK_SUBMIT;
break;
}
setDebugBrowser(TOPLEVEL_ENV_FRAME, false, false, m);
//$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 ProgressMonitor m) 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 connectionInfo the initialization data
* @param enableDebug if debug features should be enabled
*/
public AbstractRDbgController(final RProcess process,
final Map<String, Object> connectionInfo) {
super(process, connectionInfo);
}
public void initDebug(final IRControllerTracepointAdapter breakpointAdapter) {
if (breakpointAdapter == null) {
throw new NullPointerException("breakpointAdapter");
}
setDebugEnabled(true);
this.breakpointAdapter= breakpointAdapter;
class LoadCallstackRunnable extends ControllerSystemRunnable implements SystemRunnable {
public LoadCallstackRunnable() {
super("r/callstack", "Load Callstack"); //$NON-NLS-1$
}
@Override
public void run(final ToolService service,
final ProgressMonitor m) throws StatusException {
getCallStack(m);
}
}
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 StatusException e) {
RConsoleCorePlugin.log(new Status(IStatus.INFO, RConsoleCorePlugin.BUNDLE_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 StatusException {
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 ProgressMonitor m) {
return request;
}
@Override
public void run(final ToolService adapter,
final ProgressMonitor m) throws StatusException {
if ((getPrompt().meta & META_PROMPT_SUSPENDED) == 0) {
return;
}
final DbgRequest checkedRequest= check((R) request, m);
if (checkedRequest == null) {
return;
}
final CtrlReport report= AbstractRDbgController.this.doExec(checkedRequest, m);
if (!report.isEngineSuspended()) {
super.run(adapter, m);
submitToConsole(getResumeRCommand(report.getOp()), null, m);
setDetail(RDbg.getResumeEventDetail(report.getOp()));
}
}
@Override
protected void doExec(final ProgressMonitor m) throws StatusException {
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 ProgressMonitor m) throws StatusException {
super.doExec(m);
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 RVersion(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 ProgressMonitor m) {
final CallStack callStack= getCallStack(m);
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 ProgressMonitor m) throws StatusException {
super.doExec(m);
// 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 StatusException {
scheduleSuspendExitRunnable(new SuspendResumeRunnable(STEP_INTO_TYPE_ID,
"Step Into", DebugEvent.STEP_OVER) {
@Override
protected boolean canExec(final ProgressMonitor m) throws StatusException {
if ((getPrompt().meta & META_PROMPT_SUSPENDED) != 0) {
final CallStack stack= getCallStack(m);
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), m);
return (report != null);
}
catch (final Exception e) {
RConsoleCorePlugin.log(new Status(IStatus.INFO, RConsoleCorePlugin.BUNDLE_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 ProgressMonitor m) throws StatusException {
briefChanged(IRConsoleService.AUTO_CHANGE);
submitToConsole("c", "c", m); //$NON-NLS-1$ //$NON-NLS-2$
return;
}
});
}
public void debugCancel() throws StatusException {
scheduleSuspendExitRunnable(new SuspendResumeRunnable(RESUME_TYPE_ID,
"Cancel", DebugEvent.CLIENT_REQUEST) {
@Override
protected boolean canExec(final ProgressMonitor m) throws StatusException {
return ((getPrompt().meta & META_PROMPT_SUSPENDED) != 0);
}
@Override
protected void doExec(final ProgressMonitor m) throws StatusException {
briefChanged(IRConsoleService.AUTO_CHANGE);
AbstractRDbgController.this.topLevelBrowserEnabled= false;
AbstractRDbgController.this.topLevelBrowserAction= TOPLEVELBROWSER_CHECK_SUBMIT;
submitToConsole("Q", "Q", m); //$NON-NLS-1$ //$NON-NLS-2$
}
});
}
@Override
protected QuitRunnable createQuitRunnable() {
return new QuitRunnable() {
@Override
protected void doExec(final ProgressMonitor m) throws StatusException {
if ((getPrompt().meta & META_PROMPT_SUSPENDED) != 0) {
briefChanged(IRConsoleService.AUTO_CHANGE);
AbstractRDbgController.this.topLevelBrowserEnabled= false;
AbstractRDbgController.this.topLevelBrowserAction= TOPLEVELBROWSER_CHECK_SUBMIT;
submitToConsole("Q", "Q", m); //$NON-NLS-1$ //$NON-NLS-2$
}
// getQueue().add(createQuitRunnable());
}
};
}
@Override
protected void doQuitL(final ProgressMonitor m) throws StatusException {
if ((getPrompt().meta & META_PROMPT_SUSPENDED) == 0) {
super.doQuitL(m);
}
}
@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 ProgressMonitor m) {
if (this.callStack == null || this.callStackStamp != getChangeStamp()) {
this.callStackStamp= getChangeStamp();
try {
this.callStack= doEvalCallStack(m);
}
catch (final Exception e) {
this.callStack= null;
RConsoleCorePlugin.log(new Status(IStatus.ERROR, RConsoleCorePlugin.BUNDLE_ID, 0,
"An error occurred when loading the R call stack.", e ));
}
}
return this.callStack;
}
public FrameContext evalFrameContext(final int position,
final ProgressMonitor m) throws StatusException {
try {
return doEvalFrameContext(position, m);
}
catch (final Exception e) {
throw new StatusException(new ErrorStatus(RConsoleCorePlugin.BUNDLE_ID,
NLS.bind("An error occurred when loading detail of R stack frame {0}.", position),
e ));
}
}
public abstract void exec(DbgEnablement request) throws StatusException;
public abstract void exec(DbgFilterState request) throws StatusException;
public abstract void exec(TracepointStatesUpdate request) throws StatusException;
public abstract void exec(TracepointStatesUpdate request,
final ProgressMonitor m) throws StatusException;
public abstract void exec(TracepointInstallationRequest request,
final ProgressMonitor m) throws StatusException;
@Override
public Set<Long> getLazyEnvironments(final ProgressMonitor m) {
Set<Long> list= super.getLazyEnvironments(m);
if (isSuspendedL()) {
final CallStack stack= getCallStack(m);
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 ProgressMonitor m) throws StatusException {
return null;
}
protected FrameContext doEvalFrameContext(final int position,
final ProgressMonitor m) throws Exception {
return null;
}
public void initTopLevelBrowser(final ProgressMonitor m) throws StatusException {
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, m);
// fStepFilterAction= STEPFILTER_STEP1;
// submitCommandToConsole(new String[] { "browser(skipCalls= 3L)" }, null, monitor);
}
private void checkInit(final ProgressMonitor m) throws StatusException {
if (this.globalEnv == null) {
try {
this.globalEnv= RDataUtils.checkRReference(
evalData(".GlobalEnv", null, 0, DEPTH_REFERENCE, m) ); //$NON-NLS-1$
}
catch (final UnexpectedRDataException e) {
throw new StatusException(new ErrorStatus(RConsoleCorePlugin.BUNDLE_ID,
"Init debug data failed.",
e ));
}
}
}
protected boolean setDebugBrowser(final RReference environment, final boolean enable,
final boolean temp,
final ProgressMonitor m) throws StatusException {
checkInit(m);
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), m );
return (report != null && report.isChanged());
}
catch (final StatusException e) {
throw e;
}
catch (final Exception e) {
throw new StatusException(new ErrorStatus(RConsoleCorePlugin.BUNDLE_ID,
"An error occurred when changing the R debug browser state.",
e ));
}
}
protected SetDebugReport doExec(final SetDebugRequest request,
final ProgressMonitor m) throws StatusException {
return null;
}
protected boolean canSuspend(final ProgressMonitor m) {
return true;
}
protected void doRequestSuspend(final ProgressMonitor m) throws StatusException {
}
protected void handleTracepointEvents(final List<? extends TracepointEvent> events) {
for (final TracepointEvent event : events) {
try {
if (event.getKind() == TracepointEvent.KIND_ABOUT_TO_HIT) {
this.breakpointHit= event;
}
else {
this.breakpointAdapter.handle(event);
}
}
catch (final Exception e) {
}
}
}
protected CtrlReport doExec(final DbgRequest request,
final ProgressMonitor m) throws StatusException {
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 ProgressMonitor m) throws StatusException {
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, m);
}
super.submitToConsole(lines[i], m);
}
return;
}
if (this.topLevelBrowserAction != 0 && getCurrentLevelL() == 0 && (this.fCurrentPrompt.meta & META_PROMPT_DEFAULT) != 0) {
this.topLevelBrowserAction= 0;
setDebugBrowser(TOPLEVEL_ENV_FRAME, false, false, m);
}
super.submitToConsole(input, m);
}
@Override
public void submitCommandToConsole(final String[] lines, final IRSrcref srcref,
final ProgressMonitor m) throws StatusException {
if (isDebugEnabled() && getCurrentLevelL() == 0
&& (this.fCurrentPrompt.meta & META_PROMPT_DEFAULT) != 0) {
if (this.topLevelBrowserAction == TOPLEVELBROWSER_ENABLE_COMMANDS) {
initTopLevelBrowser(m);
}
else if (!this.topLevelBrowserEnabled && srcref instanceof IRModelSrcref
&& this.breakpointAdapter.matchScriptBreakpoint((IRModelSrcref) srcref, m) ) {
initTopLevelBrowser(m);
}
}
final SrcfileData srcfile= getSrcfile(srcref, m);
doSubmitCommandL(lines, srcfile, srcref, m);
if (isDebugEnabled() && srcfile != null && srcref instanceof IRModelSrcref) {
final ElementTracepointInstallationRequest breakpointsRequest= this.breakpointAdapter
.getElementTracepoints(srcfile, (IRModelSrcref) srcref, m );
if (breakpointsRequest != null) {
this.breakpointAdapter.installElementTracepoints(breakpointsRequest, m);
}
}
}
protected void doSubmitCommandL(final String[] lines, final SrcfileData srcfile,
final IRSrcref srcref,
final ProgressMonitor m) throws StatusException {
super.submitCommandToConsole(lines, srcref, m);
}
@Override
public void submitFileCommandToConsole(final String[] lines, final SourceUnit su,
final ProgressMonitor m) throws StatusException {
if (su == null) {
super.submitFileCommandToConsole(lines, null, m);
return;
}
SrcfileData srcfile= getSrcfile(su, m);
final ElementTracepointInstallationRequest breakpointsRequest =
(isDebugEnabled() && su instanceof RWorkspaceSourceUnit) ?
this.breakpointAdapter.prepareFileElementTracepoints(srcfile, (RSourceUnit) su, m ) :
null;
try {
doSubmitFileCommandToConsole(lines, srcfile, su, m);
}
finally {
if (breakpointsRequest != null) {
if (srcfile.getTimestamp() != getTimestamp((RWorkspaceSourceUnit) su, m)) {
srcfile= null;
}
this.breakpointAdapter.finishFileElementTracepoints(srcfile, (RSourceUnit) su,
breakpointsRequest, m );
}
}
}
public void doSubmitFileCommandToConsole(final String[] lines,
final SrcfileData srcfile, final SourceUnit su,
final ProgressMonitor m) throws StatusException {
super.submitFileCommandToConsole(lines, su, m);
}
protected SrcfileData getSrcfile(final IRSrcref srcref,
final ProgressMonitor m) throws StatusException {
if (srcref instanceof IRModelSrcref) {
return getSrcfile(((IRModelSrcref) srcref).getFile(), m);
}
return null;
}
private long getTimestamp(final WorkspaceSourceUnit su, final ProgressMonitor m) {
return (su.getWorkingContext() == Ltk.PERSISTENCE_CONTEXT) ?
su.getResource().getLocalTimeStamp() :
RDbg.getTimestamp(su, m);
}
protected SrcfileData getSrcfile(final SourceUnit su,
final ProgressMonitor m) throws StatusException {
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 | StatusException e) {
}
}
if (fileName == null) {
return null;
}
if (su instanceof WorkspaceSourceUnit) {
final WorkspaceSourceUnit wsu= (WorkspaceSourceUnit) su;
final IPath path= wsu.getResource().getFullPath();
prepareSrcfile(fileName, path, m);
return new SrcfileData(
(this.lastSrcfile == fileName) ? this.lastSrcfilePath : path.toPortableString(),
fileName, getTimestamp(wsu, m) );
}
else {
return new SrcfileData(null, fileName, RDbg.getTimestamp(su, m));
}
}
return null;
}
private void prepareSrcfile(final String srcfile, final IPath path, final ProgressMonitor m) {
try {
if (srcfile == null || path == null) {
return;
}
final String statetPath= path.toPortableString();
if (!srcfile.equals(this.lastSrcfile) || !statetPath.equals(this.lastSrcfilePath) ) {
doPrepareSrcfile(srcfile, statetPath, m);
}
this.lastSrcfile= srcfile;
this.lastSrcfilePath= statetPath;
}
catch (final Exception e) {
this.lastSrcfile= null;
this.lastSrcfilePath= null;
RConsoleCorePlugin.log(new Status(IStatus.ERROR, RConsoleCorePlugin.BUNDLE_ID, 0,
"An error occurred when preparing srcfile information in R." , e ));
}
}
protected void doPrepareSrcfile(final String srcfile, final String statetPath,
final ProgressMonitor m) throws Exception {
}
}