/*=============================================================================# # Copyright (c) 2009-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.internal.debug.ui.actions; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugException; import org.eclipse.jface.text.AbstractDocument; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITypedRegion; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.TextUtilities; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.statushandlers.StatusManager; import de.walware.jcommons.collections.ImList; import de.walware.ecommons.ltk.AstInfo; import de.walware.ecommons.ltk.ast.AstSelection; import de.walware.ecommons.ltk.ast.IAstNode; import de.walware.ecommons.ltk.core.model.ISourceUnit; import de.walware.ecommons.ltk.ui.sourceediting.ISourceEditor; import de.walware.ecommons.workbench.ui.WorkbenchUIUtil; import de.walware.statet.r.core.model.IRModelInfo; import de.walware.statet.r.core.model.IRModelManager; import de.walware.statet.r.core.model.IRSourceUnit; import de.walware.statet.r.core.model.RElementAccess; import de.walware.statet.r.core.model.RModel; import de.walware.statet.r.core.rlang.RTokens; import de.walware.statet.r.core.rsource.ast.NodeType; import de.walware.statet.r.core.rsource.ast.RAstNode; import de.walware.statet.r.core.source.IRDocumentConstants; import de.walware.statet.r.debug.core.IRStackFrame; import de.walware.statet.r.internal.debug.ui.RDebugUIPlugin; import de.walware.statet.r.internal.debug.ui.RDebugUIUtils; import de.walware.statet.r.nico.AbstractRDbgController; public class StepIntoSelectionHandler extends AbstractHandler { public static RElementAccess searchAccess(final ISourceEditor editor, final IRegion region) { try { final IDocument document = editor.getViewer().getDocument(); final ITypedRegion partition = TextUtilities.getPartition(document, editor.getDocumentContentInfo().getPartitioning(), region.getOffset(), false ); final ISourceUnit su = editor.getSourceUnit(); if (su instanceof IRSourceUnit && region.getOffset() < document.getLength() && ( (IRDocumentConstants.R_DEFAULT_CONTENT_CONSTRAINT.matches(partition.getType()) && !RTokens.isRobustSeparator(document.getChar(region.getOffset()), false) ) || partition.getType() == IRDocumentConstants.R_QUOTED_SYMBOL_CONTENT_TYPE || partition.getType() == IRDocumentConstants.R_STRING_CONTENT_TYPE )) { final IRModelInfo info = (IRModelInfo) su.getModelInfo(RModel.TYPE_ID, IRModelManager.MODEL_FILE, new NullProgressMonitor()); if (info != null) { final AstInfo astInfo = info.getAst(); final AstSelection selection = AstSelection.search(astInfo.root, region.getOffset(), region.getOffset()+region.getLength(), AstSelection.MODE_COVERING_SAME_LAST ); final IAstNode covering = selection.getCovering(); if (covering instanceof RAstNode) { final RAstNode node = (RAstNode) covering; RAstNode current = node; do { final ImList<Object> attachments= current.getAttachments(); for (final Object attachment : attachments) { if (attachment instanceof RElementAccess) { final RElementAccess access= (RElementAccess) attachment; if (access.isFunctionAccess() && access.isCallAccess()) { if (isChild(node, access.getNode())) { return access; } return null; } } } current = current.getRParent(); } while (current != null); } } } } catch (final BadLocationException e) { } return null; } private static boolean isChild(RAstNode child, final RAstNode parent) { do { if (child == parent) { return true; } child = child.getRParent(); } while (child != null); return false; } public static void exec(final AbstractRDbgController controller, final AbstractDocument document, final RElementAccess access, final IWorkbenchPart part) { try { final RAstNode nameNode = access.getNameNode(); String code; switch (nameNode.getNodeType()) { case STRING_CONST: case SYMBOL: code = access.getSegmentName(); if (access.getNode().getNodeType() == NodeType.F_CALL) { code = "`" + code + "`"; //$NON-NLS-1$ //$NON-NLS-2$ } else { code = "get('" + code + "')"; //$NON-NLS-1$ //$NON-NLS-2$ } break; default: code = document.get(nameNode.getOffset(), nameNode.getLength()); break; } if (code != null && code.length() > 0) { final IRStackFrame frame = RDebugUIUtils.getFrame(part, controller.getTool()); controller.debugStepInto((frame != null) ? frame.getPosition() : -1, code); } } catch (final BadLocationException e) {} catch (final CoreException e) { StatusManager.getManager().handle(new Status(IStatus.ERROR, RDebugUIPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "An error occurred when executing debug request in the R engine.", e ), StatusManager.LOG ); } } public StepIntoSelectionHandler() { } @Override public Object execute(final ExecutionEvent event) throws ExecutionException { final IWorkbenchPart activePart = WorkbenchUIUtil.getActivePart(event.getApplicationContext()); final ISourceEditor editor = (ISourceEditor) activePart.getAdapter(ISourceEditor.class); if (editor == null) { return null; } final AbstractRDbgController controller = RDebugUIUtils.getRDbgController(editor); if (controller == null) { return null; } final ITextSelection selection = (ITextSelection) editor.getViewer().getSelection(); final RElementAccess access = searchAccess(editor, new Region(selection.getOffset(), selection.getLength()) ); if (access != null) { exec(controller, (AbstractDocument) editor.getViewer().getDocument(), access, activePart); return null; } Display.getCurrent().beep(); return null; } }