Fixed: [ Issue 56 ] Keywords are valid element names https://code.google.com/p/protobuf-dt/issues/detail?id=56
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java index 9f6c7ab..380ffc4 100644 --- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
@@ -15,19 +15,19 @@ import org.eclipse.ui.plugin.AbstractUIPlugin; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; import org.eclipse.xtext.ui.LanguageSpecific; -import org.eclipse.xtext.ui.editor.IURIEditorOpener; -import org.eclipse.xtext.ui.editor.IXtextEditorCallback; +import org.eclipse.xtext.ui.editor.*; import org.eclipse.xtext.ui.editor.model.XtextDocumentProvider; import org.eclipse.xtext.ui.editor.outline.actions.IOutlineContribution; import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer; +import org.eclipse.xtext.ui.editor.syntaxcoloring.ISemanticHighlightingCalculator; import com.google.eclipse.protobuf.scoping.IFileUriResolver; import com.google.eclipse.protobuf.ui.builder.AutoAddNatureEditorCallback; import com.google.eclipse.protobuf.ui.editor.ProtobufUriEditorOpener; import com.google.eclipse.protobuf.ui.editor.hyperlinking.ProtobufHyperlinkDetector; import com.google.eclipse.protobuf.ui.editor.model.ProtobufDocumentProvider; -import com.google.eclipse.protobuf.ui.outline.LinkWithEditor; -import com.google.eclipse.protobuf.ui.outline.ProtobufOutlinePage; +import com.google.eclipse.protobuf.ui.editor.syntaxcoloring.ProtobufSemanticHighlightingCalculator; +import com.google.eclipse.protobuf.ui.outline.*; import com.google.eclipse.protobuf.ui.preferences.compiler.CompilerPreferenceStoreInitializer; import com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferenceStoreInitializer; import com.google.eclipse.protobuf.ui.scoping.FileUriResolver; @@ -92,4 +92,8 @@ .annotatedWith(LanguageSpecific.class) .to(ProtobufUriEditorOpener.class); } + + public void configureSemanticHighlightingCalculator(Binder binder) { + binder.bind(ISemanticHighlightingCalculator.class).to(ProtobufSemanticHighlightingCalculator.class); + } }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/syntaxcoloring/ProtobufSemanticHighlightingCalculator.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/syntaxcoloring/ProtobufSemanticHighlightingCalculator.java new file mode 100644 index 0000000..5a730de --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/syntaxcoloring/ProtobufSemanticHighlightingCalculator.java
@@ -0,0 +1,122 @@ +/* + * Created on Jun 2, 2011 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * Copyright @2011 the original author or authors. + */ +package com.google.eclipse.protobuf.ui.editor.syntaxcoloring; + +import static org.eclipse.xtext.nodemodel.util.NodeModelUtils.findNodesForFeature; +import static org.eclipse.xtext.ui.editor.syntaxcoloring.DefaultHighlightingConfiguration.DEFAULT_ID; + +import java.util.List; + +import org.eclipse.emf.ecore.*; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.ui.editor.syntaxcoloring.*; + +import com.google.eclipse.protobuf.protobuf.*; +import com.google.eclipse.protobuf.protobuf.Package; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +public class ProtobufSemanticHighlightingCalculator implements ISemanticHighlightingCalculator { + + public void provideHighlightingFor(XtextResource resource, IHighlightedPositionAcceptor acceptor) { + if (resource.getContents().isEmpty()) return; + Protobuf protobuf = (Protobuf) resource.getContents().get(0); + highlightAllNames(protobuf, acceptor, DEFAULT_ID); + } + + private void highlightAllNames(Protobuf protobuf, IHighlightedPositionAcceptor acceptor, String highlightId) { + highlightPackageName(protobuf, acceptor, highlightId); + highlightFileOptionNames(protobuf, acceptor, highlightId); + highlightElementNames(protobuf, acceptor, highlightId); + } + + private void highlightPackageName(Protobuf protobuf, IHighlightedPositionAcceptor acceptor, String highlightId) { + Package aPackage = protobuf.getPackage(); + if (aPackage == null) return; + highlightName(aPackage, acceptor, highlightId); + } + + private void highlightFileOptionNames(Protobuf protobuf, IHighlightedPositionAcceptor acceptor, String highlightId) { + for (Option option : protobuf.getOptions()) { + highlightName(option, acceptor, highlightId); + } + } + + private void highlightElementNames(Protobuf protobuf, IHighlightedPositionAcceptor acceptor, String highlightId) { + for (ProtobufElement element : protobuf.getElements()) { + if (element instanceof Type) { + highlightName(element, acceptor, highlightId); + if (element instanceof Message) highlightElementNames((Message) element, acceptor, highlightId); + continue; + } + if (element instanceof Service) { + highlightName(element, acceptor, highlightId); + highlightRpcNames((Service) element, acceptor, highlightId); + } + } + } + + private void highlightElementNames(Message message, IHighlightedPositionAcceptor acceptor, String highlightId) { + for (MessageElement element : message.getElements()) { + if (element instanceof Option) { + highlightName(element, acceptor, highlightId); + continue; + } + if (element instanceof Field) { + highlightName(element, acceptor, highlightId); + highLightFieldOptionNames((Field) element, acceptor, highlightId); + } + if (element instanceof Group) { + for (Property property : ((Group) element).getElements()) { + highlightName(property, acceptor, highlightId); + highLightFieldOptionNames(property, acceptor, highlightId); + } + } + } + } + + private void highLightFieldOptionNames(Field field, IHighlightedPositionAcceptor acceptor, String highlightId) { + for (FieldOption option : field.getFieldOptions()) { + highlightName(option, acceptor, highlightId); + } + } + + private void highlightRpcNames(Service service, IHighlightedPositionAcceptor acceptor, String highlightId) { + for (Rpc rpc : service.getRpcs()) { + highlightName(rpc, acceptor, highlightId); + for (Option option : rpc.getOptions()) { + highlightName(option, acceptor, highlightId); + } + } + } + + private void highlightName(EObject o, IHighlightedPositionAcceptor acceptor, String highlightId) { + highlightFirstFeature(o, o.eClass().getEStructuralFeature("name"), highlightId, acceptor); + } + + private void highlightFirstFeature(EObject semantic, EStructuralFeature feature, String highlightId, + IHighlightedPositionAcceptor acceptor) { + INode node = firstFeatureNode(semantic, feature); + if (node == null || node.getText() == null) return; + acceptor.addPosition(node.getOffset(), node.getText().length(), highlightId); + } + + public INode firstFeatureNode(EObject semantic, EStructuralFeature feature) { + List<INode> nodes = findNodesForFeature(semantic, feature); + return (nodes.size() == 1) ? nodes.get(0) : null; + } +}
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 index 9926ea1..303bc4a 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext
@@ -29,10 +29,10 @@ 'import' importURI=STRING ';'; QualifiedName: - ID ('.' ID)*; + Name ('.' Name)*; Option: - 'option' name=ID '=' value=ValueRef ';'; + 'option' name=Name '=' value=ValueRef ';'; ProtobufElement: Type | ExtendMessage | Service; @@ -41,7 +41,7 @@ Message | Enum; Message: - 'message' name=ID '{' + 'message' name=Name '{' elements+=MessageElement* ('extensions' extensionsFrom=INT 'to' (extensionsTo=INT | 'max') ';')? '}'(';')?; @@ -53,13 +53,13 @@ Property | Group; Group: - modifier=Modifier 'group' name=ID '=' index=INT + modifier=Modifier 'group' name=Name '=' index=INT ('[' (fieldOptions+=FieldOption (',' fieldOptions+=FieldOption)*) ']')? '{' elements+=Property* '}'(';')?; Property: - modifier=Modifier type=AbstractTypeReference name=(ID | 'message') '=' index=INT + modifier=Modifier type=AbstractTypeReference name=Name '=' index=INT ( ('[' 'default' '=' default=ValueRef ']') | ('[' 'default' '=' default=ValueRef (',' fieldOptions+=FieldOption)* ']') | @@ -67,7 +67,7 @@ )? ';'; FieldOption: - name=ID '=' value=ValueRef; + name=Name '=' value=ValueRef; enum Modifier: required @@ -127,12 +127,12 @@ string=STRING; Enum: - 'enum' name=ID '{' + 'enum' name=Name '{' literals+=Literal* '}' ';'?; Literal: - name=ID '=' index=INT ';'; + name=Name '=' index=INT ';'; ExtendMessage: 'extend' message=MessageReference '{' @@ -140,15 +140,19 @@ '}'(';')?; Service: - 'service' name=ID '{' + 'service' name=Name '{' rpcs+=Rpc* '}'; Rpc: - 'rpc' name=ID '(' argType=MessageReference ')' 'returns' '(' returnType=MessageReference ')' + 'rpc' name=Name '(' argType=MessageReference ')' 'returns' '(' returnType=MessageReference ')' (('{' options+=Option* '}')(';')? | ';') ; +Name: + ID | 'package' | 'import' | 'option' | 'extend' | 'message' | 'optional' | 'required' | 'repeated' | 'group' | 'enum' + | 'service' | 'rpc' | 'returns' | 'true' | 'false' | 'default' | 'extensions' | 'to' | 'max'; + MessageReference: type=[Message | QualifiedName];