In progress: [ Issue 45 ] Protobuf-dt should be able to open files outside workspace https://code.google.com/p/protobuf-dt/issues/detail?id=45 Initial work. Protobuf-dt now can open files outside the workspace. Outline View is working. Hyperlinking is broken.
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java index a006703..c7b82d9 100644 --- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
@@ -14,12 +14,14 @@ import org.eclipse.ui.plugin.AbstractUIPlugin; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; import org.eclipse.xtext.ui.editor.IXtextEditorCallback; +import org.eclipse.xtext.ui.editor.model.XtextDocumentProvider; import org.eclipse.xtext.ui.editor.outline.actions.IOutlineContribution; import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer; import com.google.eclipse.protobuf.scoping.IFileUriResolver; import com.google.eclipse.protobuf.ui.builder.AutoAddNatureEditorCallback; -import com.google.eclipse.protobuf.ui.editor.ProtobufHyperlinkDetector; +import com.google.eclipse.protobuf.ui.editor.hyperlinking.ProtobufHyperlinkDetector; +import com.google.eclipse.protobuf.ui.editor.model.ProtobufDocumentProvider; import com.google.eclipse.protobuf.ui.outline.LinkWithEditor; import com.google.eclipse.protobuf.ui.outline.ProtobufOutlinePage; import com.google.eclipse.protobuf.ui.preferences.compiler.CompilerPreferenceStoreInitializer; @@ -34,6 +36,8 @@ */ public class ProtobufUiModule extends AbstractProtobufUiModule { + public static final String PLUGIN_ID = "com.google.eclipse.protobuf.ui"; + public ProtobufUiModule(AbstractUIPlugin plugin) { super(plugin); } @@ -73,4 +77,8 @@ public void configureFileUriResolver(Binder binder) { binder.bind(IFileUriResolver.class).to(FileUriResolver.class); } + + public void configureDocumentProvider(Binder binder) { + binder.bind(XtextDocumentProvider.class).to(ProtobufDocumentProvider.class); + } }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ImportHyperlink.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ImportHyperlink.java similarity index 92% rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ImportHyperlink.java rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ImportHyperlink.java index ffcd9c4..93c741d 100644 --- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ImportHyperlink.java +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ImportHyperlink.java
@@ -6,7 +6,7 @@ * * http://www.eclipse.org/legal/epl-v10.html */ -package com.google.eclipse.protobuf.ui.editor; +package com.google.eclipse.protobuf.ui.editor.hyperlinking; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; @@ -53,7 +53,7 @@ private void openFromFileSystem() { IFileStore fileStore = EFS.getLocalFileSystem().getStore(new Path(importUri.toFileString())); IEditorInput editorInput = new FileStoreEditorInput(fileStore); - openFile(editorInput, "org.eclipse.ui.DefaultTextEditor"); + openFile(editorInput, "com.google.eclipse.protobuf.Protobuf"/*"org.eclipse.ui.DefaultTextEditor"*/); } private void openFile(IEditorInput editorInput, String editorId) {
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ProtobufHyperlinkDetector.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java similarity index 98% rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ProtobufHyperlinkDetector.java rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java index 729c483..59a0775 100644 --- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ProtobufHyperlinkDetector.java +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java
@@ -6,7 +6,7 @@ * * http://www.eclipse.org/legal/epl-v10.html */ -package com.google.eclipse.protobuf.ui.editor; +package com.google.eclipse.protobuf.ui.editor.hyperlinking; import static org.eclipse.emf.common.util.URI.createURI;
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 new file mode 100644 index 0000000..fc3dad8 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ProtobufDocumentProvider.java
@@ -0,0 +1,140 @@ +/* + * 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 org.eclipse.core.runtime.IStatus.ERROR; +import static org.eclipse.emf.common.util.URI.createURI; +import static org.eclipse.xtext.validation.CheckMode.FAST_ONLY; + +import java.io.*; +import java.net.URI; + +import org.eclipse.core.filesystem.*; +import org.eclipse.core.runtime.*; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.ui.IURIEditorInput; +import org.eclipse.ui.ide.FileStoreEditorInput; +import org.eclipse.xtext.parser.IParseResult; +import org.eclipse.xtext.parser.IParser; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.ui.editor.model.XtextDocument; +import org.eclipse.xtext.ui.editor.model.XtextDocumentProvider; +import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionProvider; +import org.eclipse.xtext.ui.editor.validation.AnnotationIssueProcessor; +import org.eclipse.xtext.ui.editor.validation.ValidationJob; +import org.eclipse.xtext.util.StringInputStream; +import org.eclipse.xtext.validation.IResourceValidator; + +import com.google.eclipse.protobuf.ui.util.Closeables; +import com.google.inject.Inject; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +public class ProtobufDocumentProvider extends XtextDocumentProvider { + + private static final String ENCODING = "UTF-8"; + + @Inject private Closeables closeables; + @Inject private IssueResolutionProvider issueResolutionProvider; + @Inject private IParser parser; + @Inject private IResourceValidator resourceValidator; + + @Override protected ElementInfo createElementInfo(Object element) throws CoreException { + if (element instanceof FileStoreEditorInput) { + FileStoreEditorInput input = (FileStoreEditorInput) element; + IDocument document = null; + IStatus status = null; + try { + document = createDocument(element); + } catch (CoreException e) { + handleCoreException(e, "ProtobufDocumentProvider.createElementInfo"); + document = createEmptyDocument(); + status = e.getStatus(); + } + IFileStore store = EFS.getLocalFileSystem().getStore(fileFrom(input).toURI()); + IFileInfo fileInfo = store.fetchInfo(); + IAnnotationModel model = createAnnotationModel(element); + // new FileSynchronizer(input).install(); + FileInfo info = new FileInfo(document, model, null); + info.fModificationStamp = fileInfo.getLastModified(); + info.fStatus = status; + info.fEncoding = ENCODING; + cacheEncodingState(element); + XtextDocument xtextDocument = (XtextDocument) document; + AnnotationIssueProcessor annotationIssueProcessor = new AnnotationIssueProcessor(xtextDocument, model, + issueResolutionProvider); + ValidationJob job = new ValidationJob(resourceValidator, xtextDocument, annotationIssueProcessor, FAST_ONLY); + xtextDocument.setValidationJob(job); + return info; + } + return super.createElementInfo(element); + } + + /** {@inheritDoc} */ + @Override protected IDocument createDocument(Object element) throws CoreException { + if (element instanceof FileStoreEditorInput) { + XtextDocument document = createEmptyDocument(); + FileStoreEditorInput input = (FileStoreEditorInput) element; + File file = fileFrom(input); + XtextResource resource = new XtextResource(createURI(file.toURI().toString())); + try { + String contents = contentsOf(file); + document.set(contents); + IParseResult result = parser.parse(new InputStreamReader(new StringInputStream(contents), ENCODING)); + resource.getContents().add(result.getRootASTElement()); + document.setInput(resource); + return document; + } catch (Throwable t) { + if (t instanceof CoreException) throw (CoreException) t; + throw wrapWithCoreException(t); + } + } + return super.createDocument(element); + } + + private File fileFrom(IURIEditorInput input) { + URI uri = input.getURI(); + String scheme = uri.getScheme(); + if (scheme != "file") { + String cleanUri = uri.toString().replaceFirst(scheme, "file"); + uri = URI.create(cleanUri); + } + return new File(uri); + } + + private String contentsOf(File file) throws CoreException { + Reader reader = null; + InputStream contentStream = null; + try { + contentStream = new FileInputStream(file); + reader = new BufferedReader(new InputStreamReader(contentStream, ENCODING), 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(); + } catch (IOException e) { + throw wrapWithCoreException(e); + } finally { + if (!closeables.close(reader)) closeables.close(contentStream); + } + } + + private CoreException wrapWithCoreException(Throwable cause) { + return new CoreException(new Status(ERROR, PLUGIN_ID, messageOf(cause), cause)); + } + + private String messageOf(Throwable t) { + String message = t.getMessage(); + return (message != null) ? message : ""; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectorySelectionDialogs.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectorySelectionDialogs.java index 02460b7..c9aa6e2 100644 --- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectorySelectionDialogs.java +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectorySelectionDialogs.java
@@ -8,6 +8,7 @@ */ package com.google.eclipse.protobuf.ui.preferences.paths; +import static com.google.eclipse.protobuf.ui.ProtobufUiModule.PLUGIN_ID; import static com.google.eclipse.protobuf.ui.swt.Messages.*; import static org.eclipse.core.runtime.IStatus.ERROR; import static org.eclipse.core.runtime.Status.OK_STATUS; @@ -17,9 +18,12 @@ import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.*; -import org.eclipse.ui.dialogs.*; -import org.eclipse.ui.model.*; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; +import org.eclipse.ui.dialogs.ISelectionStatusValidator; +import org.eclipse.ui.model.WorkbenchContentProvider; +import org.eclipse.ui.model.WorkbenchLabelProvider; import org.eclipse.ui.views.navigator.ResourceComparator; /** @@ -29,8 +33,6 @@ */ class DirectorySelectionDialogs { - private static final String PLUGIN_ID = "com.google.eclipse.protobuf.ui"; - static String showWorkspaceDirectoryDialog(Shell shell, String initialPath) { return showWorkspaceDirectoryDialog(shell, initialPath, null); }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Closeables.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Closeables.java new file mode 100644 index 0000000..4abef77 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Closeables.java
@@ -0,0 +1,28 @@ +/* + * 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.util; + +import java.io.Closeable; +import java.io.IOException; + +import com.google.inject.Singleton; + +/** + * Utility methods related to <code>{@link Closeable}</code>. + * + * @author alruiz@google.com (Alex Ruiz) + */ +@Singleton +public class Closeables { + + public boolean close(Closeable c) { + if (c == null) return false; + try { + c.close(); + } catch (IOException ignored) {} + return true; + } +}