|
From: <caw...@us...> - 2007-01-25 16:39:56
|
Revision: 1882
http://svn.sourceforge.net/rubyeclipse/?rev=1882&view=rev
Author: cawilliams
Date: 2007-01-25 08:39:47 -0800 (Thu, 25 Jan 2007)
Log Message:
-----------
add a new experimental index for code completion. This index just keeps track of all the type names. So when we do code completion on types, it pops up the names very quickly.
Modified Paths:
--------------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/RubyCore.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
Added Paths:
-----------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/ExperimentalIndex.java
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/RubyCore.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/RubyCore.java 2007-01-25 15:40:44 UTC (rev 1881)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/RubyCore.java 2007-01-25 16:39:47 UTC (rev 1882)
@@ -54,6 +54,7 @@
import org.rubypeople.rdt.internal.core.builder.MassIndexUpdaterJob;
import org.rubypeople.rdt.internal.core.builder.RubyBuilder;
import org.rubypeople.rdt.internal.core.parser.RubyParser;
+import org.rubypeople.rdt.internal.core.search.ExperimentalIndex;
import org.rubypeople.rdt.internal.core.symbols.ISymbolFinder;
import org.rubypeople.rdt.internal.core.symbols.SymbolIndex;
import org.rubypeople.rdt.internal.core.util.Util;
@@ -350,6 +351,8 @@
List rubyProjects = Arrays.asList(getRubyProjects());
MassIndexUpdaterJob massUpdater = new MassIndexUpdaterJob(indexUpdater, rubyProjects);
massUpdater.schedule();
+ addElementChangedListener(ExperimentalIndex.instance());
+ ExperimentalIndex.start();
}
/*
@@ -361,6 +364,7 @@
public void stop(BundleContext context) throws Exception {
try {
RubyModelManager.getRubyModelManager().shutdown();
+ removeElementChangedListener(ExperimentalIndex.instance());
} finally {
// ensure we call super.stop as the last thing
super.stop(context);
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-01-25 15:40:44 UTC (rev 1881)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-01-25 16:39:47 UTC (rev 1882)
@@ -6,6 +6,7 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
import org.jruby.ast.ClassNode;
import org.jruby.ast.ClassVarAsgnNode;
@@ -25,16 +26,23 @@
import org.rubypeople.rdt.core.CompletionProposal;
import org.rubypeople.rdt.core.CompletionRequestor;
import org.rubypeople.rdt.core.Flags;
+import org.rubypeople.rdt.core.IImportDeclaration;
import org.rubypeople.rdt.core.IMethod;
import org.rubypeople.rdt.core.IParent;
import org.rubypeople.rdt.core.IRubyElement;
import org.rubypeople.rdt.core.IRubyProject;
import org.rubypeople.rdt.core.IRubyScript;
+import org.rubypeople.rdt.core.ISourceFolderRoot;
import org.rubypeople.rdt.core.IType;
+import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.internal.core.RubyElement;
import org.rubypeople.rdt.internal.core.RubyType;
import org.rubypeople.rdt.internal.core.parser.RubyParser;
+import org.rubypeople.rdt.internal.core.search.ExperimentalIndex;
+import org.rubypeople.rdt.internal.core.symbols.ISymbolFinder;
+import org.rubypeople.rdt.internal.core.symbols.ISymbolTypes;
+import org.rubypeople.rdt.internal.core.symbols.SearchResult;
import org.rubypeople.rdt.internal.ti.DefaultTypeInferrer;
import org.rubypeople.rdt.internal.ti.ITypeGuess;
import org.rubypeople.rdt.internal.ti.ITypeInferrer;
@@ -56,8 +64,6 @@
this.requestor.beginReporting();
if (offset < 0)
offset = 0;
- ITypeInferrer inferrer = new DefaultTypeInferrer();
-
StringBuffer source = new StringBuffer(script.getSource());
int replaceStart = offset + 1;
// Read from offset back until we hit a: space, period
@@ -89,27 +95,36 @@
this.prefix = prefix.toString();
if (this.prefix != null) replaceStart -= this.prefix.length();
- // If the prefix looks like a constant don't bother searching for
- // methods
- if (!(this.prefix != null && this.prefix.length() > 0 && Character.isUpperCase(this.prefix
- .charAt(0)))) {
+ if (isConstant()) { // type or constant
+ List<String> types = ExperimentalIndex.getTypes();
+ // TODO Remove duplicates? Sort?
+ for (String name : types) {
+ if (this.prefix != null && !name.startsWith(this.prefix)) continue;
+ CompletionProposal proposal = new CompletionProposal(
+ CompletionProposal.TYPE_REF, name, 100);
+ proposal.setReplaceRange(replaceStart, replaceStart + name.length());
+ requestor.accept(proposal);
+ }
+ } else { // method or variable
+ ITypeInferrer inferrer = new DefaultTypeInferrer();
List<ITypeGuess> guesses = inferrer
.infer(source.toString(), offset);
- // TODO Grab the project and all referred projects!
- IRubyProject[] projects = new IRubyProject[1];
- projects[0] = script.getRubyProject();
- RubyElementRequestor completer = new RubyElementRequestor(projects);
+ RubyElementRequestor completer = new RubyElementRequestor(script.getRubyProject());
for (Iterator iter = guesses.iterator(); iter.hasNext();) {
ITypeGuess guess = (ITypeGuess) iter.next();
IType type = completer.findType(guess.getType());
suggestMethods(replaceStart, completer, guess, type);
}
+ if (!isMethod) getDocumentsRubyElementsInScope(script, source.toString(), offset, replaceStart);
}
- // FIXME Do we need to call this at all if we know it's a method call we're trying to complete?
- if (!isMethod) getDocumentsRubyElementsInScope(script, source.toString(), offset, replaceStart);
this.requestor.endReporting();
}
+ private boolean isConstant() {
+ return this.prefix != null && this.prefix.length() > 0 && Character.isUpperCase(this.prefix
+ .charAt(0));
+ }
+
private void suggestMethods(int replaceStart, RubyElementRequestor completer, ITypeGuess guess,
IType type) throws RubyModelException {
if (type == null)
@@ -174,13 +189,7 @@
* @return a List of the names of all the elements in the current RubyScript
*/
private void getDocumentsRubyElementsInScope(IRubyScript script, String source, int offset, int replaceStart) {
- try {
- // Get all references projects
- List<IRubyProject> projects = new ArrayList<IRubyProject>();
- projects.add(script.getRubyProject());
- // TODO Search the loadpaths!
-// projects.addAll(script.getRubyProject().getReferencedProjects());
-
+ try {
// FIXME Try to stop all the multiple re-parsing of the source! Can we parse once and pass the root node around?
// Parse
Node rootNode = (new RubyParser()).parse(source);
@@ -223,11 +232,8 @@
}
// Add all globals, classes, and modules
- for (Iterator iter = projects.iterator(); iter.hasNext();) {
- IRubyProject nextProject = (IRubyProject)(iter.next());
- getElementsOfType( nextProject, new int[] { IRubyElement.GLOBAL }, replaceStart);
- addClassesAndModulesInProject( nextProject, replaceStart );
- }
+ getElementsOfType( script.getRubyProject(), new int[] { IRubyElement.GLOBAL }, replaceStart);
+ addClassesAndModulesInProject( script.getRubyProject(), replaceStart );
} catch ( RubyModelException rme ) {
System.out.println("RubyModelException in CompletionEngine::getElementsInScope()");
rme.printStackTrace();
Added: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/ExperimentalIndex.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/ExperimentalIndex.java (rev 0)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/search/ExperimentalIndex.java 2007-01-25 16:39:47 UTC (rev 1882)
@@ -0,0 +1,112 @@
+package org.rubypeople.rdt.internal.core.search;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.rubypeople.rdt.core.ElementChangedEvent;
+import org.rubypeople.rdt.core.IElementChangedListener;
+import org.rubypeople.rdt.core.IParent;
+import org.rubypeople.rdt.core.IRubyElement;
+import org.rubypeople.rdt.core.IRubyElementDelta;
+import org.rubypeople.rdt.core.IRubyModel;
+import org.rubypeople.rdt.core.RubyModelException;
+import org.rubypeople.rdt.internal.core.RubyModelManager;
+
+public class ExperimentalIndex implements IElementChangedListener {
+
+ private static List<String> fgTypes = new ArrayList<String>();
+ private static ExperimentalIndex fgInstance;
+
+ private ExperimentalIndex() {
+
+ }
+
+ public void elementChanged(ElementChangedEvent event) {
+ processDelta(event.getDelta());
+ }
+
+ public static List<String> getTypes() {
+ return Collections.unmodifiableList(fgTypes);
+ }
+
+ private void processDelta(IRubyElementDelta delta) {
+ IRubyElement element = delta.getElement();
+ switch (delta.getKind()) {
+ case IRubyElementDelta.CHANGED:
+ IRubyElementDelta[] children = delta.getAffectedChildren();
+ for (int i = 0, length = children.length; i < length; i++) {
+ IRubyElementDelta child = children[i];
+ this.processDelta(child);
+ }
+ break;
+ case IRubyElementDelta.REMOVED:
+ switch (element.getElementType()) {
+ case IRubyElement.TYPE:
+ fgTypes.remove(element.getElementName());
+ break;
+ }
+ break;
+ case IRubyElementDelta.ADDED:
+ addElement(element);
+ break;
+ }
+ }
+
+ void addElement(IRubyElement element) {
+ switch (element.getElementType()) {
+ case IRubyElement.TYPE:
+ fgTypes.add(element.getElementName());
+ break;
+ }
+ }
+
+ public static ExperimentalIndex instance() {
+ if (fgInstance == null) {
+ fgInstance = new ExperimentalIndex();
+ }
+ return fgInstance;
+ }
+
+ public static void start() {
+ Job job = new ExperimentalIndexJob(instance());
+ job.schedule();
+ }
+
+ private static class ExperimentalIndexJob extends Job {
+ private ExperimentalIndex index;
+
+ public ExperimentalIndexJob(ExperimentalIndex index) {
+ super("Experimental Index Job");
+ this.index = index;
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ IRubyModel model = RubyModelManager.getRubyModelManager().getRubyModel();
+ addChildren(model);
+ return Status.OK_STATUS;
+ }
+
+ private void addChildren(IParent parent) {
+ try {
+ IRubyElement[] children = parent.getChildren();
+ for (int i = 0; i < children.length; i++) {
+ index.addElement(children[i]);
+ if (children[i] instanceof IParent) {
+ IParent newParent = (IParent) children[i];
+ addChildren(newParent);
+ }
+ }
+ } catch (RubyModelException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ }
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|