Fixed: [Issue 4] Make auto-complete of '[packed = true]' available only to primitive types
https://code.google.com/p/protobuf-dt/issues/detail?id=4

Both "smart semicolon" command and content assist now check that the property is repeated *and* primitive before inserting or proposing 'packed=true'.

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
index 2ccb99f..6912347 100644
--- 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
@@ -20,9 +20,12 @@
 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.eclipse.protobuf.protobuf.Literal;
+import com.google.eclipse.protobuf.protobuf.Property;
+import com.google.eclipse.protobuf.ui.grammar.CompoundElements;
+import com.google.eclipse.protobuf.ui.grammar.Keywords;
+import com.google.eclipse.protobuf.ui.util.Literals;
+import com.google.eclipse.protobuf.ui.util.Properties;
 import com.google.inject.Inject;
 
 /**
@@ -101,21 +104,36 @@
 
   private String contentToInsert(String line, Property property) {
     boolean hasIndexAlready = PROPERTY_WITH_INDEX.matcher(line).matches();
-    if (hasIndexAlready) return semicolon;
+    if (hasIndexAlready) {
+      // we can still insert '[packed = true]' if necessary
+      if (shouldInsertPackedOption(property)) {
+        String content = compoundElements.packedInBrackets() + semicolon;
+        return addSpaceAtBeginning(line, content);
+      }
+      return semicolon;
+    }
     int index = properties.calculateIndexOf(property);
-    if (REPEATED.equals(property.getModifier())) {
+    if (shouldInsertPackedOption(property)) {
       String format = "= %d " + compoundElements.packedInBrackets() + "%s";
       return indexAndSemicolonToInsert(format, line, index);
     }
     return defaultIndexAndSemicolonToInsert(line, index);
   }
 
+  private boolean shouldInsertPackedOption(Property property) {
+    return REPEATED.equals(property.getModifier()) && properties.isPrimitiveProperty(property);
+  }
+
   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;
+    return addSpaceAtBeginning(line, content);
+  }
+
+  private String addSpaceAtBeginning(String line, String contentToInsert) {
+    return (line.endsWith(" ")) ? contentToInsert : " " + contentToInsert;
   }
 }
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
index 253046f..2afcb2d 100644
--- 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
@@ -24,7 +24,8 @@
 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.grammar.CompoundElements;
+import com.google.eclipse.protobuf.ui.grammar.Keywords;
 import com.google.eclipse.protobuf.ui.labeling.Images;
 import com.google.eclipse.protobuf.ui.util.*;
 import com.google.eclipse.protobuf.util.EObjectFinder;
@@ -197,13 +198,16 @@
       }
       acceptor.accept(proposal);
     }
-    if (REPEATED.equals(modifier)) proposeAndAccept(compoundElements.packedInBrackets(), context, acceptor);
+    if (REPEATED.equals(modifier) && properties.isPrimitiveProperty(p))
+      proposeAndAccept(compoundElements.packedInBrackets(), context, acceptor);
     return true;
   }
 
   private void proposePackedOption(ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
-    Modifier modifier = extractModifierFromModel(context);
-    if (!REPEATED.equals(modifier)) return;
+    Property p = extractPropertyFrom(context);
+    if (p == null) return;
+    Modifier modifier = p.getModifier();
+    if (!REPEATED.equals(modifier) || !properties.isPrimitiveProperty(p)) return;
     proposeAndAccept(compoundElements.packed(), context, acceptor);
   }
 
@@ -225,11 +229,16 @@
   }
 
   private Modifier extractModifierFromModel(ContentAssistContext context) {
+    Property p = extractPropertyFrom(context);
+    return (p == null) ? null : p.getModifier();
+  }
+
+  private Property extractPropertyFrom(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();
+    return (Property) model;
   }
 
   private boolean isStringProperty(Property p) {
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
index 7030ca6..da6154f 100644
--- 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
@@ -12,9 +12,11 @@
 
 import java.util.List;
 
-import org.eclipse.xtext.*;
+import org.eclipse.xtext.IGrammarAccess;
+import org.eclipse.xtext.Keyword;
 
-import com.google.inject.*;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * @author alruiz@google.com (Alex Ruiz)
@@ -25,6 +27,7 @@
   private Keyword bool;
   private Keyword boolTrue;
   private Keyword boolFalse;
+  private Keyword bytes;
   private Keyword openingBracket;
   private Keyword closingBracket;
   private Keyword defaultValue;
@@ -39,6 +42,7 @@
       if (assignIfIsBool(k)) continue;
       if (assignIfIsBoolTrue(k)) continue;
       if (assignIfIsBoolFalse(k)) continue;
+      if (assignIfIsBytes(k)) continue;
       if (assignIfIsOpeningBracket(k)) continue;
       if (assignIfIsClosingBracket(k)) continue;
       if (assignIfIsDefaultValue(k)) continue;
@@ -67,6 +71,12 @@
     return true;
   }
 
+  private boolean assignIfIsBytes(Keyword k) {
+    if (!isKeywordValue(k, "bytes")) return false;
+    bytes = k;
+    return true;
+  }
+
   private boolean assignIfIsOpeningBracket(Keyword k) {
     if (!isKeywordValue(k, "[")) return false;
     openingBracket = k;
@@ -125,6 +135,10 @@
     return boolFalse;
   }
 
+  public Keyword bytes() {
+    return bytes;
+  }
+
   public Keyword openingBracket() {
     return openingBracket;
   }
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
index 7e2fadc..74d1b0b 100644
--- 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
@@ -27,6 +27,13 @@
 
   @Inject private Keywords keywords;
 
+  public boolean isPrimitiveProperty(Property p) {
+    AbstractTypeReference r = p.getType();
+    if (!(r instanceof ScalarTypeReference)) return false;
+    String typeName = ((ScalarTypeReference) r).getScalar().getName();
+    return !keywords.string().getValue().equals(typeName) && !keywords.bytes().getValue().equals(typeName);
+  }
+
   public boolean isStringProperty(Property p) {
     return keywords.string().getValue().equals(nameOfTypeIn(p));
   }