/*
* Copyright (c) 2013, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.tools.ui.internal.actions;
import com.google.dart.engine.ast.AstNode;
import com.google.dart.engine.ast.ClassDeclaration;
import com.google.dart.engine.ast.CompilationUnit;
import com.google.dart.engine.ast.ConstructorDeclaration;
import com.google.dart.engine.ast.FieldDeclaration;
import com.google.dart.engine.ast.FunctionDeclaration;
import com.google.dart.engine.ast.MethodDeclaration;
import com.google.dart.engine.ast.NodeList;
import com.google.dart.engine.ast.VariableDeclaration;
import com.google.dart.engine.ast.visitor.ElementLocator;
import com.google.dart.engine.ast.visitor.GeneralizingAstVisitor;
import com.google.dart.engine.ast.visitor.NodeLocator;
import com.google.dart.engine.element.Element;
import com.google.dart.engine.services.assist.AssistContext;
import com.google.dart.tools.core.DartCore;
import com.google.dart.tools.ui.internal.text.editor.DartEditor;
import org.dartlang.analysis.server.protocol.NavigationRegion;
import org.dartlang.analysis.server.protocol.NavigationTarget;
import org.eclipse.jface.text.ITextSelection;
import java.util.List;
/**
* To replace {@link SelectionConverter}.
*/
public class NewSelectionConverter {
/**
* Get the element associated with the editor's current selection.
*
* @param editor the editor
* @return the associated element, or {@code null} if none can be found
*/
public static Element getElementAtOffset(DartEditor editor) {
AssistContext context = editor.getAssistContext();
if (context == null) {
return null;
}
return context.getCoveredElement();
}
/**
* Get the element associated with the selected portion of the given input element.
*
* @param editor the editor
* @param caret the caret position in the editor
* @return the associated element
*/
public static Element getElementAtOffset(DartEditor editor, int caret) {
AstNode node = getNodeAtOffset(editor, caret);
if (node == null) {
return null;
}
return ElementLocator.locateWithOffset(node, caret);
}
/**
* Get the element associated with the selected portion of the given input element.
*
* @param editor the editor
* @param offset the beginning of the selection
* @param length the length of the selection
* @return the associated element
*/
public static Element getElementAtOffset(DartEditor editor, int offset, int length) {
CompilationUnit cu = editor.getInputUnit();
AstNode node = new NodeLocator(offset, offset + length).searchWithin(cu);
if (node == null) {
return null;
}
return ElementLocator.locateWithOffset(node, offset);
}
/**
* Get the element associated with the selected portion of the given input element.
*
* @param input the input element
* @param selection the selection
* @return the associated element
*/
public static Element getElementAtOffset(Element input, ITextSelection selection) {
//TODO (pquitslund): parse selection
return input;
}
public static Element getElementEnclosingOffset(CompilationUnit unit, final int offset) {
final Element result[] = new Element[] {null};
unit.accept(new GeneralizingAstVisitor<Void>() {
@Override
public Void visitClassDeclaration(ClassDeclaration node) {
if (isNodeEnclosingOffset(node)) {
result[0] = node.getElement();
return super.visitClassDeclaration(node);
}
return null;
}
@Override
public Void visitConstructorDeclaration(ConstructorDeclaration node) {
if (isNodeEnclosingOffset(node)) {
result[0] = node.getElement();
return super.visitConstructorDeclaration(node);
}
return null;
}
@Override
public Void visitFieldDeclaration(FieldDeclaration node) {
if (isNodeEnclosingOffset(node)) {
NodeList<VariableDeclaration> variables = node.getFields().getVariables();
if (!variables.isEmpty()) {
result[0] = variables.get(0).getElement();
}
return super.visitFieldDeclaration(node);
}
return null;
}
@Override
public Void visitFunctionDeclaration(FunctionDeclaration node) {
if (isNodeEnclosingOffset(node)) {
result[0] = node.getElement();
return super.visitFunctionDeclaration(node);
}
return null;
}
@Override
public Void visitMethodDeclaration(MethodDeclaration node) {
if (isNodeEnclosingOffset(node)) {
result[0] = node.getElement();
return super.visitMethodDeclaration(node);
}
return null;
}
@Override
public Void visitNode(AstNode node) {
if (isNodeEnclosingOffset(node)) {
super.visitNode(node);
}
return null;
}
private boolean isNodeEnclosingOffset(AstNode node) {
return node.getOffset() <= offset && offset <= node.getEnd();
}
});
return result[0];
}
/**
* Returns navigation targets for the given context, may be empty, but not {@code null}.
*/
public static NavigationTarget[] getNavigationTargets(String file, int offset) {
// find the smallest navigation region
NavigationRegion result = null;
NavigationRegion[] regions = DartCore.getAnalysisServerData().getNavigation(file);
for (NavigationRegion region : regions) {
if (region.containsInclusive(offset)) {
if (result == null || result.getLength() > region.getLength()) {
result = region;
}
}
if (region.getOffset() > offset) {
break;
}
}
// found a region
if (result != null) {
List<NavigationTarget> targets = result.getTargetObjects();
return targets.toArray(new NavigationTarget[targets.size()]);
}
// not found
return NavigationTarget.EMPTY_ARRAY;
}
/**
* Get the {@link AstNode} associated with the selected portion of the given editor.
*
* @param editor the editor
* @param caret the caret position in the editor
* @return the associated {@link AstNode}
*/
public static AstNode getNodeAtOffset(DartEditor editor, int caret) {
CompilationUnit cu = editor.getInputUnit();
if (cu == null) {
return null;
}
return new NodeLocator(caret).searchWithin(cu);
}
}