/******************************************************************************* * Copyright (c) 2000, 2006 IBM Corporation 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.rubypeople.rdt.internal.ui.rubyeditor; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.TextSelection; import org.jruby.ast.MethodDefNode; import org.jruby.ast.Node; import org.jruby.ast.RootNode; import org.rubypeople.rdt.core.IRubyElement; import org.rubypeople.rdt.core.IRubyScript; import org.rubypeople.rdt.core.RubyModelException; import org.rubypeople.rdt.internal.corext.dom.Selection; import org.rubypeople.rdt.internal.corext.dom.SelectionAnalyzer; import org.rubypeople.rdt.internal.ti.util.ClosestSpanningNodeLocator; import org.rubypeople.rdt.internal.ti.util.INodeAcceptor; import org.rubypeople.rdt.internal.ui.RubyPlugin; import org.rubypeople.rdt.internal.ui.actions.SelectionConverter; /** * A special text selection that gives access to the resolved and * enclosing element. */ public class RubyTextSelection extends TextSelection { private IRubyElement fElement; private IRubyElement[] fResolvedElements; private boolean fEnclosingElementRequested; private IRubyElement fEnclosingElement; private boolean fPartialASTRequested; private RootNode fPartialAST; private boolean fNodesRequested; private Node[] fSelectedNodes; private Node fCoveringNode; private boolean fInMethodBodyRequested; private boolean fInMethodBody; /** * Creates a new text selection at the given offset and length. */ public RubyTextSelection(IRubyElement element, IDocument document, int offset, int length) { super(document, offset, length); fElement= element; } /** * Resolves the <code>IRubyElement</code>s at the current offset. Returns * an empty array if the string under the offset doesn't resolve to a * <code>IRubyElement</code>. * * @return the resolved ruby elements at the current offset * @throws RubyModelException passed from the underlying code resolve API */ public IRubyElement[] resolveElementAtOffset() throws RubyModelException { if (fResolvedElements != null) return fResolvedElements; // long start= System.currentTimeMillis(); fResolvedElements= SelectionConverter.codeResolve(fElement, this); // System.out.println("Time resolving element: " + (System.currentTimeMillis() - start)); return fResolvedElements; } public IRubyElement resolveEnclosingElement() throws RubyModelException { if (fEnclosingElementRequested) return fEnclosingElement; fEnclosingElementRequested= true; fEnclosingElement= SelectionConverter.resolveEnclosingElement(fElement, this); return fEnclosingElement; } public RootNode resolvePartialAstAtOffset() { if (fPartialASTRequested) return fPartialAST; fPartialASTRequested= true; if (! (fElement instanceof IRubyScript)) return null; // long start= System.currentTimeMillis(); fPartialAST= (RootNode) RubyPlugin.getDefault().getASTProvider().getAST(fElement, ASTProvider.WAIT_YES, null); // System.out.println("Time requesting partial AST: " + (System.currentTimeMillis() - start)); return fPartialAST; } public Node[] resolveSelectedNodes() { if (fNodesRequested) return fSelectedNodes; fNodesRequested= true; RootNode root= resolvePartialAstAtOffset(); if (root == null) return null; Selection ds= Selection.createFromStartLength(getOffset(), getLength()); SelectionAnalyzer analyzer= new SelectionAnalyzer(ds, false); root.accept(analyzer); fSelectedNodes= analyzer.getSelectedNodes(); fCoveringNode= analyzer.getLastCoveringNode(); return fSelectedNodes; } public Node resolveCoveringNode() { if (fNodesRequested) return fCoveringNode; resolveSelectedNodes(); return fCoveringNode; } public boolean resolveInMethodBody() { if (fInMethodBodyRequested) return fInMethodBody; fInMethodBodyRequested= true; resolveSelectedNodes(); Node node= getStartNode(); if (node == null) { fInMethodBody= true; } else { Node spanner = ClosestSpanningNodeLocator.Instance().findClosestSpanner(resolvePartialAstAtOffset(), node.getPosition().getStartOffset(), new INodeAcceptor() { public boolean doesAccept(Node node) { return node instanceof MethodDefNode; } }); if (spanner != null) fInMethodBody = true; } return fInMethodBody; } private Node getStartNode() { if (fSelectedNodes != null && fSelectedNodes.length > 0) return fSelectedNodes[0]; else return fCoveringNode; } }