package org.rubypeople.rdt.core.codeassist; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.eclipse.core.resources.IFile; import org.jruby.ast.Node; import org.jruby.ast.RootNode; import org.jruby.lexer.yacc.SyntaxException; import org.rubypeople.rdt.core.IRubyElement; import org.rubypeople.rdt.core.IRubyProject; import org.rubypeople.rdt.core.IRubyScript; import org.rubypeople.rdt.core.RubyModelException; import org.rubypeople.rdt.internal.core.ExternalRubyScript; import org.rubypeople.rdt.internal.core.RubyScript; import org.rubypeople.rdt.internal.core.parser.RubyParser; import org.rubypeople.rdt.internal.ti.util.OffsetNodeLocator; public class ResolveContext { private IRubyScript script; private int start; private int end; private RootNode root; private Node selected; private IRubyElement[] resolved = new IRubyElement[0]; public ResolveContext(IRubyScript script, int start, int end) { this.script = script; this.start = start; this.end = end; } public RootNode getAST() throws RubyModelException { if (root == null) { try { RubyParser parser = new RubyParser(); root = (RootNode) parser.parse((IFile) script.getResource(), script.getSource()).getAST(); } catch (SyntaxException e) { root = (RootNode) ((RubyScript) script).lastGoodAST; } } return root; } public Node getSelectedNode() throws RubyModelException { if (selected == null) { selected = OffsetNodeLocator.Instance().getNodeAtOffset(getAST(), start); } return selected; } public IRubyScript getScript() { return script; } public int getStartOffset() { return start; } public int getEndOffset() { return end; } public IRubyElement[] getResolved() { // TODO Prioritize the results! If in same IRubyScript, they go first, then if in same project, then everything // else. return prioritize(resolved); } private IRubyElement[] prioritize(IRubyElement[] resolved) { List<IRubyElement> prioritized = Arrays.asList(resolved); Collections.sort(prioritized, new Comparator<IRubyElement>() { public int compare(IRubyElement o1, IRubyElement o2) { IRubyScript o1Script = (IRubyScript) o1.getAncestor(IRubyElement.SCRIPT); if (o1Script != null && o1Script.getPath().equals(script.getPath())) { // o1 is in same script! IRubyScript o2Script = (IRubyScript) o2.getAncestor(IRubyElement.SCRIPT); if (o2Script != null && o2Script.getPath().equals(script.getPath())) { // so is o2, they're equal return 0; } return -1; // o1 is "closer" } else { IRubyScript o2Script = (IRubyScript) o2.getAncestor(IRubyElement.SCRIPT); if (o2Script != null && o2Script.getPath().equals(script.getPath())) { // o2 is closer return 1; } // Ok neither script matches. Now check if in same project IRubyProject o1Project = o1.getRubyProject(); if (o1Project != null && o1Project.equals(script.getRubyProject())) { // o1 has same project IRubyProject o2Project = o2.getRubyProject(); if (o2Project != null && o2Project.equals(script.getRubyProject())) { // o2 has same project too, consider equal return 0; } return -1; } else { // o1 project doesn't match! IRubyProject o2Project = o2.getRubyProject(); if (o2Project != null && o2Project.equals(script.getRubyProject())) { // o2 has same project, it's "closer" return 1; } // neither project matches, check if they're from external lib/gem if (o1Script != null && o1Script instanceof ExternalRubyScript) { // o1 is external gem/library if (o2Script != null && o2Script instanceof ExternalRubyScript) { return 0; } return -1; } else if (o2Script != null && o2Script instanceof ExternalRubyScript) { return 1; } // not external, projects don't match context, consider equal return 0; } } } }); return prioritized.toArray(new IRubyElement[prioritized.size()]); } public void putResolved(IRubyElement[] resolved) { this.resolved = resolved; } }