package com.redhat.ceylon.eclipse.code.search; import static com.redhat.ceylon.eclipse.code.complete.CodeCompletions.getQualifiedDescriptionFor; import static com.redhat.ceylon.eclipse.code.outline.CeylonLabelProvider.getImageKeyForNode; import static com.redhat.ceylon.eclipse.code.outline.CeylonLabelProvider.getNodeDecorationAttributes; import static com.redhat.ceylon.eclipse.code.outline.CeylonLabelProvider.getStyledLabelForNode; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.PARAMS_IN_OUTLINES; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.PARAM_TYPES_IN_OUTLINES; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.RETURN_TYPES_IN_OUTLINES; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.TYPE_PARAMS_IN_OUTLINES; import static com.redhat.ceylon.eclipse.util.Nodes.getImportedName; import static com.redhat.ceylon.eclipse.java2ceylon.Java2CeylonProxies.vfsJ2C; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.StyledString; import org.eclipse.swt.graphics.Font; import com.redhat.ceylon.compiler.typechecker.io.VirtualFile; import com.redhat.ceylon.compiler.typechecker.tree.Node; import com.redhat.ceylon.compiler.typechecker.tree.Tree; import com.redhat.ceylon.eclipse.ui.CeylonPlugin; import com.redhat.ceylon.eclipse.util.ModelProxy; import com.redhat.ceylon.ide.common.vfs.ResourceVirtualFile; import com.redhat.ceylon.model.typechecker.model.Declaration; import com.redhat.ceylon.model.typechecker.model.Package; import com.redhat.ceylon.model.typechecker.model.Unit; public class CeylonElement { private VirtualFile file; //TODO: is this really the best thing to use nowadays? private String qualifiedName; private int line; private int decline; private String imageKey; private String packageLabel; private StyledString label; private int decorations; private int startOffset; private int endOffset; private final ModelProxy proxy; private final CeylonSearchMatch.Type type; public CeylonSearchMatch.Type getType() { return type; } public CeylonElement(Node node, VirtualFile file, int line, CeylonSearchMatch.Type type) { //the file and line number, which get //displayed in the search results page this.file = file; this.line = line; this.type = type; //store enough information to be able to //locate the model again if we run a search //for usages of the container from the search //results view startOffset = node.getStartIndex(); endOffset = node.getEndIndex(); //compute and cache everything we need to //display the search result, without holding //onto a hard ref to the container node imageKey = getImageKeyForNode(node); label = getStyledLabelForNode(node); Unit unit = node.getUnit(); if (unit==null) { packageLabel = "(unknown package)"; } else { Package pack = unit.getPackage(); String name = pack.getQualifiedNameString(); packageLabel = name.isEmpty() ? "(default package)" : name; } //TODO: this winds up caching error decorations, // so it's not really very good decorations = getNodeDecorationAttributes(node); if (node instanceof Tree.Declaration) { Tree.Declaration decl = (Tree.Declaration) node; Declaration d = decl.getDeclarationModel(); proxy = new ModelProxy(d); } else { proxy = null; } if (node instanceof Tree.Declaration) { Tree.Declaration decl = (Tree.Declaration) node; Declaration dec = decl.getDeclarationModel(); qualifiedName = dec.getQualifiedNameString(); decline = decl.getToken().getLine(); } else if (node instanceof Tree.PackageDescriptor) { qualifiedName = unit.getPackage() .getNameAsString(); } else if (node instanceof Tree.ModuleDescriptor) { qualifiedName = unit.getPackage() .getModule() .getNameAsString(); } else if (node instanceof Tree.CompilationUnit) { qualifiedName = unit.getPackage() .getNameAsString() + '/' + unit.getFilename(); } else if (node instanceof Tree.Import) { Tree.Import imp = (Tree.Import) node; String name = getImportedName(imp); qualifiedName = unit.getPackage() .getNameAsString() + '/' + unit.getFilename() + '#' + name; } else if (node instanceof Tree.ImportModule) { Tree.ImportModule imp = (Tree.ImportModule) node; String name = getImportedName(imp); qualifiedName = unit.getPackage() .getNameAsString() + '/' + unit.getFilename() + '@' + name; } } public String getImageKey() { return imageKey; } public String getPackageLabel() { return packageLabel; } public StyledString getLabel() { return getLabel(null, null); } public StyledString getLabel(String prefix, Font font) { if (proxy==null) { return label; } else { IPreferenceStore prefs = CeylonPlugin.getPreferences(); return getQualifiedDescriptionFor( proxy.get(), prefs.getBoolean(TYPE_PARAMS_IN_OUTLINES), prefs.getBoolean(PARAMS_IN_OUTLINES), prefs.getBoolean(PARAM_TYPES_IN_OUTLINES), prefs.getBoolean(RETURN_TYPES_IN_OUTLINES), prefix, font); } } public int getDecorations() { return decorations; } public int getLocation() { return line; } public VirtualFile getVirtualFile() { return file; } public IFile getFile() { if (vfsJ2C().instanceOfIFileVirtualFile(file)) { return vfsJ2C().getIFileVirtualFile(file).getNativeResource(); } else { return null; } } //for no good reason that I can see, ResourceVirtualFiles //return a project-relative path from getPath() @SuppressWarnings("rawtypes") public String getPathString() { if (file instanceof ResourceVirtualFile) { ResourceVirtualFile rvf = (ResourceVirtualFile) file; Object nativeResource = rvf.getNativeResource(); if (nativeResource instanceof IResource) { return ((IResource)nativeResource) .getFullPath() .toPortableString(); } } return file.getPath(); } public int getStartOffset() { return startOffset; } public int getEndOffset() { return endOffset; } @Override public boolean equals(Object obj) { if (obj instanceof CeylonElement) { CeylonElement that = (CeylonElement) obj; if (!file.equals(that.file)) { return false; } if (qualifiedName!=null && that.qualifiedName!=null) { return qualifiedName.equals(that.qualifiedName) && //handle overloaded methods decline == that.decline; } else if (qualifiedName==null && that.qualifiedName==null) { return line==that.line; } else { return false; } } else { return false; } } @Override public int hashCode() { return file.getName().hashCode() ^ (qualifiedName==null ? 0 : qualifiedName.hashCode()); } }