Fixed: [Issue 95] Add ability to view descriptor.proto in an editor.
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/UriEditorInput.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/UriEditorInput.java
new file mode 100644
index 0000000..ec8697d
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/UriEditorInput.java
@@ -0,0 +1,80 @@
+/*
+ * 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.ui.editor;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IPersistableElement;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class UriEditorInput implements IEditorInput {
+
+  private final URI fileUri;
+  private final String name;
+
+  public UriEditorInput(URI fileUri, String name) {
+    this.fileUri = fileUri.trimFragment();
+    this.name = name;
+  }
+
+  @SuppressWarnings("rawtypes")
+  public Object getAdapter(Class adapter) {
+    return Platform.getAdapterManager().getAdapter(this, adapter);
+  }
+
+  public boolean exists() {
+    return false;
+  }
+
+  public ImageDescriptor getImageDescriptor() {
+    return null;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public IPersistableElement getPersistable() {
+    return null;
+  }
+
+  public String getToolTipText() {
+    return name;
+  }
+
+  public URI getFileUri() {
+    return fileUri;
+  }
+
+  @Override public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + ((name == null) ? 0 : name.hashCode());
+    result = prime * result + ((fileUri == null) ? 0 : fileUri.hashCode());
+    return result;
+  }
+
+  @Override public boolean equals(Object obj) {
+    if (this == obj) return true;
+    if (obj == null) return false;
+    if (getClass() != obj.getClass()) return false;
+    UriEditorInput other = (UriEditorInput) obj;
+    if (name == null) {
+      if (other.name != null) return false;
+    } else if (!name.equals(other.name)) return false;
+    if (fileUri == null) {
+      if (other.fileUri != null) return false;
+    } else if (!fileUri.equals(other.fileUri)) return false;
+    return true;
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java
index b7abcae..8cfd4e1 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java
@@ -23,7 +23,6 @@
 
 import com.google.eclipse.protobuf.protobuf.Import;
 import com.google.eclipse.protobuf.ui.util.Resources;
-import com.google.eclipse.protobuf.util.Imports;
 import com.google.inject.Inject;
 
 /**
@@ -39,7 +38,6 @@
   private static final char QUOTE = '\"';
 
   @Inject private EObjectAtOffsetHelper eObjectAtOffsetHelper;
-  @Inject private Imports imports;
   @Inject private Resources resources;
 
   @Override public IHyperlink[] detectHyperlinks(ITextViewer textViewer, final IRegion region,
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ContentReader.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ContentReader.java
new file mode 100644
index 0000000..107ca0a
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ContentReader.java
@@ -0,0 +1,46 @@
+/*
+ * 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.ui.editor.model;
+
+import static com.google.eclipse.protobuf.util.Closeables.close;
+import static com.google.eclipse.protobuf.util.Encodings.UTF_8;
+
+import java.io.*;
+
+import com.google.inject.Singleton;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@Singleton
+class ContentReader {
+
+  private static final int DEFAULT_FILE_SIZE= 15 * 1024;
+
+  String contentsOf(InputStream inputStream) throws IOException {
+    Reader reader = null;
+    try {
+      reader = new BufferedReader(readerFor(inputStream), DEFAULT_FILE_SIZE);
+      StringBuilder contents = new StringBuilder(DEFAULT_FILE_SIZE);
+      char[] buffer = new char[2048];
+      int character = reader.read(buffer);
+      while (character > 0) {
+        contents.append(buffer, 0, character);
+        character = reader.read(buffer);
+      }
+      return contents.toString();
+    } finally {
+      close(reader);
+    }
+  }
+
+  private Reader readerFor(InputStream inputStream) throws IOException {
+    return new InputStreamReader(inputStream, UTF_8);
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/DocumentContentsFactory.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/DocumentContentsFactory.java
new file mode 100644
index 0000000..c8eb09b
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/DocumentContentsFactory.java
@@ -0,0 +1,23 @@
+/*
+ * 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.ui.editor.model;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.xtext.ui.editor.model.XtextDocument;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+interface DocumentContentsFactory {
+
+  void createContents(XtextDocument document, Object element) throws CoreException;
+
+  boolean supportsEditorInputType(IEditorInput input);
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/DocumentContentsFactoryRegistry.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/DocumentContentsFactoryRegistry.java
new file mode 100644
index 0000000..d8c1b1d
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/DocumentContentsFactoryRegistry.java
@@ -0,0 +1,39 @@
+/*
+ * 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.ui.editor.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.ui.IEditorInput;
+
+import com.google.inject.Inject;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class DocumentContentsFactoryRegistry {
+
+  private final List<DocumentContentsFactory> factories = new ArrayList<DocumentContentsFactory>();
+
+  @Inject
+  DocumentContentsFactoryRegistry(FileStoreDocumentContentsFactory factory1, UriDocumentContentsFactory factory2) {
+    factories.add(factory1);
+    factories.add(factory2);
+  }
+
+  DocumentContentsFactory findFactory(Object element) {
+    if (!(element instanceof IEditorInput)) return null;
+    IEditorInput input = (IEditorInput) element;
+    for (DocumentContentsFactory factory : factories) {
+      if (factory.supportsEditorInputType(input)) return factory;
+    }
+    return null;
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/FileStoreDocumentContentsFactory.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/FileStoreDocumentContentsFactory.java
new file mode 100644
index 0000000..c8146ab
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/FileStoreDocumentContentsFactory.java
@@ -0,0 +1,91 @@
+/*
+ * 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.ui.editor.model;
+
+import static com.google.eclipse.protobuf.ui.ProtobufUiModule.PLUGIN_ID;
+import static com.google.eclipse.protobuf.util.Closeables.close;
+import static com.google.eclipse.protobuf.util.Encodings.UTF_8;
+import static java.util.Collections.singletonMap;
+import static org.eclipse.core.runtime.IStatus.ERROR;
+import static org.eclipse.emf.common.util.URI.createURI;
+import static org.eclipse.emf.ecore.resource.ContentHandler.UNSPECIFIED_CONTENT_TYPE;
+import static org.eclipse.xtext.EcoreUtil2.resolveLazyCrossReferences;
+import static org.eclipse.xtext.resource.XtextResource.OPTION_ENCODING;
+import static org.eclipse.xtext.util.CancelIndicator.NullImpl;
+
+import java.io.*;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.ide.FileStoreEditorInput;
+import org.eclipse.xtext.resource.XtextResource;
+import org.eclipse.xtext.ui.editor.model.XtextDocument;
+import org.eclipse.xtext.ui.resource.IResourceSetProvider;
+import org.eclipse.xtext.util.StringInputStream;
+
+import com.google.eclipse.protobuf.ui.util.Resources;
+import com.google.inject.Inject;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class FileStoreDocumentContentsFactory implements DocumentContentsFactory {
+
+  @Inject private IResourceSetProvider resourceSetProvider;
+  @Inject private Resources resources;
+  @Inject private Files files;
+  @Inject private ContentReader contentReader;
+
+  public void createContents(XtextDocument document, Object element) throws CoreException {
+    FileStoreEditorInput input = supportedEditorInputType().cast(element);
+    File file = files.fileFrom(input);
+    try {
+      String contents = contentsOf(file);
+      document.set(contents);
+      XtextResource resource = createResource(file.toURI().toString(), new StringInputStream(contents));
+      document.setInput(resource);
+    } catch (Throwable t) {
+      String message = t.getMessage();
+      if (message == null) message = "";
+      throw new CoreException(new Status(ERROR, PLUGIN_ID, message, t));
+    }
+  }
+
+  private String contentsOf(File file) throws IOException {
+    InputStream inputStream = null;
+    try {
+      inputStream = new FileInputStream(file);
+      return contentReader.contentsOf(inputStream);
+    } finally {
+      close(inputStream);
+    }
+  }
+
+  private XtextResource createResource(String uri, InputStream input) {
+    ResourceSet resourceSet = resourceSetProvider.get(resources.activeProject());
+    XtextResource resource = (XtextResource) resourceSet.createResource(createURI(uri), UNSPECIFIED_CONTENT_TYPE);
+    try {
+      resource.load(input, singletonMap(OPTION_ENCODING, UTF_8));
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+    resolveLazyCrossReferences(resource, NullImpl);
+    return resource;
+  }
+
+  public boolean supportsEditorInputType(IEditorInput input) {
+    return supportedEditorInputType().isInstance(input);
+  }
+
+  private Class<FileStoreEditorInput> supportedEditorInputType() {
+    return FileStoreEditorInput.class;
+  }
+}
\ No newline at end of file
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/Files.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/Files.java
new file mode 100644
index 0000000..48252ce
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/Files.java
@@ -0,0 +1,35 @@
+/*
+ * 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.ui.editor.model;
+
+import static com.google.eclipse.protobuf.ui.util.Resources.URI_SCHEME_FOR_FILES;
+
+import java.io.File;
+import java.net.URI;
+
+import org.eclipse.ui.IURIEditorInput;
+
+import com.google.inject.Singleton;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@Singleton
+class Files {
+
+  File fileFrom(IURIEditorInput input) {
+    URI uri = input.getURI();
+    String scheme = uri.getScheme();
+    if (scheme != URI_SCHEME_FOR_FILES) {
+      String cleanUri = uri.toString().replaceFirst(scheme, URI_SCHEME_FOR_FILES);
+      uri = URI.create(cleanUri);
+    }
+    return new File(uri);
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ProtobufDocumentProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ProtobufDocumentProvider.java
index 72388c3..89391e6 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ProtobufDocumentProvider.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ProtobufDocumentProvider.java
@@ -1,62 +1,45 @@
 /*
  * 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.ui.editor.model;
 
 import static com.google.eclipse.protobuf.ui.ProtobufUiModule.PLUGIN_ID;
-import static com.google.eclipse.protobuf.ui.util.Resources.URI_SCHEME_FOR_FILES;
-import static com.google.eclipse.protobuf.util.Closeables.close;
 import static com.google.eclipse.protobuf.util.Encodings.UTF_8;
-import static java.util.Collections.singletonMap;
 import static org.eclipse.core.runtime.IStatus.ERROR;
-import static org.eclipse.emf.common.util.URI.createURI;
-import static org.eclipse.emf.ecore.resource.ContentHandler.UNSPECIFIED_CONTENT_TYPE;
 import static org.eclipse.text.undo.DocumentUndoManagerRegistry.getDocumentUndoManager;
-import static org.eclipse.xtext.EcoreUtil2.resolveLazyCrossReferences;
-import static org.eclipse.xtext.resource.XtextResource.OPTION_ENCODING;
-import static org.eclipse.xtext.util.CancelIndicator.NullImpl;
 
-import com.google.eclipse.protobuf.ui.util.Resources;
-import com.google.inject.Inject;
-
-import org.eclipse.core.filesystem.*;
 import org.eclipse.core.runtime.*;
-import org.eclipse.emf.ecore.resource.ResourceSet;
 import org.eclipse.jface.text.*;
 import org.eclipse.jface.text.source.IAnnotationModel;
 import org.eclipse.text.edits.TextEdit;
 import org.eclipse.text.undo.IDocumentUndoManager;
-import org.eclipse.ui.*;
-import org.eclipse.ui.ide.FileStoreEditorInput;
-import org.eclipse.xtext.resource.XtextResource;
-import org.eclipse.xtext.ui.editor.model.*;
-import org.eclipse.xtext.ui.resource.IResourceSetProvider;
-import org.eclipse.xtext.util.StringInputStream;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.xtext.ui.editor.model.XtextDocument;
+import org.eclipse.xtext.ui.editor.model.XtextDocumentProvider;
 
-import java.io.*;
-import java.net.URI;
+import com.google.inject.Inject;
 
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
 public class ProtobufDocumentProvider extends XtextDocumentProvider {
 
-  @Inject private IResourceSetProvider resourceSetProvider;
-  @Inject private Resources resources;
+  @Inject private DocumentContentsFactoryRegistry contentsFactories;
   @Inject private SaveActions saveActions;
 
   @Override protected ElementInfo createElementInfo(Object element) throws CoreException {
-    if (element instanceof FileStoreEditorInput) return createElementInfo((FileStoreEditorInput) element);
+    if (contentsFactories.findFactory(element) != null) return createElementInfo((IEditorInput) element);
     return super.createElementInfo(element);
   }
 
-  private ElementInfo createElementInfo(FileStoreEditorInput input) throws CoreException {
+  private ElementInfo createElementInfo(IEditorInput input) throws CoreException {
     IDocument document = null;
     IStatus status = null;
     try {
@@ -66,12 +49,9 @@
       document = createEmptyDocument();
       status = e.getStatus();
     }
-    IFileStore store = EFS.getLocalFileSystem().getStore(fileFrom(input).toURI());
-    IFileInfo fileInfo = store.fetchInfo();
     IAnnotationModel model = createAnnotationModel(input);
     // new FileSynchronizer(input).install();
     FileInfo info = new FileInfo(document, model, null);
-    info.fModificationStamp = fileInfo.getLastModified();
     info.fStatus = status;
     info.fEncoding = UTF_8;
     cacheEncodingState(input);
@@ -79,69 +59,15 @@
   }
 
   @Override protected IDocument createDocument(Object element) throws CoreException {
-    if (element instanceof FileStoreEditorInput) return createDocument((FileStoreEditorInput) element);
+    DocumentContentsFactory contentsFactory = contentsFactories.findFactory(element);
+    if (contentsFactory != null) return createDocument(contentsFactory, element);
     return super.createDocument(element);
   }
 
-  private IDocument createDocument(FileStoreEditorInput input) throws CoreException {
+  private IDocument createDocument(DocumentContentsFactory contentsFactory, Object element) throws CoreException {
     XtextDocument document = createEmptyDocument();
-    File file = fileFrom(input);
-    try {
-      String contents = contentsOf(file);
-      document.set(contents);
-      XtextResource resource = createResource(file.toURI().toString(), new StringInputStream(contents));
-      document.setInput(resource);
-      return document;
-    } catch (Throwable t) {
-      String message = t.getMessage();
-      if (message == null) message = "";
-      throw new CoreException(new Status(ERROR, PLUGIN_ID, message, t));
-    }
-  }
-
-  private File fileFrom(IURIEditorInput input) {
-    URI uri = input.getURI();
-    String scheme = uri.getScheme();
-    if (scheme != URI_SCHEME_FOR_FILES) {
-      String cleanUri = uri.toString().replaceFirst(scheme, URI_SCHEME_FOR_FILES);
-      uri = URI.create(cleanUri);
-    }
-    return new File(uri);
-  }
-
-  private String contentsOf(File file) throws IOException {
-    Reader reader = null;
-    InputStream inputStream = null;
-    try {
-      inputStream = new FileInputStream(file);
-      reader = new BufferedReader(readerFor(inputStream), DEFAULT_FILE_SIZE);
-      StringBuilder contents = new StringBuilder(DEFAULT_FILE_SIZE);
-      char[] buffer = new char[2048];
-      int character = reader.read(buffer);
-      while (character > 0) {
-        contents.append(buffer, 0, character);
-        character = reader.read(buffer);
-      }
-      return contents.toString();
-    } finally {
-      if (!close(reader)) close(inputStream);
-    }
-  }
-
-  private Reader readerFor(InputStream inputStream) throws IOException {
-    return new InputStreamReader(inputStream, UTF_8);
-  }
-
-  private XtextResource createResource(String uri, InputStream input) {
-    ResourceSet resourceSet = resourceSetProvider.get(resources.activeProject());
-    XtextResource resource = (XtextResource) resourceSet.createResource(createURI(uri), UNSPECIFIED_CONTENT_TYPE);
-    try {
-      resource.load(input, singletonMap(OPTION_ENCODING, UTF_8));
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-    resolveLazyCrossReferences(resource, NullImpl);
-    return resource;
+    contentsFactory.createContents(document, element);
+    return document;
   }
 
   @Override protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document,
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/UriDocumentContentsFactory.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/UriDocumentContentsFactory.java
new file mode 100644
index 0000000..027d3b3
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/UriDocumentContentsFactory.java
@@ -0,0 +1,75 @@
+/*
+ * 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.ui.editor.model;
+
+import static com.google.eclipse.protobuf.ui.ProtobufUiModule.PLUGIN_ID;
+import static com.google.eclipse.protobuf.util.Closeables.close;
+import static org.eclipse.core.runtime.IStatus.ERROR;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.xtext.ui.editor.model.XtextDocument;
+
+import com.google.eclipse.protobuf.scoping.ProtoDescriptor;
+import com.google.eclipse.protobuf.scoping.ProtoDescriptorProvider;
+import com.google.eclipse.protobuf.ui.editor.UriEditorInput;
+import com.google.inject.Inject;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class UriDocumentContentsFactory implements DocumentContentsFactory {
+
+  @Inject private ProtoDescriptorProvider descriptorProvider;
+  @Inject private ContentReader contentReader;
+
+  public void createContents(XtextDocument document, Object element) throws CoreException {
+    UriEditorInput input = supportedEditorInputType().cast(element);
+    URI uri = input.getFileUri().trimFragment();
+    if (!descriptorProvider.descriptorLocation().equals(uri)) {
+      throw new UnsupportedOperationException("File to open is not descriptor.proto");
+    }
+    ProtoDescriptor descriptor = descriptorProvider.get();
+    try {
+      String contents = contentsOf(uri);
+      document.set(contents);
+      document.setInput(descriptor.resource());
+    } catch (Throwable t) {
+      String message = t.getMessage();
+      if (message == null) message = "";
+      // TODO remove duplication
+      throw new CoreException(new Status(ERROR, PLUGIN_ID, message, t));
+    }
+  }
+
+  private String contentsOf(URI uri) throws IOException {
+    InputStream inputStream = null;
+    try {
+      URL url = new URL(uri.toString());
+      inputStream = url.openConnection().getInputStream();
+      return contentReader.contentsOf(inputStream);
+    } finally {
+      close(inputStream);
+    }
+  }
+
+  public boolean supportsEditorInputType(IEditorInput input) {
+    return supportedEditorInputType().isInstance(input);
+  }
+
+  private Class<UriEditorInput> supportedEditorInputType() {
+    return UriEditorInput.class;
+  }
+}
\ No newline at end of file
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Resources.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Resources.java
index 1e9b653..99a7eb8 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Resources.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Resources.java
@@ -17,11 +17,10 @@
 import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.ui.*;
 import org.eclipse.ui.ide.FileStoreEditorInput;
-import org.eclipse.ui.internal.editors.text.EditorsPlugin;
-import org.eclipse.ui.internal.editors.text.NonExistingFileEditorInput;
 import org.eclipse.ui.part.FileEditorInput;
 import org.eclipse.ui.views.navigator.ResourceNavigator;
 
+import com.google.eclipse.protobuf.ui.editor.UriEditorInput;
 import com.google.inject.Singleton;
 
 /**
@@ -93,20 +92,11 @@
     return openFile(editorInput/*"org.eclipse.ui.DefaultTextEditor"*/);
   }
 
-  @SuppressWarnings("restriction")
   public IEditorPart openProtoFileInPlugin(URI uri) throws PartInitException {
-    IFileStore fileStore = queryFileStore();
-    IEditorInput editorInput = new NonExistingFileEditorInput(fileStore, "descriptor.proto");
+    IEditorInput editorInput = new UriEditorInput(uri, "descriptor.proto");
     return openFile(editorInput);
   }
 
-  @SuppressWarnings("restriction")
-  private IFileStore queryFileStore() {
-    IPath stateLocation = EditorsPlugin.getDefault().getStateLocation();
-    IPath path = stateLocation.append("/_" + new Object().hashCode()); //$NON-NLS-1$
-    return EFS.getLocalFileSystem().getStore(path);
-  }
-
   private IEditorPart openFile(IEditorInput editorInput) throws PartInitException {
     IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
     return page.openEditor(editorInput, "com.google.eclipse.protobuf.Protobuf");
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor.java
index e10394d..a5d0231 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtoDescriptor.java
@@ -56,13 +56,14 @@
   private Protobuf root;
 
   private final ModelNodes nodes;
+  private final XtextResource resource;
 
   @Inject public ProtoDescriptor(IParser parser, URI descriptorLocation, ModelNodes nodes) {
     this.nodes = nodes;
     addOptionTypes();
     InputStreamReader reader = null;
     try {
-      XtextResource resource = new XtextResource(descriptorLocation);
+      resource = new XtextResource(descriptorLocation);
       reader = new InputStreamReader(contents(descriptorLocation), UTF_8);
       IParseResult result = parser.parse(reader);
       root = (Protobuf) result.getRootASTElement();
@@ -243,4 +244,8 @@
   public List<Type> allTypes() {
     return unmodifiableList(allTypes);
   }
+
+  public XtextResource resource() {
+    return resource;
+  }
 }
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 cb3d5b1..6c50689 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
@@ -33,7 +33,8 @@
 import com.google.eclipse.protobuf.protobuf.*;
 import com.google.eclipse.protobuf.protobuf.Enum;
 import com.google.eclipse.protobuf.protobuf.Package;
-import com.google.eclipse.protobuf.util.*;
+import com.google.eclipse.protobuf.util.FieldOptions;
+import com.google.eclipse.protobuf.util.ProtobufElementFinder;
 import com.google.inject.Inject;
 
 /**
@@ -55,7 +56,6 @@
   @Inject private LocalNamesProvider localNamesProvider;
   @Inject private ImportedNamesProvider importedNamesProvider;
   @Inject private PackageResolver packageResolver;
-  @Inject private Imports imports;
 
   @SuppressWarnings("unused")
   IScope scope_TypeRef_type(TypeRef typeRef, EReference reference) {
@@ -119,7 +119,7 @@
       Class<T> targetType) {
     List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
     for (Import anImport : allImports) {
-      if (imports.hasUnresolvedDescriptorUri(anImport)) {
+      if (isImportingDescriptor(anImport)) {
         descriptions.addAll(allBuiltInTypes(targetType));
         continue;
       }
@@ -135,6 +135,10 @@
     return descriptions;
   }
 
+  private boolean isImportingDescriptor(Import anImport) {
+    return descriptorProvider.descriptorLocation().toString().equals(anImport.getImportURI());
+  }
+
   private <T extends Type> Collection<IEObjectDescription> allBuiltInTypes(Class<T> targetType) {
     List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
     ProtoDescriptor descriptor = descriptorProvider.get();