Initial code import. This plug-in is pretty functional already: * Working editor with content-assist based on grammar, context and data type * Imports of .proto files works * Content-assist for common options * Outline View * Preferences for using protoc on save * Error markers based on protoc's output
diff --git a/com.google.eclipse.protobuf.ui/.classpath b/com.google.eclipse.protobuf.ui/.classpath new file mode 100644 index 0000000..7e8449d --- /dev/null +++ b/com.google.eclipse.protobuf.ui/.classpath
@@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="src-gen"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="output" path="bin"/> +</classpath>
diff --git a/com.google.eclipse.protobuf.ui/.project b/com.google.eclipse.protobuf.ui/.project new file mode 100644 index 0000000..aa5cde0 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/.project
@@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>com.google.eclipse.protobuf.ui</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + <nature>org.eclipse.pde.PluginNature</nature> + </natures> +</projectDescription>
diff --git a/com.google.eclipse.protobuf.ui/.settings/org.eclipse.jdt.core.prefs b/com.google.eclipse.protobuf.ui/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..47c08ff --- /dev/null +++ b/com.google.eclipse.protobuf.ui/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,81 @@ +#Wed Apr 06 10:56:25 PDT 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=warning +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.5
diff --git a/com.google.eclipse.protobuf.ui/META-INF/MANIFEST.MF b/com.google.eclipse.protobuf.ui/META-INF/MANIFEST.MF new file mode 100644 index 0000000..4098738 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,29 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %Bundle-Name +Bundle-Vendor: %Bundle-Vendor +Bundle-Version: 1.0.0 +Bundle-SymbolicName: com.google.eclipse.protobuf.ui; singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: com.google.eclipse.protobuf;visibility:=reexport, + org.eclipse.xtext.ui, + org.eclipse.ui.editors;bundle-version="3.5.0", + org.eclipse.ui.ide;bundle-version="3.5.0", + org.eclipse.xtext.ui.shared, + org.eclipse.ui, + org.eclipse.xtext.builder, + org.antlr.runtime, + org.eclipse.core.runtime, + org.eclipse.core.databinding, + org.eclipse.core.databinding.beans, + org.eclipse.core.databinding.observable, + org.eclipse.core.databinding.property, + org.eclipse.jface.databinding, + com.ibm.icu, + org.eclipse.emf.databinding, + org.eclipse.core.resources +Import-Package: org.apache.log4j, + org.apache.commons.logging +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Export-Package: com.google.eclipse.protobuf.ui.contentassist.antlr +Bundle-Activator: com.google.eclipse.protobuf.ui.internal.ProtobufActivator
diff --git a/com.google.eclipse.protobuf.ui/OSGI-INF/l10n/bundle.properties b/com.google.eclipse.protobuf.ui/OSGI-INF/l10n/bundle.properties new file mode 100644 index 0000000..b699865 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/OSGI-INF/l10n/bundle.properties
@@ -0,0 +1,19 @@ +#Properties file for com.google.eclipse.protobuf.ui +Bundle-Vendor = Google Inc. +Bundle-Name = com.google.eclipse.protobuf.ui +editor.name = Protocol Buffer Editor +page.name = Protocol Buffer +page.name.0 = Syntax Coloring +page.name.1 = Templates +page.name.2 = Compiler +page.name.3 = Protocol Buffer Compiler +keyword.label = Protocol Buffer +command.description = Trigger expensive validation +command.name = Validate +command.tooltip = Trigger expensive validation +command.description.0 = Open the quick outline. +command.name.0 = Quick Outline +command.tooltip.0 = Open Quick Outline +command.description.1 = Insert semicolon. +command.name.1 = Insert semicolon +command.tooltip.1 = Insert semicolon \ No newline at end of file
diff --git a/com.google.eclipse.protobuf.ui/build.properties b/com.google.eclipse.protobuf.ui/build.properties new file mode 100644 index 0000000..300fb1a --- /dev/null +++ b/com.google.eclipse.protobuf.ui/build.properties
@@ -0,0 +1,6 @@ +source.. = src/,\ + src-gen/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + OSGI-INF/
diff --git a/com.google.eclipse.protobuf.ui/icons/empty.gif b/com.google.eclipse.protobuf.ui/icons/empty.gif new file mode 100644 index 0000000..9cd97c2 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/empty.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/enum.gif b/com.google.eclipse.protobuf.ui/icons/enum.gif new file mode 100644 index 0000000..15535f5 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/enum.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/extend.gif b/com.google.eclipse.protobuf.ui/icons/extend.gif new file mode 100644 index 0000000..e8abf43 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/extend.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/extensions.gif b/com.google.eclipse.protobuf.ui/icons/extensions.gif new file mode 100644 index 0000000..13500b7 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/extensions.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/import.gif b/com.google.eclipse.protobuf.ui/icons/import.gif new file mode 100644 index 0000000..9e44ce5 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/import.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/literal.gif b/com.google.eclipse.protobuf.ui/icons/literal.gif new file mode 100644 index 0000000..5b881d8 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/literal.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/message.gif b/com.google.eclipse.protobuf.ui/icons/message.gif new file mode 100644 index 0000000..e24e9e3 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/message.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/option.gif b/com.google.eclipse.protobuf.ui/icons/option.gif new file mode 100644 index 0000000..9d8c615 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/option.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/package.gif b/com.google.eclipse.protobuf.ui/icons/package.gif new file mode 100644 index 0000000..131c28d --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/package.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/pb.gif b/com.google.eclipse.protobuf.ui/icons/pb.gif new file mode 100644 index 0000000..4fcebf9 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/pb.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/property-opt.gif b/com.google.eclipse.protobuf.ui/icons/property-opt.gif new file mode 100644 index 0000000..6e3302d --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/property-opt.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/property-rep.gif b/com.google.eclipse.protobuf.ui/icons/property-rep.gif new file mode 100644 index 0000000..ae61259 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/property-rep.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/property-req.gif b/com.google.eclipse.protobuf.ui/icons/property-req.gif new file mode 100644 index 0000000..5611cce --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/property-req.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/property.gif b/com.google.eclipse.protobuf.ui/icons/property.gif new file mode 100644 index 0000000..cd83b96 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/property.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/icons/protobuf.gif b/com.google.eclipse.protobuf.ui/icons/protobuf.gif new file mode 100644 index 0000000..5f161d9 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/icons/protobuf.gif Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/plugin.xml b/com.google.eclipse.protobuf.ui/plugin.xml new file mode 100644 index 0000000..6a3942f --- /dev/null +++ b/com.google.eclipse.protobuf.ui/plugin.xml
@@ -0,0 +1,243 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?eclipse version="3.0"?> + +<plugin> + + <extension + point="org.eclipse.ui.editors"> + <editor + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:org.eclipse.xtext.ui.editor.XtextEditor" + contributorClass="org.eclipse.ui.editors.text.TextEditorActionContributor" + default="true" + extensions="proto" + icon="icons/pb.gif" + id="com.google.eclipse.protobuf.Protobuf" + name="%editor.name"> + </editor> + </extension> + <extension + point="org.eclipse.ui.handlers"> + <handler + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:org.eclipse.xtext.ui.editor.hyperlinking.OpenDeclarationHandler" + commandId="org.eclipse.xtext.ui.editor.hyperlinking.OpenDeclaration"> + <activeWhen> + <reference + definitionId="com.google.eclipse.protobuf.Protobuf.Editor.opened"> + </reference> + </activeWhen> + </handler> + <handler + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:org.eclipse.xtext.ui.editor.handler.ValidateActionHandler" + commandId="com.google.eclipse.protobuf.Protobuf.validate"> + <activeWhen> + <reference + definitionId="com.google.eclipse.protobuf.Protobuf.Editor.opened"> + </reference> + </activeWhen> + </handler> + <handler + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.commands.SmartSemicolonHandler" + commandId="com.google.eclipse.protobuf.ui.smartSemicolon"> + <activeWhen> + <reference + definitionId="com.google.eclipse.protobuf.Protobuf.Editor.opened"> + </reference> + </activeWhen> + </handler> + </extension> + <extension point="org.eclipse.core.expressions.definitions"> + <definition id="com.google.eclipse.protobuf.Protobuf.Editor.opened"> + <and> + <reference definitionId="isActiveEditorAnInstanceOfXtextEditor"/> + <with variable="activeEditor"> + <test property="org.eclipse.xtext.ui.editor.XtextEditor.languageName" + value="com.google.eclipse.protobuf.Protobuf" + forcePluginActivation="true"/> + </with> + </and> + </definition> + </extension> + <extension + point="org.eclipse.ui.preferencePages"> + <page + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:org.eclipse.xtext.ui.editor.preferences.LanguageRootPreferencePage" + id="com.google.eclipse.protobuf.Protobuf" + name="%page.name"> + <keywordReference id="com.google.eclipse.protobuf.ui.keyword_Protobuf"/> + </page> + <page + category="com.google.eclipse.protobuf.Protobuf" + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:org.eclipse.xtext.ui.editor.syntaxcoloring.SyntaxColoringPreferencePage" + id="com.google.eclipse.protobuf.Protobuf.coloring" + name="%page.name.0"> + <keywordReference id="com.google.eclipse.protobuf.ui.keyword_Protobuf"/> + </page> + <page + category="com.google.eclipse.protobuf.Protobuf" + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:org.eclipse.xtext.ui.editor.templates.XtextTemplatePreferencePage" + id="com.google.eclipse.protobuf.Protobuf.templates" + name="%page.name.1"> + <keywordReference id="com.google.eclipse.protobuf.ui.keyword_Protobuf"/> + </page> + <page + category="com.google.eclipse.protobuf.Protobuf" + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.preferences.CompilerPreferencePage" + id="com.google.eclipse.protobuf.ui.preferences.CompilerPreferencePage" + name="%page.name.2"> + <keywordReference id="com.google.eclipse.protobuf.ui.keyword_Protobuf"/> + </page> + </extension> + <extension + point="org.eclipse.ui.keywords"> + <keyword + id="com.google.eclipse.protobuf.ui.keyword_Protobuf" + label="%keyword.label"/> + </extension> + <extension + point="org.eclipse.ui.commands"> + <command + description="%command.description" + id="com.google.eclipse.protobuf.Protobuf.validate" + name="%command.name"> + </command> + </extension> + <extension point="org.eclipse.ui.menus"> + <menuContribution + locationURI="popup:#TextEditorContext?after=group.edit"> + <command + commandId="com.google.eclipse.protobuf.Protobuf.validate" + style="push" + tooltip="%command.tooltip"> + <visibleWhen checkEnabled="false"> + <reference + definitionId="com.google.eclipse.protobuf.Protobuf.Editor.opened"> + </reference> + </visibleWhen> + </command> + </menuContribution> + </extension> + <extension point="org.eclipse.ui.menus"> + <menuContribution locationURI="popup:#TextEditorContext?endof=group.find"> + <command commandId="org.eclipse.xtext.ui.editor.FindReferences"> + <visibleWhen checkEnabled="false"> + <reference definitionId="com.google.eclipse.protobuf.Protobuf.Editor.opened"> + </reference> + </visibleWhen> + </command> + </menuContribution> + </extension> + <extension point="org.eclipse.ui.handlers"> + <handler + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:org.eclipse.xtext.ui.editor.findrefs.FindReferencesHandler" + commandId="org.eclipse.xtext.ui.editor.FindReferences"> + <activeWhen> + <reference + definitionId="com.google.eclipse.protobuf.Protobuf.Editor.opened"> + </reference> + </activeWhen> + </handler> + </extension> + +<!-- adding resource factories --> + + <extension + point="org.eclipse.emf.ecore.extension_parser"> + <parser + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:org.eclipse.xtext.resource.IResourceFactory" + type="proto"> + </parser> + </extension> + <extension point="org.eclipse.xtext.extension_resourceServiceProvider"> + <resourceServiceProvider + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:org.eclipse.xtext.ui.resource.IResourceUIServiceProvider" + uriExtension="proto"> + </resourceServiceProvider> + </extension> + + + + <!-- Quick Outline --> + <extension + point="org.eclipse.ui.handlers"> + <handler + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:org.eclipse.xtext.ui.editor.outline.quickoutline.ShowQuickOutlineActionHandler" + commandId="org.eclipse.xtext.ui.editor.outline.QuickOutline"> + <activeWhen> + <reference + definitionId="com.google.eclipse.protobuf.Protobuf.Editor.opened"> + </reference> + </activeWhen> + </handler> + </extension> + <extension + point="org.eclipse.ui.commands"> + <command + description="%command.description.0" + id="org.eclipse.xtext.ui.editor.outline.QuickOutline" + name="%command.name.0"> + </command> + <command + categoryId="org.eclipse.ui.category.textEditor" + description="%command.description.1" + id="com.google.eclipse.protobuf.ui.smartSemicolon" + name="%command.name.1"> + </command> + </extension> + <extension point="org.eclipse.ui.menus"> + <menuContribution + locationURI="popup:#TextEditorContext?after=group.open"> + <command commandId="org.eclipse.xtext.ui.editor.outline.QuickOutline" + style="push" + tooltip="%command.tooltip.0"> + <visibleWhen checkEnabled="false"> + <reference definitionId="com.google.eclipse.protobuf.Protobuf.Editor.opened"/> + </visibleWhen> + </command> + </menuContribution> + </extension> + <!-- quickfix marker resolution generator --> + <extension + point="org.eclipse.ui.ide.markerResolution"> + <markerResolutionGenerator + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:org.eclipse.xtext.ui.editor.quickfix.MarkerResolutionGenerator"> + </markerResolutionGenerator> + </extension> + <extension + point="org.eclipse.ui.bindings"> + <key + commandId="com.google.eclipse.protobuf.ui.smartSemicolon" + contextId="org.eclipse.xtext.ui.XtextEditorScope" + schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" + sequence=";"> + </key> + </extension> + <extension + point="org.eclipse.ui.propertyPages"> + <page + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.preferences.CompilerPreferencePage" + id="com.google.eclipse.protobuf.ui.properties.CompilerPropertyPage" + name="%page.name.3" + selectionFilter="single"> + </page> + </extension> + <extension + point="org.eclipse.xtext.builder.participant"> + <participant + class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.builder.ProtobufBuildParticipant"> + </participant> + </extension> + <extension + id="pbmarker" + name="Protocol Buffer Marker" + point="org.eclipse.core.resources.markers"> + <super + type="org.eclipse.core.resources.problemmarker"> + </super> + <super + type="org.eclipse.core.resources.textmarker"> + </super> + <persistent + value="true"> + </persistent> + </extension> +</plugin>
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 new file mode 100644 index 0000000..99e78a5 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
@@ -0,0 +1,56 @@ +/* + * 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; + +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.outline.actions.IOutlineContribution; +import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer; + +import com.google.eclipse.protobuf.ui.builder.AutoAddNatureEditorCallback; +import com.google.eclipse.protobuf.ui.outline.LinkWithEditor; +import com.google.eclipse.protobuf.ui.outline.ProtobufOutlinePage; +import com.google.eclipse.protobuf.ui.preferences.CompilerPreferencesInitializer; +import com.google.inject.Binder; +import com.google.inject.name.Names; + +/** + * Use this class to register components to be used within the IDE. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class ProtobufUiModule extends AbstractProtobufUiModule { + + public ProtobufUiModule(AbstractUIPlugin plugin) { + super(plugin); + } + + @Override public Class<? extends IContentOutlinePage> bindIContentOutlinePage() { + return ProtobufOutlinePage.class; + } + + @Override public Class<? extends IXtextEditorCallback> bindIXtextEditorCallback() { + return AutoAddNatureEditorCallback.class; + } + + /** {@inheritDoc} */ + @Override public void configureToggleLinkWithEditorOutlineContribution(Binder binder) { + binder.bind(IOutlineContribution.class) + .annotatedWith(IOutlineContribution.LinkWithEditor.class) + .to(LinkWithEditor.class); + } + + public void configureCompilerPreferencesInitializer(Binder binder) { + binder.bind(IPreferenceStoreInitializer.class) + .annotatedWith(Names.named("compilerPreferences")) + .to(CompilerPreferencesInitializer.class); + } + +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/AutoAddNatureEditorCallback.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/AutoAddNatureEditorCallback.java new file mode 100644 index 0000000..5c46840 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/AutoAddNatureEditorCallback.java
@@ -0,0 +1,38 @@ +/* + * 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.builder; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.xtext.builder.nature.ToggleXtextNatureAction; +import org.eclipse.xtext.builder.nature.XtextNature; +import org.eclipse.xtext.ui.editor.AbstractDirtyStateAwareEditorCallback; +import org.eclipse.xtext.ui.editor.XtextEditor; + +import com.google.inject.Inject; + +/** + * Automatically adds <code>{@link XtextNature}</code> and <code>{@link ProtobufNature}</code> to a project if needed + * (e.g. when opening a 'Protocol Buffer' editor for the first time.) + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class AutoAddNatureEditorCallback extends AbstractDirtyStateAwareEditorCallback { + + @Inject private ToggleXtextNatureAction xtext; + + @Override public void afterCreatePartControl(XtextEditor editor) { + super.afterCreatePartControl(editor); + IResource resource = editor.getResource(); + if (resource == null) return; + IProject project = resource.getProject(); + if (!project.isAccessible() || project.isHidden()) return; + if (!xtext.hasNature(project)) xtext.toggleNature(project); + } +} \ No newline at end of file
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/MarkerFactory.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/MarkerFactory.java new file mode 100644 index 0000000..7a850b5 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/MarkerFactory.java
@@ -0,0 +1,56 @@ +/* + * 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.builder; + +import static java.lang.Integer.parseInt; +import static org.eclipse.core.resources.IMarker.*; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; + +/** + * Parses the output of protoc and create error markers if necessary. + * + * @author alruiz@google.com (Alex Ruiz) + */ +class MarkerFactory { + + static final String MARKER_ID = "com.google.eclipse.protobuf.ui.pbmarker"; + + /* + * (.*):(\\d+):(\\d+):\\s*(.*) + * --1- ---2-- ---3-- -*- --4- + * + * 1: file name + * 2: line number + * 3: column + * *: whitespace + * 4: description + */ + private static final Pattern ERROR_PATTERN = Pattern.compile("(.*):(\\d+):(\\d+):\\s*(.*)"); + + void parseAndCreateMarkerIfNecessary(String line, IFile file) throws CoreException { + parseError(line, file); + } + + private void parseError(String line, IFile file) throws CoreException { + Matcher errorMatcher = ERROR_PATTERN.matcher(line); + if (!errorMatcher.matches()) return; + int lineNumber = parseInt(errorMatcher.group(2)); + String description = errorMatcher.group(4); + IMarker marker = file.createMarker(MARKER_ID); + marker.setAttribute(SEVERITY, SEVERITY_ERROR); + marker.setAttribute(MESSAGE, description); + marker.setAttribute(LINE_NUMBER, lineNumber); + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/ProtobufBuildParticipant.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/ProtobufBuildParticipant.java new file mode 100644 index 0000000..96f1022 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/ProtobufBuildParticipant.java
@@ -0,0 +1,130 @@ +/* + * 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.builder; + +import static com.google.eclipse.protobuf.ui.preferences.CompilerPreferences.loadPreferences; +import static com.google.eclipse.protobuf.ui.preferences.RefreshTarget.PROJECT; +import static org.eclipse.core.resources.IResource.DEPTH_INFINITE; + +import java.io.*; +import java.util.List; + +import org.apache.log4j.Logger; +import org.eclipse.core.resources.*; +import org.eclipse.core.runtime.*; +import org.eclipse.emf.common.util.URI; +import org.eclipse.xtext.builder.IXtextBuilderParticipant; +import org.eclipse.xtext.resource.IResourceDescription; +import org.eclipse.xtext.resource.IResourceDescription.Delta; +import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess; + +import com.google.eclipse.protobuf.ui.preferences.*; +import com.google.inject.Inject; + +/** + * Calls protoc to generate Java, C++ or Python code from .proto files. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class ProtobufBuildParticipant implements IXtextBuilderParticipant { + + private static final NullProgressMonitor NO_MONITOR = new NullProgressMonitor(); + + private static Logger logger = Logger.getLogger(ProtobufBuildParticipant.class); + + @Inject private IPreferenceStoreAccess preferenceStoreAccess; + @Inject private MarkerFactory markerFactory; + @Inject private ProtocCommandFactory commandFactory; + + public void build(IBuildContext context, IProgressMonitor monitor) throws CoreException { + IProject project = context.getBuiltProject(); + CompilerPreferences preferences = loadPreferences(preferenceStoreAccess, project); + if (!preferences.compileProtoFiles) return; + List<Delta> deltas = context.getDeltas(); + if (deltas.isEmpty()) return; + IFolder outputFolder = findOrCreateOutputFolder(project, preferences.outputFolderName); + for (Delta d : deltas) { + IResourceDescription newResource = d.getNew(); + String path = filePath(newResource); + if (path == null) continue; + IFile source = project.getWorkspace().getRoot().getFile(new Path(path)); + generateSingleProto(source, preferences.protocPath, preferences.language, pathOf(outputFolder)); + } + if (preferences.refreshResources) refresh(outputFolder, preferences.refreshTarget, monitor); + } + + private static IFolder findOrCreateOutputFolder(IProject project, String outputFolderName) throws CoreException { + IFolder outputFolder = project.getFolder(outputFolderName); + if (!outputFolder.exists()) outputFolder.create(true, true, NO_MONITOR); + return outputFolder; + } + + private static String filePath(IResourceDescription r) { + if (r == null) return null; + URI uri = r.getURI(); + if (uri.scheme() == null) return uri.toFileString(); + StringBuilder b = new StringBuilder(); + int segmentCount = uri.segmentCount(); + for (int i = 1; i < segmentCount; i++) + b.append("/").append(uri.segment(i)); + return b.length() == 0 ? null : b.toString(); + } + + private void generateSingleProto(IFile source, String protocPath, TargetLanguage language, String outputFolderPath) { + String command = commandFactory.protocCommand(source, protocPath, language, outputFolderPath); + try { + source.deleteMarkers(MarkerFactory.MARKER_ID, true, DEPTH_INFINITE); + Process process = Runtime.getRuntime().exec(command); + processStream(process.getErrorStream(), source); + process.destroy(); + } catch (Exception ex) { + // TODO show error message + ex.printStackTrace(); + } + } + + private void processStream(InputStream stream, IFile source) { + InputStreamReader reader = null; + try { + reader = new InputStreamReader(stream); + BufferedReader bufferedReader = new BufferedReader(reader); + String line = null; + while ((line = bufferedReader.readLine()) != null) { + markerFactory.parseAndCreateMarkerIfNecessary(line, source); + System.out.println("[protoc] " + line); + } + } catch (Exception e) { + logger.fatal("Execution of protoc on [" + source.getName() + "] failed", e); + } finally { + close(reader); + } + } + + private static void close(Reader reader) { + if (reader == null) return; + try { + reader.close(); + } catch (IOException ignored) {} + } + + private static String pathOf(IResource r) { + return r.getLocation().toOSString(); + } + + private static void refresh(IFolder outputFolder, RefreshTarget refreshTarget, IProgressMonitor monitor) + throws CoreException { + IResource target = refreshTarget(outputFolder, refreshTarget); + target.refreshLocal(DEPTH_INFINITE, monitor); + } + + private static IResource refreshTarget(IFolder outputFolder, RefreshTarget refreshTarget) { + if (refreshTarget.equals(PROJECT)) return outputFolder.getProject(); + return outputFolder; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/ProtocCommandFactory.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/ProtocCommandFactory.java new file mode 100644 index 0000000..67d79b5 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/ProtocCommandFactory.java
@@ -0,0 +1,44 @@ +/* + * 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.builder; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.IPath; + +import com.google.eclipse.protobuf.ui.preferences.TargetLanguage; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +class ProtocCommandFactory { + private static final Map<TargetLanguage, String> LANG_OUT_FLAG = new HashMap<TargetLanguage, String>(); + + static { + for (TargetLanguage lang : TargetLanguage.values()) + LANG_OUT_FLAG.put(lang, "--" + lang.name().toLowerCase() + "_out="); + } + + String protocCommand(IFile protoFile, String protocPath, TargetLanguage language, String outputFolderPath) { + IPath protoFilePath = protoFile.getLocation(); + StringBuilder command = new StringBuilder(); + command.append(protocPath).append(" "); + String protoFileFolder = protoFilePath.toFile().getParentFile().toString(); + command.append("-I=").append(protoFileFolder).append(" "); + command.append(langOutFlag(language)).append(outputFolderPath).append(" "); + command.append(protoFilePath.toOSString()); + return command.toString(); + } + + private String langOutFlag(TargetLanguage targetLanguage) { + return LANG_OUT_FLAG.get(targetLanguage); + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/commands/SmartInsertHandler.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/commands/SmartInsertHandler.java new file mode 100644 index 0000000..3dcecea --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/commands/SmartInsertHandler.java
@@ -0,0 +1,40 @@ +/* + * 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.commands; + +import static org.eclipse.xtext.ui.editor.utils.EditorUtils.getActiveXtextEditor; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Control; +import org.eclipse.xtext.ui.editor.XtextEditor; + +/** + * Base class for command handlers that insert content in an editor. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public abstract class SmartInsertHandler extends AbstractHandler { + + /** {@inheritDoc} */ + public final Object execute(ExecutionEvent event) { + XtextEditor activeEditor = getActiveXtextEditor(); + if (activeEditor != null) insertContent(activeEditor); + return null; + } + + protected abstract void insertContent(XtextEditor editor); + + protected static StyledText styledTextFrom(XtextEditor editor) { + Object adapter = editor.getAdapter(Control.class); + if (adapter instanceof StyledText) return (StyledText) adapter; + return null; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/commands/SmartSemicolonHandler.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/commands/SmartSemicolonHandler.java new file mode 100644 index 0000000..2ccb99f --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/commands/SmartSemicolonHandler.java
@@ -0,0 +1,121 @@ +/* + * 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.commands; + +import static com.google.eclipse.protobuf.protobuf.Modifier.REPEATED; + +import java.util.regex.Pattern; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.ui.editor.XtextEditor; +import org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext; +import org.eclipse.xtext.ui.editor.contentassist.antlr.ParserBasedContentAssistContextFactory; +import org.eclipse.xtext.util.concurrent.IUnitOfWork; + +import com.google.eclipse.protobuf.protobuf.*; +import com.google.eclipse.protobuf.ui.grammar.*; +import com.google.eclipse.protobuf.ui.util.*; +import com.google.inject.Inject; + +/** + * Inserts a semicolon at the end of a line, regardless of the current position of the caret in the editor. If the + * line of code being edited is a property or enum literal and if it does not have an index yet, this handler will + * insert an index with a proper value as well. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class SmartSemicolonHandler extends SmartInsertHandler { + + private static final Pattern LITERAL_WITH_INDEX = Pattern.compile("[\\s]+(.*)[\\s]+=[\\s]+[\\d]+(.*)"); + + private static final Pattern PROPERTY_WITH_INDEX = + Pattern.compile("[\\s]+(.*)[\\s]+(.*)[\\s]+(.*)[\\s]+=[\\s]+[\\d]+(.*)"); + + private final CompoundElements compoundElements; + + @Inject private ParserBasedContentAssistContextFactory contextFactory; + @Inject private Literals literals; + @Inject private Properties properties; + + private final String semicolon; + + @Inject public SmartSemicolonHandler(CompoundElements compoundElements, Keywords keywords) { + this.compoundElements = compoundElements; + semicolon = keywords.semicolon().getValue(); + } + + /** {@inheritDoc} */ + @Override protected void insertContent(XtextEditor editor) { + StyledText styledText = styledTextFrom(editor); + int originalCaretOffset = styledText.getCaretOffset(); + int lineAtOffset = styledText.getLineAtOffset(originalCaretOffset); + int offsetAtLine = styledText.getOffsetAtLine(lineAtOffset); + String line = styledText.getLine(lineAtOffset); + if (line.endsWith(semicolon)) { + behaveLikeRegularEditing(originalCaretOffset, styledText); + return; + } + int endOfLineOffset = offsetAtLine + line.length(); + styledText.setCaretOffset(endOfLineOffset); + String contentToInsert = contentToInsert(line, editor, originalCaretOffset); + styledText.insert(contentToInsert); + styledText.setCaretOffset(endOfLineOffset + contentToInsert.length()); + } + + private void behaveLikeRegularEditing(int caretOffset, StyledText styledText) { + styledText.insert(semicolon); + styledText.setCaretOffset(caretOffset + semicolon.length()); + } + + private String contentToInsert(final String line, final XtextEditor editor, final int offset) { + return editor.getDocument().readOnly(new IUnitOfWork<String, XtextResource>() { + public String exec(XtextResource state) { + ContentAssistContext[] context = contextFactory.create(editor.getInternalSourceViewer(), offset, state); + if (context == null || context.length == 0) return semicolon; + for (ContentAssistContext c : context) { + EObject model = c.getCurrentModel(); + if (model instanceof Literal) + return contentToInsert(line, (Literal) model); + if (model instanceof Property) + return contentToInsert(line, (Property) model); + } + return semicolon; + } + }); + } + + private String contentToInsert(String line, Literal literal) { + boolean hasIndexAlready = LITERAL_WITH_INDEX.matcher(line).matches(); + if (hasIndexAlready) return semicolon; + int index = literals.calculateIndexOf(literal); + return defaultIndexAndSemicolonToInsert(line, index); + } + + private String contentToInsert(String line, Property property) { + boolean hasIndexAlready = PROPERTY_WITH_INDEX.matcher(line).matches(); + if (hasIndexAlready) return semicolon; + int index = properties.calculateIndexOf(property); + if (REPEATED.equals(property.getModifier())) { + String format = "= %d " + compoundElements.packedInBrackets() + "%s"; + return indexAndSemicolonToInsert(format, line, index); + } + return defaultIndexAndSemicolonToInsert(line, index); + } + + private String defaultIndexAndSemicolonToInsert(String line, int index) { + return indexAndSemicolonToInsert("= %d%s", line, index); + } + + private String indexAndSemicolonToInsert(String format, String line, int index) { + String content = String.format(format, index, semicolon); + return (line.endsWith(" ")) ? content : " " + content; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/contentassist/ProtobufProposalProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/contentassist/ProtobufProposalProvider.java new file mode 100644 index 0000000..253046f --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/contentassist/ProtobufProposalProvider.java
@@ -0,0 +1,307 @@ +/* + * 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.contentassist; + +import static com.google.eclipse.protobuf.protobuf.Modifier.*; +import static com.google.eclipse.protobuf.protobuf.ScalarType.STRING; +import static java.lang.String.valueOf; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Image; +import org.eclipse.xtext.*; +import org.eclipse.xtext.ui.PluginImageHelper; +import org.eclipse.xtext.ui.editor.contentassist.*; + +import com.google.common.collect.ImmutableList; +import com.google.eclipse.protobuf.protobuf.*; +import com.google.eclipse.protobuf.protobuf.Enum; +import com.google.eclipse.protobuf.scoping.GlobalScope; +import com.google.eclipse.protobuf.ui.grammar.*; +import com.google.eclipse.protobuf.ui.labeling.Images; +import com.google.eclipse.protobuf.ui.util.*; +import com.google.eclipse.protobuf.util.EObjectFinder; +import com.google.inject.Inject; + +/** + * @author alruiz@google.com (Alex Ruiz) + * + * @see http://www.eclipse.org/Xtext/documentation/latest/xtext.html#contentAssist on how to customize content assistant + */ +public class ProtobufProposalProvider extends AbstractProtobufProposalProvider { + + @Inject private CompoundElements compoundElements; + @Inject private EObjectFinder finder; + @Inject private GlobalScope globalScope; + @Inject private PluginImageHelper imageHelper; + @Inject private Images imageRegistry; + @Inject private Keywords keywords; + @Inject private Literals literals; + @Inject private Properties properties; + @Inject private Strings strings; + + @Override public void completeOption_Name(EObject model, Assignment assignment, ContentAssistContext context, + ICompletionProposalAcceptor acceptor) { + EObject container = model.eContainer(); + if (container instanceof Protobuf) { + proposeCommonFileOptions(context, acceptor); + return; + } + } + + private void proposeCommonFileOptions(ContentAssistContext context, ICompletionProposalAcceptor acceptor) { + for (Property fileOption : globalScope.fileOptions()) { + String displayString = fileOption.getName(); + String proposalText = displayString + " " + keywords.equalSign().getValue() + " "; + boolean isStringOption = properties.isStringProperty(fileOption); + if (isStringOption) + proposalText = proposalText + compoundElements.emptyString() + keywords.semicolon().getValue(); + ICompletionProposal proposal = createCompletionProposal(proposalText, displayString, context); + if (isStringOption && proposal instanceof ConfigurableCompletionProposal) { + // set cursor between the proposal's quotes + ConfigurableCompletionProposal configurable = (ConfigurableCompletionProposal) proposal; + configurable.setCursorPosition(proposalText.length() - 2); + } + acceptor.accept(proposal); + } + } + + @Override public void completeOption_Value(EObject model, Assignment assignment, ContentAssistContext context, + ICompletionProposalAcceptor acceptor) { + Option option = (Option) model; + Property fileOption = globalScope.lookupFileOption(option.getName()); + if (fileOption == null) return; + if (globalScope.isOptimizeForOption(option)) { + proposeAndAccept(globalScope.optimizedMode(), context, acceptor); + return; + } + if (properties.isStringProperty(fileOption)) { + proposeEmptyString(context, acceptor); + return; + } + if (properties.isBoolProperty(fileOption)) { + proposeBooleanValues(context, acceptor); + return; + } + } + + private void proposeBooleanValues(ContentAssistContext context, ICompletionProposalAcceptor acceptor) { + proposeAndAccept(keywords.boolFalse().getValue(), context, acceptor); + proposeAndAccept(keywords.boolTrue().getValue(), context, acceptor); + } + + @Override public void complete_ID(EObject model, RuleCall ruleCall, ContentAssistContext context, + ICompletionProposalAcceptor acceptor) {} + + @Override public void complete_STRING(EObject model, RuleCall ruleCall, ContentAssistContext context, + ICompletionProposalAcceptor acceptor) { + if (model instanceof Property && isProposalForDefaultValue(context)) { + Property p = (Property) model; + if (!isStringProperty(p)) return; + proposeEmptyString(context, acceptor); + return; + } + if (model instanceof Option) return; + super.complete_STRING(model, ruleCall, context, acceptor); + } + + private void proposeEmptyString(ContentAssistContext context, ICompletionProposalAcceptor acceptor) { + ICompletionProposal proposal = createCompletionProposal(compoundElements.emptyString(), context); + if (proposal instanceof ConfigurableCompletionProposal) { + ConfigurableCompletionProposal configurable = (ConfigurableCompletionProposal) proposal; + configurable.setCursorPosition(1); + } + acceptor.accept(proposal); + } + + private boolean isProposalForDefaultValue(ContentAssistContext context) { + return isProposalForAssignment(keywords.defaultValue().getValue(), context); + } + + private boolean isProposalForAssignment(String feature, ContentAssistContext context) { + ImmutableList<AbstractElement> grammarElements = context.getFirstSetGrammarElements(); + for (AbstractElement e : grammarElements) { + if (!(e instanceof Assignment)) continue; + Assignment a = (Assignment) e; + String equalSign = keywords.equalSign().getValue(); + if (feature.equals(a.getFeature()) && equalSign.equals(a.getOperator())) return true; + } + return false; + } + + @Override public void completeKeyword(Keyword keyword, ContentAssistContext context, + ICompletionProposalAcceptor acceptor) { + if (keyword == null) return; + if (isKeywordEqualToPreviousWordInEditor(keyword, context)) return; + if (keyword.equals(keywords.boolTrue()) || keyword.equals(keywords.boolFalse())) { + if (!isBoolProposalValid(context)) return; + } + if (keyword.equals(keywords.openingBracket())) { + boolean proposalWasHandledAlready = proposeOpenBracket(context, acceptor); + if (proposalWasHandledAlready) return; + } + if (keyword.equals(keywords.packed())) { + proposePackedOption(context, acceptor); + return; + } + if (keyword.equals(keywords.defaultValue())) { + proposeDefaultValue(context, acceptor); + return; + } + super.completeKeyword(keyword, context, acceptor); + } + + private boolean isKeywordEqualToPreviousWordInEditor(Keyword keyword, ContentAssistContext context) { + StyledText styledText = context.getViewer().getTextWidget(); + String value = keyword.getValue(); + int valueLength = value.length(); + int start = styledText.getCaretOffset() - valueLength; + if (start < 0) return false; + String previousWord = styledText.getTextRange(start, valueLength); + return value.equals(previousWord); + } + + private boolean isBoolProposalValid(ContentAssistContext context) { + EObject model = context.getCurrentModel(); + if (model instanceof Property) return properties.isBoolProperty((Property) model); + if (model instanceof Option) { + Property fileOption = globalScope.lookupFileOption(((Option) model).getName()); + return fileOption != null && properties.isBoolProperty(fileOption); + } + return false; + } + + private boolean proposeOpenBracket(ContentAssistContext context, ICompletionProposalAcceptor acceptor) { + EObject model = context.getCurrentModel(); + if (!(model instanceof Property)) return false; + Property p = (Property) model; + Modifier modifier = p.getModifier(); + if (OPTIONAL.equals(modifier)) { + String display = compoundElements.defaultValueInBrackets(); + int cursorPosition = display.indexOf(keywords.closingBracket().getValue()); + if (isStringProperty(p)) { + display = compoundElements.defaultStringValueInBrackets(); + cursorPosition++; + } + ICompletionProposal proposal = createCompletionProposal(display, context); + if (proposal instanceof ConfigurableCompletionProposal) { + ConfigurableCompletionProposal configurable = (ConfigurableCompletionProposal) proposal; + configurable.setCursorPosition(cursorPosition); + } + acceptor.accept(proposal); + } + if (REPEATED.equals(modifier)) proposeAndAccept(compoundElements.packedInBrackets(), context, acceptor); + return true; + } + + private void proposePackedOption(ContentAssistContext context, ICompletionProposalAcceptor acceptor) { + Modifier modifier = extractModifierFromModel(context); + if (!REPEATED.equals(modifier)) return; + proposeAndAccept(compoundElements.packed(), context, acceptor); + } + + private void proposeDefaultValue(ContentAssistContext context, ICompletionProposalAcceptor acceptor) { + Modifier modifier = extractModifierFromModel(context); + if (!OPTIONAL.equals(modifier)) return; + String display = compoundElements.defaultValue(); + int cursorPosition = display.length(); + if (isStringProperty((Property) context.getCurrentModel())) { + display = compoundElements.defaultStringValue(); + cursorPosition++; + } + ICompletionProposal proposal = createCompletionProposal(display, context); + if (proposal instanceof ConfigurableCompletionProposal) { + ConfigurableCompletionProposal configurable = (ConfigurableCompletionProposal) proposal; + configurable.setCursorPosition(cursorPosition); + } + acceptor.accept(proposal); + } + + private Modifier extractModifierFromModel(ContentAssistContext context) { + EObject model = context.getCurrentModel(); + // this is most likely a bug in Xtext: + if (!(model instanceof Property)) model = context.getPreviousModel(); + if (!(model instanceof Property)) return null; + return ((Property) model).getModifier(); + } + + private boolean isStringProperty(Property p) { + return STRING.equals(finder.scalarTypeOfProperty(p)); + } + + @Override public void completeLiteral_Index(EObject model, Assignment assignment, ContentAssistContext context, + ICompletionProposalAcceptor acceptor) { + int index = literals.calculateIndexOf((Literal) model); + proposeIndex(index, context, acceptor); + } + + @Override public void completeProperty_Default(EObject model, Assignment assignment, ContentAssistContext context, + ICompletionProposalAcceptor acceptor) { + Enum enumType = finder.enumTypeOfProperty((Property) model); + if (enumType == null) return; + proposeAndAccept(enumType, context, acceptor); + } + + private void proposeAndAccept(Enum enumType, ContentAssistContext context, ICompletionProposalAcceptor acceptor) { + Image image = imageHelper.getImage(imageRegistry.imageFor(Literal.class)); + for (Literal literal : enumType.getLiterals()) + proposeAndAccept(literal.getName(), image, context, acceptor); + } + + private void proposeAndAccept(String proposalText, Image image, ContentAssistContext context, + ICompletionProposalAcceptor acceptor) { + ICompletionProposal proposal = createCompletionProposal(proposalText, proposalText, image, context); + acceptor.accept(proposal); + } + + @Override public void completeProperty_Index(EObject model, Assignment assignment, ContentAssistContext context, + ICompletionProposalAcceptor acceptor) { + int index = properties.calculateIndexOf((Property) model); + proposeIndex(index, context, acceptor); + } + + private void proposeIndex(int index, ContentAssistContext context, ICompletionProposalAcceptor acceptor) { + proposeAndAccept(valueOf(index), context, acceptor); + } + + @Override public void completeProperty_Name(EObject model, Assignment assignment, ContentAssistContext context, + ICompletionProposalAcceptor acceptor) { + String typeName = strings.firstCharToLowerCase(properties.nameOfTypeIn((Property) model)); + int index = 1; + String name = typeName + index; + for (EObject o : model.eContainer().eContents()) { + if (o == model || !(o instanceof Property)) continue; + Property p = (Property) o; + if (!name.equals(p.getName())) continue; + name = typeName + (++index); + } + proposeAndAccept(name, context, acceptor); + } + + private ICompletionProposal createCompletionProposal(String proposal, String displayString, + ContentAssistContext context) { + return createCompletionProposal(proposal, displayString, defaultImage(), context); + } + + private void proposeAndAccept(String proposalText, ContentAssistContext context, ICompletionProposalAcceptor acceptor) { + ICompletionProposal proposal = createCompletionProposal(proposalText, context); + acceptor.accept(proposal); + } + + @Override protected ICompletionProposal createCompletionProposal(String proposal, + ContentAssistContext contentAssistContext) { + return createCompletionProposal(proposal, null, defaultImage(), getPriorityHelper().getDefaultPriority(), + contentAssistContext.getPrefix(), contentAssistContext); + } + + private Image defaultImage() { + return imageHelper.getImage(imageRegistry.defaultImage()); + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/grammar/CompoundElements.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/grammar/CompoundElements.java new file mode 100644 index 0000000..a648ecf --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/grammar/CompoundElements.java
@@ -0,0 +1,83 @@ +/* + * 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.grammar; + +import org.eclipse.xtext.Keyword; + +import com.google.inject.*; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +@Singleton +public class CompoundElements { + + private static final String EMPTY_STRING = "\"\""; + + private final String inBracketsFormat; + + private final String defaultValue; + private final String defaultValueInBrackets; + private final String defaultStringValue; + private final String defaultStringValueInBrackets; + private final String packed; + private final String packedInBrackets; + + @Inject public CompoundElements(Keywords keywords) { + inBracketsFormat = keywords.openingBracket().getValue() + "%s" + keywords.closingBracket().getValue(); + defaultValue = format("%s %s", keywords.defaultValue(), keywords.equalSign()); + defaultValueInBrackets = inBrackets(defaultValue); + defaultStringValue = format("%s %s %s", keywords.defaultValue(), keywords.equalSign(), EMPTY_STRING); + defaultStringValueInBrackets = inBrackets(defaultStringValue); + packed = format("%s %s %s", keywords.packed(), keywords.equalSign(), keywords.boolTrue()); + packedInBrackets = inBrackets(packed); + } + + private static String format(String format, Object...values) { + int count = values.length; + Object[] cleanValues = new Object[count]; + for (int i = 0; i < count; i++) { + Object value = values[i]; + cleanValues[i] = (value instanceof Keyword) ? ((Keyword) value).getValue() : value; + } + return String.format(format, cleanValues); + } + + private String inBrackets(String element) { + return String.format(inBracketsFormat, element); + } + + public String defaultValue() { + return defaultValue; + } + + public String defaultValueInBrackets() { + return defaultValueInBrackets; + } + + public String defaultStringValue() { + return defaultStringValue; + } + + public String defaultStringValueInBrackets() { + return defaultStringValueInBrackets; + } + + public String emptyString() { + return EMPTY_STRING; + } + + public String packed() { + return packed; + } + + public String packedInBrackets() { + return packedInBrackets; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/grammar/Keywords.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/grammar/Keywords.java new file mode 100644 index 0000000..7030ca6 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/grammar/Keywords.java
@@ -0,0 +1,155 @@ +/* + * 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.grammar; + +import static org.eclipse.xtext.GrammarUtil.containedKeywords; + +import java.util.List; + +import org.eclipse.xtext.*; + +import com.google.inject.*; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +@Singleton +public class Keywords { + + private Keyword bool; + private Keyword boolTrue; + private Keyword boolFalse; + private Keyword openingBracket; + private Keyword closingBracket; + private Keyword defaultValue; + private Keyword equalSign; + private Keyword packed; + private Keyword semicolon; + private Keyword string; + + @Inject public Keywords(IGrammarAccess grammarAccess) { + List<Keyword> allKeywords = containedKeywords(grammarAccess.getGrammar()); + for (Keyword k : allKeywords) { + if (assignIfIsBool(k)) continue; + if (assignIfIsBoolTrue(k)) continue; + if (assignIfIsBoolFalse(k)) continue; + if (assignIfIsOpeningBracket(k)) continue; + if (assignIfIsClosingBracket(k)) continue; + if (assignIfIsDefaultValue(k)) continue; + if (assignIfIsEqualSign(k)) continue; + if (assignIfIsPacked(k)) continue; + if (assignIfIsSemicolon(k)) continue; + if (assignIfIsString(k)) continue; + } + } + + private boolean assignIfIsBool(Keyword k) { + if (!isKeywordValue(k, "bool")) return false; + bool = k; + return true; + } + + private boolean assignIfIsBoolTrue(Keyword k) { + if (!isKeywordValue(k, "true")) return false; + boolTrue = k; + return true; + } + + private boolean assignIfIsBoolFalse(Keyword k) { + if (!isKeywordValue(k, "false")) return false; + boolFalse = k; + return true; + } + + private boolean assignIfIsOpeningBracket(Keyword k) { + if (!isKeywordValue(k, "[")) return false; + openingBracket = k; + return true; + } + + private boolean assignIfIsClosingBracket(Keyword k) { + if (!isKeywordValue(k, "]")) return false; + closingBracket = k; + return true; + } + + private boolean assignIfIsDefaultValue(Keyword k) { + if (!isKeywordValue(k, "default")) return false; + defaultValue = k; + return true; + } + + private boolean assignIfIsEqualSign(Keyword k) { + if (!isKeywordValue(k, "=")) return false; + equalSign = k; + return true; + } + + private boolean assignIfIsPacked(Keyword k) { + if (!isKeywordValue(k, "packed")) return false; + packed = k; + return true; + } + + private boolean assignIfIsSemicolon(Keyword k) { + if (!isKeywordValue(k, ";")) return false; + semicolon = k; + return true; + } + + private boolean assignIfIsString(Keyword k) { + if (!isKeywordValue(k, "string")) return false; + string = k; + return true; + } + + private static boolean isKeywordValue(Keyword k, String expectedValue) { + return expectedValue.equals(k.getValue()); + } + + public Keyword bool() { + return bool; + } + + public Keyword boolTrue() { + return boolTrue; + } + + public Keyword boolFalse() { + return boolFalse; + } + + public Keyword openingBracket() { + return openingBracket; + } + + public Keyword closingBracket() { + return closingBracket; + } + + public Keyword defaultValue() { + return defaultValue; + } + + public Keyword equalSign() { + return equalSign; + } + + public Keyword packed() { + return packed; + } + + public Keyword semicolon() { + return semicolon; + } + + public Keyword string() { + return string; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Images.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Images.java new file mode 100644 index 0000000..c53092b --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Images.java
@@ -0,0 +1,93 @@ +/* + * 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.labeling; + +import static com.google.eclipse.protobuf.protobuf.Modifier.*; +import static java.util.Arrays.asList; + +import java.util.*; + +import org.eclipse.xtext.Keyword; + +import com.google.eclipse.protobuf.protobuf.*; +import com.google.eclipse.protobuf.protobuf.Enum; +import com.google.eclipse.protobuf.protobuf.Package; +import com.google.inject.Singleton; + +/** + * Registry of all images used in the 'Protocol Buffer' editor. + * + * @author alruiz@google.com (Alex Ruiz) + */ +@Singleton +public class Images { + + private static final String DEFAULT_IMAGE = "empty.gif"; + + private static final Map<Modifier, String> IMAGES_BY_MODIFIER = new HashMap<Modifier, String>(); + static { + IMAGES_BY_MODIFIER.put(OPTIONAL, "property-opt.gif"); + IMAGES_BY_MODIFIER.put(REPEATED, "property-rep.gif"); + IMAGES_BY_MODIFIER.put(REQUIRED, "property-req.gif"); + } + + private static final Map<Class<?>, String> IMAGES_BY_TYPE = new HashMap<Class<?>, String>(); + static { + IMAGES_BY_TYPE.put(Enum.class, "enum.gif"); + IMAGES_BY_TYPE.put(ExtendMessage.class, "extend.gif"); + IMAGES_BY_TYPE.put(Import.class, "import.gif"); + IMAGES_BY_TYPE.put(Literal.class, "literal.gif"); + IMAGES_BY_TYPE.put(Message.class, "message.gif"); + IMAGES_BY_TYPE.put(Option.class, "option.gif"); + IMAGES_BY_TYPE.put(Package.class, "package.gif"); + IMAGES_BY_TYPE.put(Protobuf.class, "protobuf.gif"); + } + + private static final List<String> STANDALONE_IMAGES = asList("extensions.gif"); + + public String imageFor(Object o) { + if (o instanceof Property) { + Property p = (Property) o; + return imageFor(p.getModifier()); + } + if (o instanceof Keyword) { + Keyword k = (Keyword) o; + return imageFor(k); + } + return imageFor(o.getClass()); + } + + public String imageFor(Class<?> type) { + String image = IMAGES_BY_TYPE.get(type); + if (image != null) return image; + Class<?>[] interfaces = type.getInterfaces(); + if (interfaces == null || interfaces.length != 1) return DEFAULT_IMAGE; + return imageFor(interfaces[0]); + } + + private String imageFor(Keyword k) { + String value = k.getValue(); + Modifier m = Modifier.getByName(value); + String image = IMAGES_BY_MODIFIER.get(m); + if (image != null) return image; + String imageName = value + ".gif"; + if (IMAGES_BY_TYPE.containsValue(imageName) || STANDALONE_IMAGES.contains(imageName)) return imageName; + return DEFAULT_IMAGE; + } + + private String imageFor(Modifier m) { + String image = IMAGES_BY_MODIFIER.get(m); + if (image != null) return image; + return "property.gif"; + } + + public String defaultImage() { + return DEFAULT_IMAGE; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Labels.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Labels.java new file mode 100644 index 0000000..966c26d --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Labels.java
@@ -0,0 +1,69 @@ +/* + * 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.labeling; + +import static com.google.eclipse.protobuf.scoping.SimpleImportUriResolver.URI_PREFIX; + +import com.google.eclipse.protobuf.protobuf.*; +import com.google.eclipse.protobuf.ui.util.Properties; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +/** + * Registry of commonly used text in the 'Protocol Buffer' editor. + * + * @author alruiz@google.com (Alex Ruiz) + */ +@Singleton +public class Labels { + + @Inject private Properties properties; + + private static final String LITERAL_FORMAT = "%s [%d]"; + private static final String PROPERTY_FORMAT = "%s [%d] : %s"; + + public String labelFor(Object o) { + if (o instanceof Import) { + Import i = (Import) o; + return labelFor(i); + } + if (o instanceof Literal) { + Literal l = (Literal) o; + return labelFor(l); + } + if (o instanceof Property) { + Property p = (Property) o; + return labelFor(p); + } + if (o instanceof Protobuf) { + Protobuf p = (Protobuf) o; + return labelFor(p); + } + return null; + } + + private String labelFor(Import i) { + String uri = i.getImportURI(); + if (uri == null || !uri.startsWith(URI_PREFIX)) return uri; + return uri.substring(URI_PREFIX.length()); + } + + private String labelFor(Literal l) { + return String.format(LITERAL_FORMAT, l.getName(), l.getIndex()); + } + + private String labelFor(Property p) { + return String.format(PROPERTY_FORMAT, p.getName(), p.getIndex(), properties.nameOfTypeIn(p)); + } + + private String labelFor(Protobuf p) { + // TODO show this text till I figure out how to hide 'Protobuf' node in outline view + return "Protocol Buffer"; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/ProtobufDescriptionLabelProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/ProtobufDescriptionLabelProvider.java new file mode 100644 index 0000000..57ca234 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/ProtobufDescriptionLabelProvider.java
@@ -0,0 +1,20 @@ +/* + * 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.labeling; + +import org.eclipse.xtext.ui.label.DefaultDescriptionLabelProvider; + +/** + * Provides labels for a {@code IEObjectDescription}s and {@code IResourceDescription}s. + * + * @author alruiz@google.com (Alex Ruiz) + * + * @see http://www.eclipse.org/Xtext/documentation/latest/xtext.html#labelProvider + */ +public class ProtobufDescriptionLabelProvider extends DefaultDescriptionLabelProvider {}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/ProtobufLabelProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/ProtobufLabelProvider.java new file mode 100644 index 0000000..71423d3 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/ProtobufLabelProvider.java
@@ -0,0 +1,40 @@ +/* + * 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.labeling; + +import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; +import org.eclipse.xtext.ui.label.DefaultEObjectLabelProvider; + +import com.google.inject.Inject; + +/** + * Provides labels for a {@code EObject}s. + * + * @author alruiz@google.com (Alex Ruiz) + * + * @see http://www.eclipse.org/Xtext/documentation/latest/xtext.html#labelProvider + */ +public class ProtobufLabelProvider extends DefaultEObjectLabelProvider { + + @Inject private Labels labels; + @Inject private Images images; + + @Inject public ProtobufLabelProvider(AdapterFactoryLabelProvider delegate) { + super(delegate); + } + + @Override public Object text(Object o) { + String text = labels.labelFor(o); + return (text != null) ? text : super.text(o); + } + + @Override public Object image(Object o) { + return images.imageFor(o); + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/LinkWithEditor.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/LinkWithEditor.java new file mode 100644 index 0000000..d8fdfd2 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/LinkWithEditor.java
@@ -0,0 +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.outline; + +import java.util.Map; + +import org.eclipse.xtext.ui.editor.outline.actions.*; +import org.eclipse.xtext.ui.editor.outline.impl.OutlinePage; + +import com.google.common.collect.Maps; +import com.google.inject.*; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +public class LinkWithEditor extends LinkWithEditorOutlineContribution { + + @Inject private Provider<OutlineWithEditorLinker> outlineWithEditorLinkerProvider; + + private final Map<OutlinePage, OutlineWithEditorLinker> page2linker = Maps.newHashMap(); + + /** {@inheritDoc} */ + @Override public void register(OutlinePage outlinePage) { + addPropertyChangeListener(); + OutlineWithEditorLinker outlineWithEditorLinker = outlineWithEditorLinkerProvider.get(); + outlineWithEditorLinker.activate(outlinePage); + getPreferenceStoreAccess().getPreferenceStore().addPropertyChangeListener(outlineWithEditorLinker); + outlineWithEditorLinker.setLinkingEnabled(true); + page2linker.put(outlinePage, outlineWithEditorLinker); + } + + @Override + public void deregister(OutlinePage outlinePage) { + removePropertyChangeListener(); + OutlineWithEditorLinker outlineWithEditorLinker = page2linker.remove(outlinePage); + outlineWithEditorLinker.deactivate(); + getPreferenceStoreAccess().getPreferenceStore().removePropertyChangeListener(outlineWithEditorLinker); + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlinePage.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlinePage.java new file mode 100644 index 0000000..493b16b --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlinePage.java
@@ -0,0 +1,27 @@ +/* + * 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.outline; + +import org.eclipse.xtext.ui.editor.outline.impl.OutlinePage; + +/** + * Outline Page for Protocol Buffer editors. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class ProtobufOutlinePage extends OutlinePage { + + /** + * Indicates that the root node and its immediate children of the Outline View need to be expanded. + * @return 3. + */ + @Override protected int getDefaultExpansionLevel() { + return 3; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlineTreeProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlineTreeProvider.java new file mode 100644 index 0000000..0b6faa7 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlineTreeProvider.java
@@ -0,0 +1,29 @@ +/* + * 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.outline; + +import org.eclipse.xtext.ui.editor.outline.impl.DefaultOutlineTreeProvider; + +import com.google.eclipse.protobuf.protobuf.*; + +/** + * Customization of the default outline structure + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class ProtobufOutlineTreeProvider extends DefaultOutlineTreeProvider { + + boolean _isLeaf(Property p) { + return true; + } + + boolean _isLeaf(Option o) { + return true; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/CompilerPreferenceNames.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/CompilerPreferenceNames.java new file mode 100644 index 0000000..69a3441 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/CompilerPreferenceNames.java
@@ -0,0 +1,30 @@ +/* + * 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.preferences; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +final class CompilerPreferenceNames { + + static final String ENABLE_PROJECT_SETTINGS = "compiler.enableProjectSettings"; + static final String COMPILE_PROTO_FILES = "compiler.compileProtoFiles"; + static final String USE_PROTOC_IN_SYSTEM_PATH = "compiler.useProtocInSystemPath"; + static final String USE_PROTOC_IN_CUSTOM_PATH = "compiler.useProtocInCustomPath"; + static final String PROTOC_FILE_PATH = "compiler.protocFilePath"; + static final String GENERATE_JAVA_CODE = "compiler.generateJavaCode"; + static final String GENERATE_CPP_CODE = "compiler.generateCppCode"; + static final String GENERATE_PYTHON_CODE = "compiler.generatePythonCode"; + static final String OUTPUT_FOLDER_NAME = "compiler.outputFolderName"; + static final String REFRESH_RESOURCES = "compiler.refreshResources"; + static final String REFRESH_PROJECT = "compiler.refreshProject"; + static final String REFRESH_OUTPUT_FOLDER = "compiler.refreshOutputProject"; + + private CompilerPreferenceNames() {} +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/CompilerPreferencePage.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/CompilerPreferencePage.java new file mode 100644 index 0000000..aeb4ffe --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/CompilerPreferencePage.java
@@ -0,0 +1,452 @@ +/* + * 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.preferences; + +import static com.google.eclipse.protobuf.ui.preferences.CompilerPreferenceNames.*; +import static com.google.eclipse.protobuf.ui.preferences.Messages.*; +import static org.eclipse.core.resources.IResource.FOLDER; +import static org.eclipse.core.runtime.IStatus.OK; + +import java.io.File; +import java.util.Map; + +import org.eclipse.core.resources.*; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferencePage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.*; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.*; +import org.eclipse.ui.*; +import org.eclipse.ui.dialogs.PreferencesUtil; +import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess; + +import com.google.inject.Inject; + +/** + * Preference page for protobuf compiler. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class CompilerPreferencePage extends PreferencePage implements IWorkbenchPreferencePage, IWorkbenchPropertyPage { + + private static final String PREFERENCE_PAGE_ID = "com.google.eclipse.protobuf.ui.preferences.CompilerPreferencePage"; + private Button btnEnableProjectSettings; + private Link lnkEnableWorkspaceSettings; + private Button btnCompileProtoFiles; + private TabFolder tabFolder; + private TabItem tbtmMain; + private TabItem tbtmRefresh; + private Group grpCompilerLocation; + private Button btnUseProtocInSystemPath; + private Button btnUseProtocInCustomPath; + private Text txtProtocFilePath; + private Button btnProtocPathBrowse; + private Group grpTargetLanguage; + private Button btnJava; + private Button btnCpp; + private Button btnPython; + private Group grpOutput; + private Text txtOutputFolderName; + private Label lblOutputFolderName; + + private IProject project; + + private final IPreferenceStoreAccess preferenceStoreAccess; + + private Map<String, Object> dataMap; + private Button btnRefreshResources; + private Group grpRefresh; + private Button btnRefreshProject; + private Button btnRefreshOutputFolder; + + @Inject public CompilerPreferencePage(IPreferenceStoreAccess preferenceStoreAccess) { + this.preferenceStoreAccess = preferenceStoreAccess; + } + + /** {@inheritDoc} */ + @Override protected Control createContents(Composite parent) { + // generated by WindowBuilder + Composite contents = new Composite(parent, NONE); + contents.setLayout(new GridLayout(3, false)); + + if (isPropertyPage()) { + btnEnableProjectSettings = new Button(contents, SWT.CHECK); + btnEnableProjectSettings.setText(CompilerPreferencePage_enableProjectSettings); + + lnkEnableWorkspaceSettings = new Link(contents, SWT.NONE); + lnkEnableWorkspaceSettings.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + lnkEnableWorkspaceSettings.setText("<a>" + CompilerPreferencePage_configureWorkspaceSettings + "</a>"); + + Label label = new Label(contents, SWT.SEPARATOR | SWT.HORIZONTAL); + label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); + } + new Label(contents, SWT.NONE); + + btnCompileProtoFiles = new Button(contents, SWT.CHECK); + btnCompileProtoFiles.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1)); + btnCompileProtoFiles.setText(CompilerPreferencePage_compileOnSave); + + tabFolder = new TabFolder(contents, SWT.NONE); + tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); + + tbtmMain = new TabItem(tabFolder, SWT.NONE); + tbtmMain.setText(CompilerPreferencePage_mainTab); + + Composite cmpMain = new Composite(tabFolder, SWT.NONE); + tbtmMain.setControl(cmpMain); + cmpMain.setLayout(new GridLayout(1, false)); + + grpCompilerLocation = new Group(cmpMain, SWT.NONE); + grpCompilerLocation.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + grpCompilerLocation.setLayout(new GridLayout(4, false)); + grpCompilerLocation.setText(CompilerPreferencePage_location); + + btnUseProtocInSystemPath = new Button(grpCompilerLocation, SWT.RADIO); + btnUseProtocInSystemPath.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 4, 1)); + btnUseProtocInSystemPath.setText(CompilerPreferencePage_systemPath); + + btnUseProtocInCustomPath = new Button(grpCompilerLocation, SWT.RADIO); + btnUseProtocInCustomPath.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 4, 1)); + btnUseProtocInCustomPath.setText(CompilerPreferencePage_customPath); + new Label(grpCompilerLocation, SWT.NONE); + + txtProtocFilePath = new Text(grpCompilerLocation, SWT.BORDER); + txtProtocFilePath.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + txtProtocFilePath.setEditable(false); + new Label(grpCompilerLocation, SWT.NONE); + + btnProtocPathBrowse = new Button(grpCompilerLocation, SWT.NONE); + btnProtocPathBrowse.setText(CompilerPreferencePage_browseCustomPath); + + grpTargetLanguage = new Group(cmpMain, SWT.NONE); + grpTargetLanguage.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + grpTargetLanguage.setLayout(new GridLayout(1, false)); + grpTargetLanguage.setText(CompilerPreferencePage_targetLanguage); + + btnJava = new Button(grpTargetLanguage, SWT.RADIO); + btnJava.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1)); + btnJava.setText(CompilerPreferencePage_generateJava); + + btnCpp = new Button(grpTargetLanguage, SWT.RADIO); + btnCpp.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1)); + btnCpp.setText(CompilerPreferencePage_generateCpp); + + btnPython = new Button(grpTargetLanguage, SWT.RADIO); + btnPython.setText(CompilerPreferencePage_generatePython); + + grpOutput = new Group(cmpMain, SWT.NONE); + grpOutput.setLayout(new GridLayout(3, false)); + grpOutput.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + grpOutput.setText(CompilerPreferencePage_generatedCode); + + lblOutputFolderName = new Label(grpOutput, SWT.NONE); + lblOutputFolderName.setText(CompilerPreferencePage_outputFolderName); + new Label(grpOutput, SWT.NONE); + + txtOutputFolderName = new Text(grpOutput, SWT.BORDER); + txtOutputFolderName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + + tbtmRefresh = new TabItem(tabFolder, SWT.NONE); + tbtmRefresh.setText(CompilerPreferencePage_refreshTab); + + Composite cmpRefresh = new Composite(tabFolder, SWT.NONE); + tbtmRefresh.setControl(cmpRefresh); + cmpRefresh.setLayout(new GridLayout(1, false)); + + btnRefreshResources = new Button(cmpRefresh, SWT.CHECK); + btnRefreshResources.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + btnRefreshResources.setText(CompilerPreferencePage_refreshResources); + + grpRefresh = new Group(cmpRefresh, SWT.NONE); + grpRefresh.setLayout(new GridLayout(1, false)); + grpRefresh.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + + btnRefreshProject = new Button(grpRefresh, SWT.RADIO); + btnRefreshProject.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + btnRefreshProject.setText(CompilerPreferencePage_refreshProject); + + btnRefreshOutputFolder = new Button(grpRefresh, SWT.RADIO); + btnRefreshOutputFolder.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + btnRefreshOutputFolder.setText(CompilerPreferencePage_refreshOutputProject); + new Label(contents, SWT.NONE); + + updateFromPreferenceStore(); + addEventListeners(); + + return contents; + } + + private void updateFromPreferenceStore() { + IPreferenceStore store = doGetPreferenceStore(); + boolean compileProtoFiles = store.getBoolean(COMPILE_PROTO_FILES); + btnCompileProtoFiles.setSelection(compileProtoFiles); + btnUseProtocInSystemPath.setSelection(store.getBoolean(USE_PROTOC_IN_SYSTEM_PATH)); + btnUseProtocInCustomPath.setSelection(store.getBoolean(USE_PROTOC_IN_CUSTOM_PATH)); + txtProtocFilePath.setText(store.getString(PROTOC_FILE_PATH)); + btnJava.setSelection(store.getBoolean(GENERATE_JAVA_CODE)); + btnCpp.setSelection(store.getBoolean(GENERATE_CPP_CODE)); + btnPython.setSelection(store.getBoolean(GENERATE_PYTHON_CODE)); + txtOutputFolderName.setText(store.getString(OUTPUT_FOLDER_NAME)); + btnRefreshResources.setSelection(store.getBoolean(REFRESH_RESOURCES)); + btnRefreshProject.setSelection(store.getBoolean(REFRESH_PROJECT)); + btnRefreshOutputFolder.setSelection(store.getBoolean(REFRESH_OUTPUT_FOLDER)); + boolean enableCompilerOptions = compileProtoFiles; + if (isPropertyPage()) { + boolean useProjectSettings = store.getBoolean(ENABLE_PROJECT_SETTINGS); + btnEnableProjectSettings.setSelection(useProjectSettings); + setPropertySpecificOptionsEnabled(useProjectSettings); + enableCompilerOptions = enableCompilerOptions && useProjectSettings; + } + setCompilerOptionsEnabled(enableCompilerOptions); + } + + private void addEventListeners() { + btnCompileProtoFiles.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + boolean selected = btnCompileProtoFiles.getSelection(); + setCompilerOptionsEnabled(selected); + checkState(); + } + }); + btnUseProtocInSystemPath.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + boolean selected = btnCompileProtoFiles.getSelection(); + setCompilerCustomPathOptionsEnabled(!selected); + checkState(); + } + }); + btnUseProtocInCustomPath.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + boolean selected = btnCompileProtoFiles.getSelection(); + setCompilerCustomPathOptionsEnabled(selected); + checkState(); + } + }); + btnProtocPathBrowse.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + FileDialog dialog = new FileDialog(getShell(), SWT.OPEN | SWT.SHEET); + String file = dialog.open(); + if (file != null) txtProtocFilePath.setText(file); + } + }); + btnRefreshResources.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + refreshResourcesOptionsEnabled(btnRefreshResources.getSelection()); + } + }); + ModifyListener modifyListener = new ModifyListener() { + public void modifyText(ModifyEvent e) { + checkState(); + } + }; + txtProtocFilePath.addModifyListener(modifyListener); + txtOutputFolderName.addModifyListener(modifyListener); + if (isPropertyPage()) { + btnEnableProjectSettings.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + boolean useProjectSettings = btnEnableProjectSettings.getSelection(); + setPropertySpecificOptionsEnabled(useProjectSettings); + setCompilerOptionsEnabled(isEnabledAndSelected(btnCompileProtoFiles)); + } + }); + lnkEnableWorkspaceSettings.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + openWorkspacePreferences(dataMap); + } + }); + } + } + + private void openWorkspacePreferences(Object data) { + String id = PREFERENCE_PAGE_ID; + PreferencesUtil.createPreferenceDialogOn(getShell(), id, new String[] { id }, data).open(); + } + + private void checkState() { + String outputFolderName = txtOutputFolderName.getText(); + if (outputFolderName == null || outputFolderName.length() == 0) { + pageIsNowInvalid(CompilerPreferencePage_error_noOutputFolderName); + return; + } + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + IStatus validFolderName = workspace.validateName(outputFolderName, FOLDER); + if (validFolderName.getCode() != OK) { + pageIsNowInvalid(validFolderName.getMessage()); + return; + } + if (!customPathOptionSelectedAndEnabled()) { + pageIsNowValid(); + return; + } + String text = txtProtocFilePath.getText(); + if (text == null || text.length() == 0) { + pageIsNowInvalid(CompilerPreferencePage_error_noSelection); + return; + } + File file = new File(text); + if (!file.isFile() || !"protoc".equals(file.getName())) { + pageIsNowInvalid(CompilerPreferencePage_error_invalidProtoc); + return; + } + pageIsNowValid(); + } + + private void pageIsNowValid() { + setErrorMessage(null); + setValid(true); + } + + private void pageIsNowInvalid(String errorMessage) { + setErrorMessage(errorMessage); + setValid(false); + } + + /** {@inheritDoc} */ + @Override protected void performDefaults() { + IPreferenceStore store = doGetPreferenceStore(); + boolean compileProtoFiles = store.getDefaultBoolean(COMPILE_PROTO_FILES); + btnCompileProtoFiles.setSelection(compileProtoFiles); + btnUseProtocInSystemPath.setSelection(store.getDefaultBoolean(USE_PROTOC_IN_SYSTEM_PATH)); + btnUseProtocInCustomPath.setSelection(store.getDefaultBoolean(USE_PROTOC_IN_CUSTOM_PATH)); + txtProtocFilePath.setText(store.getDefaultString(PROTOC_FILE_PATH)); + btnJava.setSelection(store.getDefaultBoolean(GENERATE_JAVA_CODE)); + btnCpp.setSelection(store.getDefaultBoolean(GENERATE_CPP_CODE)); + btnPython.setSelection(store.getDefaultBoolean(GENERATE_PYTHON_CODE)); + txtOutputFolderName.setText(store.getDefaultString(OUTPUT_FOLDER_NAME)); + btnRefreshResources.setSelection(store.getDefaultBoolean(REFRESH_RESOURCES)); + btnRefreshProject.setSelection(store.getDefaultBoolean(REFRESH_PROJECT)); + btnRefreshOutputFolder.setSelection(store.getDefaultBoolean(REFRESH_OUTPUT_FOLDER)); + boolean enableCompilerOptions = compileProtoFiles; + if (isPropertyPage()) { + boolean useProjectSettings = store.getDefaultBoolean(ENABLE_PROJECT_SETTINGS); + btnEnableProjectSettings.setSelection(useProjectSettings); + setPropertySpecificOptionsEnabled(useProjectSettings); + enableCompilerOptions = enableCompilerOptions && useProjectSettings; + } + setCompilerOptionsEnabled(enableCompilerOptions); + super.performDefaults(); + } + + private void setPropertySpecificOptionsEnabled(boolean enabled) { + btnCompileProtoFiles.setEnabled(enabled); + lnkEnableWorkspaceSettings.setEnabled(!enabled); + } + + private void setCompilerOptionsEnabled(boolean enabled) { + tabFolder.setEnabled(enabled); + setCompilerPathOptionsEnabled(enabled); + setTargetLanguageOptionsEnabled(enabled); + setOutputOptionsEnabled(enabled); + setRefreshOptionsEnabled(enabled); + } + + private void setCompilerPathOptionsEnabled(boolean enabled) { + grpCompilerLocation.setEnabled(enabled); + btnUseProtocInSystemPath.setEnabled(enabled); + btnUseProtocInCustomPath.setEnabled(enabled); + setCompilerCustomPathOptionsEnabled(customPathOptionSelectedAndEnabled()); + } + + private void setCompilerCustomPathOptionsEnabled(boolean enabled) { + txtProtocFilePath.setEnabled(enabled); + btnProtocPathBrowse.setEnabled(enabled); + } + + private boolean customPathOptionSelectedAndEnabled() { + return isEnabledAndSelected(btnUseProtocInCustomPath); + } + + private boolean isEnabledAndSelected(Button b) { + return b.isEnabled() && b.getSelection(); + } + + private void setTargetLanguageOptionsEnabled(boolean enabled) { + grpTargetLanguage.setEnabled(enabled); + btnJava.setEnabled(enabled); + btnCpp.setEnabled(enabled); + btnPython.setEnabled(enabled); + } + + private void setOutputOptionsEnabled(boolean enabled) { + grpOutput.setEnabled(enabled); + lblOutputFolderName.setEnabled(enabled); + txtOutputFolderName.setEnabled(enabled); + } + + private void setRefreshOptionsEnabled(boolean enabled) { + btnRefreshResources.setEnabled(enabled); + refreshResourcesOptionsEnabled(isEnabledAndSelected(btnRefreshResources)); + } + + private void refreshResourcesOptionsEnabled(boolean enabled) { + grpRefresh.setEnabled(enabled); + btnRefreshProject.setEnabled(enabled); + btnRefreshOutputFolder.setEnabled(enabled); + } + + /** {@inheritDoc} */ + public void init(IWorkbench workbench) {} + + @Override public boolean performOk() { + savePreferences(); + return true; + } + + private void savePreferences() { + IPreferenceStore store = getPreferenceStore(); + if (isPropertyPage()) { + store.setValue(ENABLE_PROJECT_SETTINGS, btnEnableProjectSettings.getSelection()); + } + store.setValue(COMPILE_PROTO_FILES, btnCompileProtoFiles.getSelection()); + store.setValue(USE_PROTOC_IN_SYSTEM_PATH, btnUseProtocInSystemPath.getSelection()); + store.setValue(USE_PROTOC_IN_CUSTOM_PATH, btnUseProtocInCustomPath.getSelection()); + store.setValue(PROTOC_FILE_PATH, txtProtocFilePath.getText()); + store.setValue(GENERATE_JAVA_CODE, btnJava.getSelection()); + store.setValue(GENERATE_CPP_CODE, btnCpp.getSelection()); + store.setValue(GENERATE_PYTHON_CODE, btnPython.getSelection()); + store.setValue(OUTPUT_FOLDER_NAME, txtOutputFolderName.getText()); + store.setValue(REFRESH_RESOURCES, btnRefreshResources.getSelection()); + store.setValue(REFRESH_PROJECT, btnRefreshProject.getSelection()); + store.setValue(REFRESH_OUTPUT_FOLDER, btnRefreshOutputFolder.getSelection()); + } + + /** {@inheritDoc} */ + public IAdaptable getElement() { + return project; + } + + /** {@inheritDoc} */ + public void setElement(IAdaptable element) { + this.project = (IProject) element.getAdapter(IProject.class); + } + + @Override protected IPreferenceStore doGetPreferenceStore() { + if (isPropertyPage()) return preferenceStoreAccess.getWritablePreferenceStore(currentProject()); + return preferenceStoreAccess.getWritablePreferenceStore(); + } + + private boolean isPropertyPage() { + return project != null; + } + + private IProject currentProject() { + if (project == null) + throw new IllegalStateException("Not a property page case, but current project was requested."); + return project; + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") @Override public void applyData(Object data) { + if (data instanceof Map) this.dataMap = (Map<String, Object>) data; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/CompilerPreferences.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/CompilerPreferences.java new file mode 100644 index 0000000..2488865 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/CompilerPreferences.java
@@ -0,0 +1,47 @@ +/* + * 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.preferences; + +import static com.google.eclipse.protobuf.ui.preferences.CompilerPreferenceNames.*; + +import org.eclipse.core.resources.IProject; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess; + +/** + * Compiler preferences, retrieved from an <code>{@link IPreferenceStore}</code>. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class CompilerPreferences { + + public final boolean compileProtoFiles; + public final String protocPath; + public final TargetLanguage language; + public final String outputFolderName; + public final boolean refreshResources; + public final RefreshTarget refreshTarget; + + public static CompilerPreferences loadPreferences(IPreferenceStoreAccess access, IProject project) { + IPreferenceStore store = access.getWritablePreferenceStore(project); + boolean useProjectPreferences = store.getBoolean(ENABLE_PROJECT_SETTINGS); + if (!useProjectPreferences) store = access.getWritablePreferenceStore(); + return new CompilerPreferences(store); + } + + private CompilerPreferences(IPreferenceStore store) { + compileProtoFiles = store.getBoolean(COMPILE_PROTO_FILES); + boolean useProtocInSystemPath = store.getBoolean(USE_PROTOC_IN_SYSTEM_PATH); + protocPath = (useProtocInSystemPath) ? "protoc" : store.getString(PROTOC_FILE_PATH); + language = TargetLanguage.find(store); + outputFolderName = store.getString(OUTPUT_FOLDER_NAME); + refreshResources = store.getBoolean(REFRESH_RESOURCES); + refreshTarget = RefreshTarget.find(store); + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/CompilerPreferencesInitializer.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/CompilerPreferencesInitializer.java new file mode 100644 index 0000000..2895400 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/CompilerPreferencesInitializer.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.preferences; + +import static com.google.eclipse.protobuf.ui.preferences.CompilerPreferenceNames.*; + +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess; +import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer; + +/** + * Initializes default values for the "Compiler" preferences. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class CompilerPreferencesInitializer implements IPreferenceStoreInitializer { + + /** {@inheritDoc} */ + public void initialize(IPreferenceStoreAccess access) { + IPreferenceStore store = access.getWritablePreferenceStore(); + store.setDefault(ENABLE_PROJECT_SETTINGS, false); + store.setDefault(USE_PROTOC_IN_SYSTEM_PATH, true); + store.setDefault(GENERATE_JAVA_CODE, true); + store.setDefault(OUTPUT_FOLDER_NAME, "src-gen"); + store.setDefault(REFRESH_RESOURCES, true); + store.setDefault(REFRESH_OUTPUT_FOLDER, true); + } + +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/Messages.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/Messages.java new file mode 100644 index 0000000..89a0673 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/Messages.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.preferences; + +import org.eclipse.osgi.util.NLS; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +public class Messages extends NLS { + + static { + Class<Messages> targetType = Messages.class; + NLS.initializeMessages(targetType.getName(), targetType); + } + + private Messages() {} + + public static String CompilerPreferencePage_enableProjectSettings; + public static String CompilerPreferencePage_configureWorkspaceSettings; + public static String CompilerPreferencePage_mainTab; + public static String CompilerPreferencePage_refreshTab; + public static String CompilerPreferencePage_browseCustomPath; + public static String CompilerPreferencePage_compileOnSave; + public static String CompilerPreferencePage_customPath; + public static String CompilerPreferencePage_location; + public static String CompilerPreferencePage_systemPath; + public static String CompilerPreferencePage_targetLanguage; + public static String CompilerPreferencePage_generateJava; + public static String CompilerPreferencePage_generateCpp; + public static String CompilerPreferencePage_generatePython; + public static String CompilerPreferencePage_generatedCode; + public static String CompilerPreferencePage_outputFolderName; + public static String CompilerPreferencePage_refreshResources; + public static String CompilerPreferencePage_refreshProject; + public static String CompilerPreferencePage_refreshOutputProject; + public static String CompilerPreferencePage_error_noSelection; + public static String CompilerPreferencePage_error_invalidProtoc; + public static String CompilerPreferencePage_error_noOutputFolderName; +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/Messages.properties b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/Messages.properties new file mode 100644 index 0000000..b69400c --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/Messages.properties
@@ -0,0 +1,22 @@ +CompilerPreferencePage_enableProjectSettings=Enable project specific settings +CompilerPreferencePage_configureWorkspaceSettings=Configure Workspace Settings... +CompilerPreferencePage_mainTab=&Main +CompilerPreferencePage_refreshTab=&Refresh +CompilerPreferencePage_browseCustomPath=&Browse... +CompilerPreferencePage_compileOnSave=Compile .proto files on &save +CompilerPreferencePage_customPath=Use protoc &in: +CompilerPreferencePage_location=Compiler location (protoc) +CompilerPreferencePage_systemPath=Use protoc in &PATH +CompilerPreferencePage_targetLanguage=Target Language +CompilerPreferencePage_generateJava=&Java +CompilerPreferencePage_generateCpp=&C++ +CompilerPreferencePage_generatePython=&Python +CompilerPreferencePage_generatedCode=Generated Code +CompilerPreferencePage_outputFolderName=Folder Name: * +CompilerPreferencePage_refreshResources=Refresh resources upon completion. +CompilerPreferencePage_refreshProject=Project +CompilerPreferencePage_refreshOutputProject=Folder containing generated code +CompilerPreferencePage_error_noSelection=Select the path of protoc +CompilerPreferencePage_error_invalidProtoc=The selected file is not protoc +CompilerPreferencePage_error_noOutputFolderName=Enter the name of the output folder +
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/RefreshTarget.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/RefreshTarget.java new file mode 100644 index 0000000..8b6e0e7 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/RefreshTarget.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.preferences; + +import static com.google.eclipse.protobuf.ui.preferences.CompilerPreferenceNames.REFRESH_PROJECT; + +import org.eclipse.jface.preference.IPreferenceStore; + +/** + * The type of resource to refresh after calling protoc. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public enum RefreshTarget { + + PROJECT, OUTPUT_FOLDER; + + static RefreshTarget find(IPreferenceStore store) { + if (store.getBoolean(REFRESH_PROJECT)) return PROJECT; + return OUTPUT_FOLDER; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/TargetLanguage.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/TargetLanguage.java new file mode 100644 index 0000000..a1dcfef --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/TargetLanguage.java
@@ -0,0 +1,30 @@ +/* + * 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.preferences; + +import static com.google.eclipse.protobuf.ui.preferences.CompilerPreferenceNames.*; + +import org.eclipse.jface.preference.IPreferenceStore; + +/** + * Languages supported by protoc. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public enum TargetLanguage { + + JAVA, CPP, PYTHON; + + static TargetLanguage find(IPreferenceStore store) { + if (store.getBoolean(GENERATE_JAVA_CODE)) return JAVA; + if (store.getBoolean(GENERATE_CPP_CODE)) return CPP; + if (store.getBoolean(GENERATE_PYTHON_CODE)) return PYTHON; + return JAVA; + } +} \ No newline at end of file
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/ProtobufQuickfixProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/ProtobufQuickfixProvider.java new file mode 100644 index 0000000..59fc306 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/ProtobufQuickfixProvider.java
@@ -0,0 +1,29 @@ +/* + * 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.quickfix; + +import org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +public class ProtobufQuickfixProvider extends DefaultQuickfixProvider { + +// @Fix(MyJavaValidator.INVALID_NAME) +// public void capitalizeName(final Issue issue, IssueResolutionAcceptor acceptor) { +// acceptor.accept(issue, "Capitalize name", "Capitalize the name.", "upcase.png", new IModification() { +// public void apply(IModificationContext context) throws BadLocationException { +// IXtextDocument xtextDocument = context.getXtextDocument(); +// String firstLetter = xtextDocument.get(issue.getOffset(), 1); +// xtextDocument.replace(issue.getOffset(), 1, firstLetter.toUpperCase()); +// } +// }); +// } + +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Literals.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Literals.java new file mode 100644 index 0000000..9d8d8c0 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Literals.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.util; + +import static java.lang.Math.max; + +import org.eclipse.emf.ecore.EObject; + +import com.google.eclipse.protobuf.protobuf.Literal; +import com.google.inject.Singleton; + +/** + * Utility methods for instances of <code>{@link Literal}</code>. + * + * @author alruiz@google.com (Alex Ruiz) + */ +@Singleton +public class Literals { + + public int calculateIndexOf(Literal l) { + int index = 0; + for (EObject o : l.eContainer().eContents()) { + if (o == l || !(o instanceof Literal)) continue; + Literal c = (Literal) o; + index = max(index, c.getIndex()); + } + return ++index; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Properties.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Properties.java new file mode 100644 index 0000000..7e2fadc --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Properties.java
@@ -0,0 +1,62 @@ +/* + * 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 static java.lang.Math.max; + +import org.eclipse.emf.ecore.EObject; + +import com.google.eclipse.protobuf.protobuf.*; +import com.google.eclipse.protobuf.ui.grammar.Keywords; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +/** + * Utility methods for instances of <code>{@link Property}</code>. + * + * @author alruiz@google.com (Alex Ruiz) + */ +@Singleton +public class Properties { + + @Inject private Keywords keywords; + + public boolean isStringProperty(Property p) { + return keywords.string().getValue().equals(nameOfTypeIn(p)); + } + + public boolean isBoolProperty(Property p) { + return keywords.bool().getValue().equals(nameOfTypeIn(p)); + } + + /** + * Returns the name of the type of the given <code>{@link Property}</code>. + * @param p the given {@code Property}. + * @return the name of the type of the given {@code Property}. + */ + public String nameOfTypeIn(Property p) { + AbstractTypeReference r = p.getType(); + if (r instanceof ScalarTypeReference) return ((ScalarTypeReference) r).getScalar().getName(); + if (r instanceof TypeReference) { + Type type = ((TypeReference) r).getType(); + return type == null ? null : type.getName(); + } + return r.toString(); + } + + public int calculateIndexOf(Property p) { + int index = 0; + for (EObject o : p.eContainer().eContents()) { + if (o == p || !(o instanceof Property)) continue; + Property c = (Property) o; + index = max(index, c.getIndex()); + } + return ++index; + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Strings.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Strings.java new file mode 100644 index 0000000..6a9f9cb --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Strings.java
@@ -0,0 +1,31 @@ +/* + * 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 static java.lang.Character.toLowerCase; + +import com.google.inject.Singleton; + +/** + * Utility classes for {@code String}s. + * + * @author alruiz@google.com (Alex Ruiz) + */ +@Singleton +public class Strings { + + public String firstCharToLowerCase(String s) { + if (s == null) return null; + if (s.length() == 0) return s; + char[] chars = s.toCharArray(); + chars[0] = toLowerCase(chars[0]); + return new String(chars); + } + +}
diff --git a/com.google.eclipse.protobuf/.antlr-generator-3.2.0.jar b/com.google.eclipse.protobuf/.antlr-generator-3.2.0.jar new file mode 100644 index 0000000..4243492 --- /dev/null +++ b/com.google.eclipse.protobuf/.antlr-generator-3.2.0.jar Binary files differ
diff --git a/com.google.eclipse.protobuf/.classpath b/com.google.eclipse.protobuf/.classpath new file mode 100644 index 0000000..7e8449d --- /dev/null +++ b/com.google.eclipse.protobuf/.classpath
@@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="src-gen"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="output" path="bin"/> +</classpath>
diff --git a/com.google.eclipse.protobuf/.project b/com.google.eclipse.protobuf/.project new file mode 100644 index 0000000..b524930 --- /dev/null +++ b/com.google.eclipse.protobuf/.project
@@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>com.google.eclipse.protobuf</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.xtext.ui.shared.xtextBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.xtext.ui.shared.xtextNature</nature> + </natures> +</projectDescription>
diff --git a/com.google.eclipse.protobuf/.settings/org.eclipse.jdt.core.prefs b/com.google.eclipse.protobuf/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..002551b --- /dev/null +++ b/com.google.eclipse.protobuf/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,81 @@ +#Wed Apr 06 10:56:09 PDT 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=warning +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=warning +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.5
diff --git a/com.google.eclipse.protobuf/META-INF/MANIFEST.MF b/com.google.eclipse.protobuf/META-INF/MANIFEST.MF new file mode 100644 index 0000000..cbe1187 --- /dev/null +++ b/com.google.eclipse.protobuf/META-INF/MANIFEST.MF
@@ -0,0 +1,32 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %Bundle-Name +Bundle-Vendor: %Bundle-Vendor +Bundle-Version: 1.0.0 +Bundle-SymbolicName: com.google.eclipse.protobuf; singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: org.eclipse.xtext, + org.eclipse.xtext.generator;resolution:=optional, + org.eclipse.emf.codegen.ecore;resolution:=optional, + org.eclipse.emf.mwe.utils;resolution:=optional, + org.eclipse.emf.mwe2.launch;resolution:=optional, + com.ibm.icu;resolution:=optional, + org.eclipse.xtext.util, + org.eclipse.emf.ecore, + org.eclipse.emf.common, + org.antlr.runtime, + org.eclipse.core.runtime;bundle-version="3.7.0" +Import-Package: org.apache.log4j, + org.apache.commons.logging +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Export-Package: com.google.eclipse.protobuf, + com.google.eclipse.protobuf.parseTreeConstruction, + com.google.eclipse.protobuf.parser.antlr, + com.google.eclipse.protobuf.parser.antlr.internal, + com.google.eclipse.protobuf.protobuf, + com.google.eclipse.protobuf.protobuf.impl, + com.google.eclipse.protobuf.protobuf.util, + com.google.eclipse.protobuf.scoping, + com.google.eclipse.protobuf.services, + com.google.eclipse.protobuf.util, + com.google.eclipse.protobuf.validation
diff --git a/com.google.eclipse.protobuf/OSGI-INF/l10n/bundle.properties b/com.google.eclipse.protobuf/OSGI-INF/l10n/bundle.properties new file mode 100644 index 0000000..a8b3cdb --- /dev/null +++ b/com.google.eclipse.protobuf/OSGI-INF/l10n/bundle.properties
@@ -0,0 +1,3 @@ +#Properties file for com.google.eclipse.protobuf +Bundle-Vendor = Google Inc. +Bundle-Name = com.google.eclipse.protobuf \ No newline at end of file
diff --git a/com.google.eclipse.protobuf/build.properties b/com.google.eclipse.protobuf/build.properties new file mode 100644 index 0000000..300fb1a --- /dev/null +++ b/com.google.eclipse.protobuf/build.properties
@@ -0,0 +1,6 @@ +source.. = src/,\ + src-gen/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + OSGI-INF/
diff --git a/com.google.eclipse.protobuf/global.proto b/com.google.eclipse.protobuf/global.proto new file mode 100644 index 0000000..294cd0e --- /dev/null +++ b/com.google.eclipse.protobuf/global.proto
@@ -0,0 +1,22 @@ +message FileOptions { + + optional string java_package = 1; + optional string java_outer_classname = 8; + optional bool java_multiple_files = 10 [default=false]; + optional bool java_generate_equals_and_hash = 20 [default=false]; + + enum OptimizeMode { + SPEED = 1; // Generate complete code for parsing, serialization, etc. + CODE_SIZE = 2; // Use ReflectionOps to implement these methods. + LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. + } + + optional OptimizeMode optimize_for = 9 [default=SPEED]; + optional bool cc_generic_services = 16 [default=false]; + optional bool java_generic_services = 17 [default=false]; + optional bool py_generic_services = 18 [default=false]; + + repeated UninterpretedOption uninterpreted_option = 999; + + extensions 1000 to max; +}
diff --git a/com.google.eclipse.protobuf/plugin.xml b/com.google.eclipse.protobuf/plugin.xml new file mode 100644 index 0000000..c9018bb --- /dev/null +++ b/com.google.eclipse.protobuf/plugin.xml
@@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?eclipse version="3.0"?> + +<plugin> + + <extension point="org.eclipse.emf.ecore.generated_package"> + <package + uri = "http://www.google.com/eclipse/protobuf/Protobuf" + class = "com.google.eclipse.protobuf.protobuf.ProtobufPackage" + genModel = "com/google/eclipse/protobuf/Protobuf.genmodel" /> + + </extension> + + + + +</plugin>
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/GenerateProtobuf.mwe2 b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/GenerateProtobuf.mwe2 new file mode 100644 index 0000000..a954940 --- /dev/null +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/GenerateProtobuf.mwe2
@@ -0,0 +1,109 @@ +/* + * 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 + * + * Generated by Xtext + */ +module com.google.eclipse.protobuf.Protobuf + +import org.eclipse.emf.mwe.utils.* +import org.eclipse.xtext.generator.* +import org.eclipse.xtext.ui.generator.* + +var grammarURI = "classpath:/com/google/eclipse/protobuf/Protobuf.xtext" +var file.extensions = "proto" +var projectName = "com.google.eclipse.protobuf" +var runtimeProject = "../${projectName}" + +Workflow { + bean = StandaloneSetup { + platformUri = "${runtimeProject}/.." + } + + component = DirectoryCleaner { + directory = "${runtimeProject}/src-gen" + } + + component = DirectoryCleaner { + directory = "${runtimeProject}.ui/src-gen" + } + + component = Generator { + pathRtProject = runtimeProject + pathUiProject = "${runtimeProject}.ui" + projectNameRt = projectName + projectNameUi = "${projectName}.ui" + language = { + uri = grammarURI + fileExtensions = file.extensions + + // Java API to access grammar elements (required by several other fragments) + fragment = grammarAccess.GrammarAccessFragment {} + + // generates Java API for the generated EPackages + fragment = ecore.EcoreGeneratorFragment { + // referencedGenModels = "uri to genmodel, uri to next genmodel" + } + + // the serialization component + fragment = parseTreeConstructor.ParseTreeConstructorFragment {} + + // a custom ResourceFactory for use with EMF + fragment = resourceFactory.ResourceFactoryFragment { + fileExtensions = file.extensions + } + + // The antlr parser generator fragment. + fragment = parser.antlr.XtextAntlrGeneratorFragment { + // options = { + // backtrack = true + // } + } + + // java-based API for validation + fragment = validation.JavaValidatorFragment { + composedCheck = "org.eclipse.xtext.validation.ImportUriValidator" + composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator" + // registerForImportedPackages = true + } + + // scoping and exporting API + // fragment = scoping.ImportURIScopingFragment {} + // fragment = exporting.SimpleNamesFragment {} + + // scoping and exporting API + fragment = scoping.ImportNamespacesScopingFragment {} + fragment = exporting.QualifiedNamesFragment {} + fragment = builder.BuilderIntegrationFragment {} + + // formatter API + fragment = formatting.FormatterFragment {} + + // labeling API + fragment = labeling.LabelProviderFragment {} + + // outline API + fragment = outline.OutlineTreeProviderFragment {} + fragment = outline.QuickOutlineFragment {} + + // quickfix API + fragment = quickfix.QuickfixProviderFragment {} + + // content assist API + fragment = contentAssist.JavaBasedContentAssistFragment {} + + // generates a more lightweight Antlr parser and lexer tailored for content assist + fragment = parser.antlr.XtextAntlrUiGeneratorFragment {} + + // project wizard (optional) + // fragment = projectWizard.SimpleProjectWizardFragment { + // generatorProjectName = "${projectName}.generator" + // modelFileExtension = file.extensions + // } + } + } +}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext new file mode 100644 index 0000000..944e1b2 --- /dev/null +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext
@@ -0,0 +1,126 @@ +/* + * 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 + * + * Author: alruiz@google.com (Alex Ruiz) + */ + +grammar com.google.eclipse.protobuf.Protobuf with org.eclipse.xtext.common.Terminals + +import "http://www.eclipse.org/emf/2002/Ecore" as ecore +generate protobuf "http://www.google.com/eclipse/protobuf/Protobuf" + +Protobuf: + (package=Package)? + (imports+=Import)* + (options+=Option)* + (elements+=ProtobufElement)*; + +Package: + 'package' name=QualifiedName ';'; + +Import: + 'import' importURI=STRING ';'; + +QualifiedName: + ID ('.' ID)*; + +Option: + 'option' name=ID '=' value=ValueRef ';'; + +ProtobufElement: + Type | ExtendMessage; + +Type: + Message | Enum; + +Message: + 'message' name=ID '{' + elements+=MessageElement* + ('extensions' extensionsFrom=INT 'to' (extensionsTo=INT | 'max') ';')? + '}'; + +MessageElement: + Type | Property; + +Property: + modifier=Modifier type=AbstractTypeReference name=ID '=' index=INT (('[' 'default' '=' default=ValueRef + ']') | ('[' 'packed' '=' packed=BooleanRef ']'))? ';'; + +enum Modifier: + required + | optional + | repeated; + +AbstractTypeReference: + ScalarTypeReference | TypeReference; + +ScalarTypeReference: + scalar=ScalarType; + +enum ScalarType: + double + | float + | int32 + | int64 + | uint32 + | uint64 + | sint32 + | sint64 + | fixed32 + | fixed64 + | sfixed32 + | sfixed64 + | bool + | string + | bytes; + +TypeReference: + type=[Type | QualifiedName]; + +ValueRef: + LiteralRef + | BooleanRef + | IntRef + | FloatRef + | StringRef; + +LiteralRef: + literal=[Literal]; + +BooleanRef: + boolean=BOOL; + +enum BOOL: + true + | false; + +IntRef: + int=INT; + +FloatRef: + float=FLOAT; + +StringRef: + string=STRING; + +Enum: + 'enum' name=ID '{' + literals+=Literal* + '}' ';'?; + +Literal: + name=ID '=' index=INT ';'; + +ExtendMessage: + 'extend' message=[Message] '{' + elements+=MessageElement* + '}'; + +terminal INT returns ecore::EInt: ('0'..'9')+; +terminal FLOAT returns ecore::EFloat: ('0'..'9')* ('.' ('0'..'9')+)?; + \ No newline at end of file
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/ProtobufRuntimeModule.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/ProtobufRuntimeModule.java new file mode 100644 index 0000000..5492360 --- /dev/null +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/ProtobufRuntimeModule.java
@@ -0,0 +1,37 @@ +/* + * 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; + +import org.eclipse.xtext.naming.IQualifiedNameProvider; +import org.eclipse.xtext.scoping.IGlobalScopeProvider; +import org.eclipse.xtext.scoping.impl.*; + +import com.google.eclipse.protobuf.naming.ProtobufQualifiedNameProvider; +import com.google.eclipse.protobuf.scoping.SimpleImportUriResolver; +import com.google.inject.Binder; + +/** + * Use this class to register components to be used at runtime / without the Equinox extension registry. + */ +public class ProtobufRuntimeModule extends com.google.eclipse.protobuf.AbstractProtobufRuntimeModule { + + /** {@inheritDoc} */ + @Override public Class<? extends IGlobalScopeProvider> bindIGlobalScopeProvider() { + return ImportUriGlobalScopeProvider.class; + } + + /** {@inheritDoc} */ + @Override public Class<? extends IQualifiedNameProvider> bindIQualifiedNameProvider() { + return ProtobufQualifiedNameProvider.class; + } + + public void configureImportUriResolver(Binder binder) { + binder.bind(ImportUriResolver.class).to(SimpleImportUriResolver.class); + } +}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/ProtobufStandaloneSetup.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/ProtobufStandaloneSetup.java new file mode 100644 index 0000000..ac0af7c --- /dev/null +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/ProtobufStandaloneSetup.java
@@ -0,0 +1,20 @@ +/* + * 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; + +/** + * Initialization support for running Xtext languages without Equinox extension registry. + */ +public class ProtobufStandaloneSetup extends ProtobufStandaloneSetupGenerated{ + + public static void doSetup() { + new ProtobufStandaloneSetup().createInjectorAndDoEMFRegistration(); + } +} +
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/formatting/ProtobufFormatter.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/formatting/ProtobufFormatter.java new file mode 100644 index 0000000..10d911a --- /dev/null +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/formatting/ProtobufFormatter.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.formatting; + +import org.eclipse.xtext.formatting.impl.*; + +import com.google.eclipse.protobuf.services.ProtobufGrammarAccess; + +/** + * This class contains custom formatting description. + * + * @see http://www.eclipse.org/Xtext/documentation/latest/xtext.html#formatting on how and when to use it + * @see {@link org.eclipse.xtext.xtext.XtextFormattingTokenSerializer} as an example + */ +public class ProtobufFormatter extends AbstractDeclarativeFormatter { + + @Override + protected void configureFormatting(FormattingConfig c) { + ProtobufGrammarAccess g = (ProtobufGrammarAccess) getGrammarAccess(); + c.setLinewrap(0, 1, 2).before(g.getSL_COMMENTRule()); + } +}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java new file mode 100644 index 0000000..2019edc --- /dev/null +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java
@@ -0,0 +1,41 @@ +/* + * 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.naming; + +import java.util.*; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.naming.*; + +import com.google.eclipse.protobuf.protobuf.Package; +import com.google.eclipse.protobuf.util.EObjectFinder; +import com.google.inject.Inject; + +/** + * Provides fully-qualified names for protobuf elements. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class ProtobufQualifiedNameProvider extends DefaultDeclarativeQualifiedNameProvider { + + @Inject private EObjectFinder finder; + + /** {@inheritDoc} */ + @Override public QualifiedName getFullyQualifiedName(EObject obj) { + QualifiedName fqn = super.getFullyQualifiedName(obj); + if (fqn == null || obj instanceof Package) return fqn; + Package p = finder.findPackage(obj); + if (p == null) return fqn; + List<String> segments = new ArrayList<String>(fqn.getSegments()); + String packageName = p.getName(); + if (packageName != null && !segments.isEmpty() && !packageName.equals(segments.get(0))) + segments.add(0, packageName); + return QualifiedName.create(segments.toArray(new String[segments.size()])); + } +}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/GlobalScope.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/GlobalScope.java new file mode 100644 index 0000000..0e3dfc2 --- /dev/null +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/GlobalScope.java
@@ -0,0 +1,114 @@ +/* + * 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.unmodifiableCollection; +import static org.eclipse.core.runtime.FileLocator.*; + +import java.io.*; +import java.net.URL; +import java.util.*; + +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.emf.common.util.URI; +import org.eclipse.xtext.parser.IParseResult; +import org.eclipse.xtext.parser.IParser; +import org.eclipse.xtext.resource.XtextResource; +import org.osgi.framework.Bundle; + +import com.google.eclipse.protobuf.protobuf.*; +import com.google.eclipse.protobuf.protobuf.Enum; +import com.google.eclipse.protobuf.util.EObjectFinder; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +/** + * Protobuf elements accesible to any .proto file. + * + * @author alruiz@google.com (Alex Ruiz) + */ +@Singleton +public class GlobalScope { + + private Protobuf root; + + private boolean initialized; + private Map<String, Property> fileOptions = new LinkedHashMap<String, Property>(); + private Enum optimizedMode; + + @Inject EObjectFinder finder; + + @Inject public GlobalScope(IParser parser) { + try { + XtextResource resource = new XtextResource(URI.createURI("")); + IParseResult result = parser.parse(new InputStreamReader(globalScopeContents(), "UTF-8")); + root = (Protobuf) result.getRootASTElement(); + resource.getContents().add(root); + } catch (IOException e) { + throw new IllegalStateException("Unable to parse global scope", e); + } + } + + private static InputStream globalScopeContents() throws IOException { + Bundle bundle = Platform.getBundle("com.google.eclipse.protobuf"); + Path originPath = new Path("global.proto"); + URL bundledFileURL = find(bundle, originPath, null); + return (InputStream) resolve(bundledFileURL).getContent(); + } + + private void init() { + if (initialized) return; + initialized = true; + Message m = fileOptionsMessage(); + for (MessageElement e : m.getElements()) { + if (e instanceof Property) { + addFileOption((Property) e); + continue; + } + if (e instanceof Enum && "OptimizeMode".equals(e.getName())) { + optimizedMode = (Enum) e; + continue; + } + } + } + + private Message fileOptionsMessage() { + for (ProtobufElement e : root.getElements()) { + if (!(e instanceof Message)) continue; + Message m = (Message) e; + if ("FileOptions".equals(m.getName())) return m; + } + return null; + } + + private void addFileOption(Property p) { + fileOptions.put(p.getName(), p); + } + + public Collection<Property> fileOptions() { + init(); + return unmodifiableCollection(fileOptions.values()); + } + + public Enum optimizedMode() { + init(); + return optimizedMode; + } + + public boolean isOptimizeForOption(Option option) { + init(); + return "optimize_for".equals(option.getName()); + } + + public Property lookupFileOption(String name) { + init(); + return fileOptions.get(name); + } +}
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 new file mode 100644 index 0000000..2a32b85 --- /dev/null +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
@@ -0,0 +1,64 @@ +/* + * 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 org.eclipse.xtext.resource.EObjectDescription.create; + +import java.util.*; + +import org.eclipse.emf.ecore.*; +import org.eclipse.xtext.resource.IEObjectDescription; +import org.eclipse.xtext.scoping.IScope; +import org.eclipse.xtext.scoping.impl.*; + +import com.google.eclipse.protobuf.protobuf.*; +import com.google.eclipse.protobuf.protobuf.Enum; +import com.google.eclipse.protobuf.util.EObjectFinder; +import com.google.inject.Inject; + +/** + * Custom scoping description. + * + * @author alruiz@google.com (Alex Ruiz) + * + * @see http://www.eclipse.org/Xtext/documentation/latest/xtext.html#scoping + */ +public class ProtobufScopeProvider extends AbstractDeclarativeScopeProvider { + + private static final boolean DO_NOT_IGNORE_CASE = false; + + @Inject private EObjectFinder finder; + @Inject private GlobalScope globalScope; + + @SuppressWarnings("unused") + IScope scope_LiteralRef_literal(LiteralRef literalRef, EReference reference) { + EObject container = literalRef.eContainer(); + if (container instanceof Property) { + Enum enumType = finder.enumTypeOfProperty((Property) container); + if (enumType != null) return scopeForLiteralsIn(enumType); + } + if (container instanceof Option && globalScope.isOptimizeForOption((Option) container)) { + Enum optimizedMode = globalScope.optimizedMode(); + return scopeForLiteralsIn(optimizedMode); + } + return null; + } + + private static IScope scopeForLiteralsIn(Enum enumType) { + List<IEObjectDescription> descriptions = descriptionsFrom(enumType); + return new SimpleScope(descriptions, DO_NOT_IGNORE_CASE); + } + + private static List<IEObjectDescription> descriptionsFrom(Enum enumType) { + List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>(); + for (Literal literal : enumType.getLiterals()) + descriptions.add(create(literal.getName(), literal)); + return descriptions; + } +}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/SimpleImportUriResolver.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/SimpleImportUriResolver.java new file mode 100644 index 0000000..4e57e85 --- /dev/null +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/SimpleImportUriResolver.java
@@ -0,0 +1,72 @@ +/* + * 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 java.util.List; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.scoping.impl.ImportUriResolver; + +import com.google.eclipse.protobuf.protobuf.Import; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +public class SimpleImportUriResolver extends ImportUriResolver { + + private static final String PREFIX = "platform:/resource"; + + /** + * Prefix used by EMF for resource URIs: "platform:/resource/". + */ + public static final String URI_PREFIX = PREFIX + "/"; + + /** {@inheritDoc} */ + @Override public String apply(EObject from) { + if (from instanceof Import) + fixUri((Import) from); + return super.apply(from); + } + + /* + * The import URI is relative to the file where the import is. Protoc works fine, but the editor doesn't. + * In order for the editor to see the import, we need to add to the import URI "platform:resource" and the parent + * folder of the file containing the import. + * + * For example: given the following file hierarchy: + * + * - protobuf-test (project) + * - folder + * - proto2.proto + * - proto1.proto + * + * If we import "folder/proto2.proto" into proto1.proto, proto1.proto will compile fine, but the editor will complain. + * We need to have the import URI as "platform:/resource/protobuf-test/folder/proto2.proto" for the editor to see it. + */ + private void fixUri(Import i) { + String prefix = uriPrefix(i.eResource().getURI()); + String uri = i.getImportURI(); + if (!uri.startsWith(prefix)) { + if (!uri.startsWith(prefix)) prefix += "/"; + i.setImportURI(prefix + uri); + } + } + + private String uriPrefix(URI containerUri) { + StringBuilder prefix = new StringBuilder(); + prefix.append(PREFIX); + int start = (containerUri.scheme() == null) ? 0 : 1; // ignore the scheme if present (e.g. "resource") + List<String> segments = containerUri.segmentsList(); + int end = segments.size() - 1; // ignore file name (at the end of the URI) + for (int j = start; j < end; j++) + prefix.append("/").append(segments.get(j)); + return prefix.toString(); + } +}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/EObjectFinder.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/EObjectFinder.java new file mode 100644 index 0000000..82c470a --- /dev/null +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/EObjectFinder.java
@@ -0,0 +1,48 @@ +/* + * 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.util; + +import org.eclipse.emf.ecore.EObject; + +import com.google.eclipse.protobuf.protobuf.*; +import com.google.eclipse.protobuf.protobuf.Enum; +import com.google.eclipse.protobuf.protobuf.Package; +import com.google.inject.Singleton; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +@Singleton +public class EObjectFinder { + + public Enum enumTypeOfProperty(Property p) { + AbstractTypeReference aTypeRef = (p).getType(); + if (aTypeRef instanceof TypeReference) { + Type type = ((TypeReference) aTypeRef).getType(); + if (type instanceof Enum) return (Enum) type; + } + return null; + } + + public ScalarType scalarTypeOfProperty(Property p) { + AbstractTypeReference aTypeRef = (p).getType(); + if (aTypeRef instanceof ScalarTypeReference) + return ((ScalarTypeReference) aTypeRef).getScalar(); + return null; + } + + public Package findPackage(EObject o) { + EObject current = o; + while (current != null) { + if (current instanceof Protobuf) return ((Protobuf) current).getPackage(); + current = current.eContainer(); + } + return null; + } +}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java new file mode 100644 index 0000000..5932ad4 --- /dev/null +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.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.validation; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +public class ProtobufJavaValidator extends AbstractProtobufJavaValidator { + +// @Check +// public void checkGreetingStartsWithCapital(Greeting greeting) { +// if (!Character.isUpperCase(greeting.getName().charAt(0))) { +// warning("Name should start with a capital", MyDslPackage.GREETING__NAME); +// } +// } + +}