In progress: [Issue 155] Editor does not support complex custom options.
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/AstWalker.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/AstWalker.java
new file mode 100644
index 0000000..b6a5b02
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/AstWalker.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * 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
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import static java.util.Collections.emptyList;
+import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
+
+import com.google.eclipse.protobuf.model.util.*;
+import com.google.eclipse.protobuf.parser.NonProto2;
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.eclipse.protobuf.protobuf.Package;
+import com.google.inject.Inject;
+
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.*;
+import org.eclipse.xtext.resource.IEObjectDescription;
+
+import java.util.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class AstWalker {
+
+  @Inject private ModelFinder modelFinder;
+  @Inject private Imports imports;
+  @Inject private Packages packages;
+  @Inject private Resources resources;
+
+  Collection<IEObjectDescription> traverseAst(EObject start, ScopeFinder scopeFinder, Object criteria) {
+    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+    EObject current = start.eContainer();
+    while (current != null) {
+      descriptions.addAll(local(current, scopeFinder, criteria));
+      current = current.eContainer();
+    }
+    Protobuf root = modelFinder.rootOf(start);
+    descriptions.addAll(imported(root, scopeFinder, criteria));
+    return descriptions;
+  }
+  
+  Collection<IEObjectDescription> traverseAst(Protobuf start, ScopeFinder scopeFinder, Object criteria) {
+    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+    descriptions.addAll(local(start, scopeFinder, criteria));
+    descriptions.addAll(imported(start, scopeFinder, criteria));
+    return descriptions;
+  }
+
+  private Collection<IEObjectDescription> local(EObject start, ScopeFinder scopeFinder, Object criteria) {
+    return local(start, scopeFinder, criteria, 0);
+  }
+
+  private Collection<IEObjectDescription> local(EObject start, ScopeFinder scopeFinder, Object criteria, int level) {
+    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
+    for (EObject element : start.eContents()) {
+      descriptions.addAll(scopeFinder.descriptions(element, criteria, level));
+      if (element instanceof Message) {
+        descriptions.addAll(local(element, scopeFinder, criteria, level + 1));
+      }
+    }
+    return descriptions;
+  }
+
+  private Collection<IEObjectDescription> imported(Protobuf start, ScopeFinder scopeFinder, Object criteria) {
+    List<Import> allImports = modelFinder.importsIn(start);
+    if (allImports.isEmpty()) return emptyList();
+    ResourceSet resourceSet = start.eResource().getResourceSet();
+    return imported(allImports, modelFinder.packageOf(start), resourceSet, scopeFinder, criteria);
+  }
+
+  private Collection<IEObjectDescription> imported(List<Import> allImports, Package aPackage,
+      ResourceSet resourceSet, ScopeFinder scopeFinder, Object criteria) {
+    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
+    for (Import anImport : allImports) {
+      if (imports.isImportingDescriptor(anImport)) {
+        descriptions.addAll(scopeFinder.fromProtoDescriptor(anImport, criteria));
+        continue;
+      }
+      Resource importedResource = resources.importedResource(anImport, resourceSet);
+      Protobuf rootOfImported = modelFinder.rootOf(importedResource);
+      if (rootOfImported instanceof NonProto2) continue;
+      if (rootOfImported != null) {
+        descriptions.addAll(publicImported(rootOfImported, scopeFinder, criteria));
+        if (arePackagesRelated(aPackage, rootOfImported)) {
+          descriptions.addAll(local(rootOfImported, scopeFinder, criteria));
+          continue;
+        }
+      }
+      descriptions.addAll(local(importedResource, scopeFinder, criteria));
+    }
+    return descriptions;
+  }
+
+  private Collection<IEObjectDescription> publicImported(Protobuf start, ScopeFinder scopeFinder, Object criteria) {
+    List<Import> allImports = modelFinder.publicImportsIn(start);
+    if (allImports.isEmpty()) return emptyList();
+    ResourceSet resourceSet = start.eResource().getResourceSet();
+    return imported(allImports, modelFinder.packageOf(start), resourceSet, scopeFinder, criteria);
+  }
+
+  private boolean arePackagesRelated(Package aPackage, EObject root) {
+    Package p = modelFinder.packageOf(root);
+    return packages.areRelated(aPackage, p);
+  }
+
+  private Collection<IEObjectDescription> local(Resource resource, ScopeFinder scopeFinder, Object criteria) {
+    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
+    TreeIterator<Object> contents = getAllContents(resource, true);
+    while (contents.hasNext()) {
+      Object next = contents.next();
+      descriptions.addAll(scopeFinder.descriptions(next, criteria));
+      // TODO verify that call to 'importedNamesProvider.namesOf' is not necessary
+    }
+    return descriptions;
+  }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionFieldScopeFinder.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionFieldScopeFinder.java
new file mode 100644
index 0000000..7a72d69
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionFieldScopeFinder.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * 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
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import static java.util.Collections.*;
+import static org.eclipse.xtext.resource.EObjectDescription.create;
+
+import com.google.eclipse.protobuf.model.util.*;
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.inject.*;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.resource.IEObjectDescription;
+
+import java.util.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class CustomOptionFieldScopeFinder {
+
+  @Inject private FieldOptions fieldOptions;
+  @Inject private ModelFinder modelFinder;
+  @Inject private Options options;
+  @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
+
+  Collection<IEObjectDescription> findScope(MessagePropertyRef ref) {
+    return findScope(ref, new IEObjectDescriptionsProvider() {
+      @Override public Collection<IEObjectDescription> fieldsInType(Property p) {
+        Message propertyType = modelFinder.messageTypeOf(p);
+        if (propertyType == null) return emptyList();
+        Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+        for (MessageElement e : propertyType.getElements()) {
+          if (!(e instanceof Property)) continue;
+          Property f = (Property) e;
+          descriptions.add(create(f.getName(), f));
+        }
+        return descriptions;
+      }
+    });
+  }
+
+  Collection<IEObjectDescription> findScope(ExtendMessagePropertyRef ref) {
+    return findScope(ref, new IEObjectDescriptionsProvider() {
+      @Override public Collection<IEObjectDescription> fieldsInType(Property p) {
+        Message propertyType = modelFinder.messageTypeOf(p);
+        if (propertyType == null) return emptyList();
+        Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
+        for (ExtendMessage extend : modelFinder.extensionsOf(propertyType)) {
+          for (MessageElement e : extend.getElements()) {
+            if (!(e instanceof Property)) continue;
+            Property f = (Property) e;
+            descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(f));
+            descriptions.add(create(f.getName(), f));
+          }
+        }
+        return descriptions;
+      }
+    });
+  }
+
+  private Collection<IEObjectDescription> findScope(EObject ref, IEObjectDescriptionsProvider provider) {
+    EObject container = ref.eContainer();
+    Property p = null;
+    if (container instanceof CustomOption) {
+      CustomOption option = (CustomOption) container;
+      p = referredProperty(ref, option);
+    }
+    if (container instanceof CustomFieldOption) {
+      CustomFieldOption option = (CustomFieldOption) container;
+      p = referredProperty(ref, option);
+    }
+    if (p != null) return provider.fieldsInType(p);
+    return emptySet();
+  }
+
+  private Property referredProperty(EObject ref, final CustomOption option) {
+    return referredProperty(ref, option.getOptionFields(), new Provider<Property>() {
+      @Override public Property get() {
+        return options.propertyFrom(option);
+      }
+    });
+  }
+
+  private Property referredProperty(EObject ref, final CustomFieldOption option) {
+    return referredProperty(ref, option.getOptionFields(), new Provider<Property>() {
+      @Override public Property get() {
+        return fieldOptions.propertyFrom(option);
+      }
+    });
+  }
+  
+  private Property referredProperty(EObject ref, List<OptionField> fields, Provider<Property> provider) {
+    OptionField previous = null;
+    boolean isFirstField = true;
+    for (OptionField field : fields) {
+      if (field == ref) {
+        return (isFirstField) ? provider.get() : propertyFrom(previous);
+      }
+      previous = field;
+      isFirstField = false;
+    }
+    return null;
+  }
+
+  private Property propertyFrom(OptionField field) {
+    if (field instanceof MessagePropertyRef) {
+      MessagePropertyRef ref = (MessagePropertyRef) field;
+      return ref.getMessageProperty();
+    }
+    if (field instanceof ExtendMessagePropertyRef) {
+      ExtendMessagePropertyRef ref = (ExtendMessagePropertyRef) field;
+      return ref.getExtendMessageProperty();
+    }
+    return null;
+  }
+  
+  private static interface IEObjectDescriptionsProvider {
+    Collection<IEObjectDescription> fieldsInType(Property p);
+  }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionSearchDelegate.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionScopeFinder.java
similarity index 93%
rename from com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionSearchDelegate.java
rename to com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionScopeFinder.java
index 8f60b2a..74b9f96 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionSearchDelegate.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/CustomOptionScopeFinder.java
@@ -15,7 +15,7 @@
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-class CustomOptionSearchDelegate extends ExtendMessageSearchDelegate {
+class CustomOptionScopeFinder extends ExtendMessageScopeFinder {
 
   @Override public Collection<IEObjectDescription> descriptions(Object target, Object criteria) {
     OptionType optionType = optionTypeFrom(criteria);
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ExtendMessageSearchDelegate.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ExtendMessageScopeFinder.java
similarity index 93%
rename from com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ExtendMessageSearchDelegate.java
rename to com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ExtendMessageScopeFinder.java
index 2473fd2..d1729c8 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ExtendMessageSearchDelegate.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ExtendMessageScopeFinder.java
@@ -23,16 +23,12 @@
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-class ExtendMessageSearchDelegate implements SearchDelegate {
+class ExtendMessageScopeFinder implements ScopeFinder {
 
   @Inject private LocalNamesProvider localNamesProvider;
   @Inject private ModelFinder modelFinder;
   @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
 
-  @Override public boolean continueSearchOneLevelHigher(Object target) {
-    return target instanceof Message;
-  }
-
   @Override public Collection<IEObjectDescription> fromProtoDescriptor(Import anImport, Object criteria) {
     return emptySet();
   }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
index a387f2f..89023d1 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
@@ -9,20 +9,19 @@
 package com.google.eclipse.protobuf.scoping;
 
 import static com.google.eclipse.protobuf.scoping.OptionType.typeOf;
-import static java.util.Collections.*;
-import static org.eclipse.xtext.resource.EObjectDescription.create;
+import static java.util.Collections.emptySet;
 
 import com.google.eclipse.protobuf.model.util.*;
 import com.google.eclipse.protobuf.protobuf.*;
 import com.google.eclipse.protobuf.protobuf.Enum;
-import com.google.inject.*;
+import com.google.inject.Inject;
 
 import org.eclipse.emf.ecore.*;
 import org.eclipse.xtext.resource.IEObjectDescription;
 import org.eclipse.xtext.scoping.IScope;
 import org.eclipse.xtext.scoping.impl.*;
 
-import java.util.*;
+import java.util.Set;
 
 /**
  * Custom scoping description.
@@ -35,23 +34,23 @@
 
   private static final boolean DO_NOT_IGNORE_CASE = false;
 
-  @Inject private CustomOptionSearchDelegate customOptionSearchDelegate;
+  @Inject private AstWalker astWalker;
+  @Inject private CustomOptionFieldScopeFinder customOptionFieldScopeFinder;
+  @Inject private CustomOptionScopeFinder customOptionScopeFinder;
   @Inject private ProtoDescriptorProvider descriptorProvider;
   @Inject private FieldOptions fieldOptions;
   @Inject private ModelFinder modelFinder;
   @Inject private LiteralDescriptions literalDescriptions;
   @Inject private NativeOptionDescriptions nativeOptionDescriptions;
   @Inject private Options options;
-  @Inject private ScopeFinder scopeFinder;
-  @Inject private TypeSearchDelegate typeSearchDelegate;
-  @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
+  @Inject private TypeScopeFinder typeScopeFinder;
 
   @SuppressWarnings("unused")
   public IScope scope_TypeRef_type(TypeRef typeRef, EReference reference) {
     EObject c = typeRef.eContainer();
     if (c instanceof Property) {
       Property property = (Property) c;
-      return createScope(scopeFinder.findScope(property, typeSearchDelegate, Type.class));
+      return createScope(astWalker.traverseAst(property, typeScopeFinder, Type.class));
     }
     Set<IEObjectDescription> descriptions = emptySet();
     return createScope(descriptions);
@@ -60,7 +59,7 @@
   @SuppressWarnings("unused")
   public IScope scope_MessageRef_type(MessageRef messageRef, EReference reference) {
     Protobuf root = modelFinder.rootOf(messageRef);
-    return createScope(scopeFinder.findScope(root, typeSearchDelegate, Message.class));
+    return createScope(astWalker.traverseAst(root, typeScopeFinder, Message.class));
   }
 
   @SuppressWarnings("unused")
@@ -110,11 +109,11 @@
     }
     if (c instanceof CustomOption) {
       CustomOption option = (CustomOption) c;
-      return createScope(scopeFinder.findScope(option, customOptionSearchDelegate, typeOf(option)));
+      return createScope(astWalker.traverseAst(option, customOptionScopeFinder, typeOf(option)));
     }
     if (c instanceof CustomFieldOption) {
       CustomFieldOption option = (CustomFieldOption) c;
-      return createScope(scopeFinder.findScope(option, customOptionSearchDelegate, typeOf(option)));
+      return createScope(astWalker.traverseAst(option, customOptionScopeFinder, typeOf(option)));
     }
     Set<IEObjectDescription> descriptions = emptySet();
     return createScope(descriptions);
@@ -122,118 +121,13 @@
   
   @SuppressWarnings("unused") 
   public IScope scope_MessagePropertyRef_messageProperty(MessagePropertyRef propertyRef, EReference reference) {
-    EObject c = propertyRef.eContainer();
-    Property property = null;
-    if (c instanceof CustomOption) {
-      final CustomOption option = (CustomOption) c;
-      property = referencedProperty(propertyRef, option.getOptionFields(), new Provider<Property>() {
-        @Override public Property get() {
-          return options.propertyFrom(option);
-        }
-      });
-    }
-    if (c instanceof CustomFieldOption) {
-      final CustomFieldOption option = (CustomFieldOption) c;
-      property = referencedProperty(propertyRef, option.getOptionFields(), new Provider<Property>() {
-        @Override public Property get() {
-          return fieldOptions.propertyFrom(option);
-        }
-      });
-    }
-    if (property != null) {
-      return createScope(fieldsInMessageContaining(property));
-    }
-    Set<IEObjectDescription> descriptions = emptySet();
-    return createScope(descriptions);
+    return createScope(customOptionFieldScopeFinder.findScope(propertyRef));
   }
   
-  private Property referencedProperty(MessagePropertyRef ref, List<OptionField> fields, Provider<Property> provider) {
-    OptionField previous = null;
-    boolean isFirstField = true;
-    for (OptionField field : fields) {
-      if (field == ref) return (isFirstField) ? provider.get() : propertyFrom(previous);
-      previous = field;
-      isFirstField = false;
-    }
-    return null;
-  }
-  
-  private Collection <IEObjectDescription> fieldsInMessageContaining(Property p) {
-    Message propertyType = modelFinder.messageTypeOf(p);
-    if (propertyType == null) return emptyList();
-    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
-    for (MessageElement e : propertyType.getElements()) {
-      if (!(e instanceof Property)) continue;
-      Property optionPropertyField = (Property) e;
-      descriptions.add(create(optionPropertyField.getName(), optionPropertyField));
-    }
-    return descriptions;
-  }
-
   @SuppressWarnings("unused") 
   public IScope scope_ExtendMessagePropertyRef_extendMessageProperty(ExtendMessagePropertyRef propertyRef, 
       EReference reference) {
-    EObject c = propertyRef.eContainer();
-    Property property = null;
-    if (c instanceof CustomOption) {
-      final CustomOption option = (CustomOption) c;
-      property = referencedProperty(propertyRef, option.getOptionFields(), new Provider<Property>() {
-        @Override public Property get() {
-          return options.propertyFrom(option);
-        }
-      });
-    }
-    if (c instanceof CustomFieldOption) {
-      final CustomFieldOption option = (CustomFieldOption) c;
-      property = referencedProperty(propertyRef, option.getOptionFields(), new Provider<Property>() {
-        @Override public Property get() {
-          return fieldOptions.propertyFrom(option);
-        }
-      });
-    }
-    if (property != null) {
-      return createScope(fieldsInExtendedVersionOfMessageContaining(property));
-    }
-    Set<IEObjectDescription> descriptions = emptySet();
-    return createScope(descriptions);
-  }
-
-  private Property referencedProperty(ExtendMessagePropertyRef ref, List<OptionField> fields, Provider<Property> provider) {
-    OptionField previous = null;
-    boolean isFirstField = true;
-    for (OptionField field : fields) {
-      if (field == ref) return (isFirstField) ? provider.get() : propertyFrom(previous);
-      previous = field;
-      isFirstField = false;
-    }
-    return null;
-  }
-
-  private Collection <IEObjectDescription> fieldsInExtendedVersionOfMessageContaining(Property p) {
-    Message propertyType = modelFinder.messageTypeOf(p);
-    if (propertyType == null) return emptyList();
-    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
-    for (ExtendMessage extend : modelFinder.extensionsOf(propertyType)) {
-      for (MessageElement e : extend.getElements()) {
-        if (!(e instanceof Property)) continue;
-        Property optionPropertyField = (Property) e;
-        descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(optionPropertyField));
-        descriptions.add(create(optionPropertyField.getName(), optionPropertyField));
-      }
-    }
-    return descriptions;
-  }
-
-  private Property propertyFrom(OptionField field) {
-    if (field instanceof MessagePropertyRef) {
-      MessagePropertyRef ref = (MessagePropertyRef) field;
-      return ref.getMessageProperty();
-    }
-    if (field instanceof ExtendMessagePropertyRef) {
-      ExtendMessagePropertyRef ref = (ExtendMessagePropertyRef) field;
-      return ref.getExtendMessageProperty();
-    }
-    return null;
+    return createScope(customOptionFieldScopeFinder.findScope(propertyRef));
   }
   
   private static IScope createScope(Iterable<IEObjectDescription> descriptions) {
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ScopeFinder.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ScopeFinder.java
index 7b921f4..f6223f5 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ScopeFinder.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ScopeFinder.java
@@ -8,116 +8,20 @@
  */
 package com.google.eclipse.protobuf.scoping;
 
-import static java.util.Collections.emptyList;
-import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
+import com.google.eclipse.protobuf.protobuf.Import;
 
-import com.google.eclipse.protobuf.model.util.*;
-import com.google.eclipse.protobuf.parser.NonProto2;
-import com.google.eclipse.protobuf.protobuf.*;
-import com.google.eclipse.protobuf.protobuf.Package;
-import com.google.inject.Inject;
-
-import org.eclipse.emf.common.util.TreeIterator;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.resource.*;
 import org.eclipse.xtext.resource.IEObjectDescription;
 
-import java.util.*;
+import java.util.Collection;
 
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-class ScopeFinder {
+interface ScopeFinder {
 
-  @Inject private ModelFinder finder;
-  @Inject private Imports imports;
-  @Inject private Packages packages;
-  @Inject private Resources resources;
+  Collection<IEObjectDescription> fromProtoDescriptor(Import anImport, Object criteria);
 
-  Collection<IEObjectDescription> findScope(EObject target, SearchDelegate delegate, Object criteria) {
-    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
-    EObject current = target.eContainer();
-    while (current != null) {
-      descriptions.addAll(local(current, delegate, criteria));
-      current = current.eContainer();
-    }
-    Protobuf root = finder.rootOf(target);
-    descriptions.addAll(imported(root, delegate, criteria));
-    return descriptions;
-  }
-  
-  Collection<IEObjectDescription> findScope(Protobuf root, SearchDelegate delegate, Object criteria) {
-    Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
-    descriptions.addAll(local(root, delegate, criteria));
-    descriptions.addAll(imported(root, delegate, criteria));
-    return descriptions;
-  }
+  Collection<IEObjectDescription> descriptions(Object target, Object criteria);
 
-  private Collection<IEObjectDescription> local(EObject root, SearchDelegate delegate, Object criteria) {
-    return local(root, delegate, criteria, 0);
-  }
-
-  private Collection<IEObjectDescription> local(EObject root, SearchDelegate delegate, Object criteria, int level) {
-    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
-    for (EObject element : root.eContents()) {
-      descriptions.addAll(delegate.descriptions(element, criteria, level));
-      if (delegate.continueSearchOneLevelHigher(element)) {
-        descriptions.addAll(local(element, delegate, criteria, level + 1));
-      }
-    }
-    return descriptions;
-  }
-
-  private Collection<IEObjectDescription> imported(Protobuf root, SearchDelegate delegate, Object criteria) {
-    List<Import> allImports = finder.importsIn(root);
-    if (allImports.isEmpty()) return emptyList();
-    ResourceSet resourceSet = root.eResource().getResourceSet();
-    return imported(allImports, finder.packageOf(root), resourceSet, delegate, criteria);
-  }
-
-  private Collection<IEObjectDescription> imported(List<Import> allImports, Package aPackage,
-      ResourceSet resourceSet, SearchDelegate delegate, Object criteria) {
-    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
-    for (Import anImport : allImports) {
-      if (imports.isImportingDescriptor(anImport)) {
-        descriptions.addAll(delegate.fromProtoDescriptor(anImport, criteria));
-        continue;
-      }
-      Resource importedResource = resources.importedResource(anImport, resourceSet);
-      Protobuf rootOfImported = finder.rootOf(importedResource);
-      if (rootOfImported instanceof NonProto2) continue;
-      if (rootOfImported != null) {
-        descriptions.addAll(publicImported(rootOfImported, delegate, criteria));
-        if (arePackagesRelated(aPackage, rootOfImported)) {
-          descriptions.addAll(local(rootOfImported, delegate, criteria));
-          continue;
-        }
-      }
-      descriptions.addAll(local(importedResource, delegate, criteria));
-    }
-    return descriptions;
-  }
-
-  private Collection<IEObjectDescription> publicImported(Protobuf root, SearchDelegate delegate, Object criteria) {
-    List<Import> allImports = finder.publicImportsIn(root);
-    if (allImports.isEmpty()) return emptyList();
-    ResourceSet resourceSet = root.eResource().getResourceSet();
-    return imported(allImports, finder.packageOf(root), resourceSet, delegate, criteria);
-  }
-
-  private boolean arePackagesRelated(Package aPackage, EObject root) {
-    Package p = finder.packageOf(root);
-    return packages.areRelated(aPackage, p);
-  }
-
-  private Collection<IEObjectDescription> local(Resource resource, SearchDelegate delegate, Object criteria) {
-    List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
-    TreeIterator<Object> contents = getAllContents(resource, true);
-    while (contents.hasNext()) {
-      Object next = contents.next();
-      descriptions.addAll(delegate.descriptions(next, criteria));
-      // TODO verify that call to 'importedNamesProvider.namesOf' is not necessary
-    }
-    return descriptions;
-  }
+  Collection<IEObjectDescription> descriptions(Object target, Object criteria, int level);
 }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/SearchDelegate.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/SearchDelegate.java
deleted file mode 100644
index a8dd4d0..0000000
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/SearchDelegate.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2011 Google Inc.
- *
- * 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
- */
-package com.google.eclipse.protobuf.scoping;
-
-import com.google.eclipse.protobuf.protobuf.Import;
-
-import org.eclipse.xtext.resource.IEObjectDescription;
-
-import java.util.Collection;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-interface SearchDelegate {
-
-  boolean continueSearchOneLevelHigher(Object target);
-  
-  Collection<IEObjectDescription> fromProtoDescriptor(Import anImport, Object criteria);
-
-  Collection<IEObjectDescription> descriptions(Object target, Object criteria);
-
-  Collection<IEObjectDescription> descriptions(Object target, Object criteria, int level);
-}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeSearchDelegate.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeScopeFinder.java
similarity index 93%
rename from com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeSearchDelegate.java
rename to com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeScopeFinder.java
index 493803b..a1c217b 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeSearchDelegate.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/TypeScopeFinder.java
@@ -22,16 +22,12 @@
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-class TypeSearchDelegate implements SearchDelegate {
+class TypeScopeFinder implements ScopeFinder {
 
   @Inject private ProtoDescriptorProvider descriptorProvider;
   @Inject private LocalNamesProvider localNamesProvider;
   @Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
 
-  @Override public boolean continueSearchOneLevelHigher(Object target) {
-    return target instanceof Message;
-  }
-
   @Override public Collection<IEObjectDescription> fromProtoDescriptor(Import anImport, Object criteria) {
     Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
     Class<? extends Type> targetType = targetTypeFrom(criteria);