In progress: [Issue 104] Update "Next Id" comment when generating a the
tag number of a field or literal

Now it is possible to obtain the comment node whose text matches a
regular expression.
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/commands/CommentNodesFinder_matchingCommentNode_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/commands/CommentNodesFinder_matchingCommentNode_Test.java
new file mode 100644
index 0000000..faaf723
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/commands/CommentNodesFinder_matchingCommentNode_Test.java
@@ -0,0 +1,66 @@
+/*
+ * 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.junit.util.Finder.findProperty;
+import static com.google.eclipse.protobuf.junit.util.SystemProperties.lineSeparator;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.junit.Assert.assertThat;
+
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.eclipse.protobuf.protobuf.*;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.nodemodel.INode;
+import org.junit.*;
+
+import java.util.regex.Pattern;
+
+/**
+ * Tests for <code>{@link CommentNodesFinder#matchingCommentNode(EObject, Pattern...)}</code>.
+ * 
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class CommentNodesFinder_matchingCommentNode_Test {
+
+  @Rule public XtextRule xtext = new XtextRule();
+
+  private CommentNodesFinder finder;
+  
+  @Before public void setUp() {
+    finder = xtext.getInstanceOf(CommentNodesFinder.class);
+  }
+  
+  @Test public void should_return_matching_single_line_comment_of_element() {
+    StringBuilder proto = new StringBuilder();
+    proto.append("message Person {           ").append(lineSeparator())
+         .append("  // Indicates whether the person is active or not.").append(lineSeparator())
+         .append("  optional bool active = 1;").append(lineSeparator())
+         .append("}                          ");
+    Protobuf root = xtext.parse(proto);
+    Property active = findProperty("active", root);
+    INode node = finder.matchingCommentNode(active, Pattern.compile(".*"));
+    assertThat(node.getText().trim(), equalTo("// Indicates whether the person is active or not."));
+  }
+
+  @Test public void should_return_matching_multi_line_comment_of_element() {
+    StringBuilder proto = new StringBuilder();
+    proto.append("message Person {           ").append(lineSeparator())
+         .append("  /*").append(lineSeparator())
+         .append("   * Indicates whether the person is active or not.").append(lineSeparator())
+         .append("   */").append(lineSeparator())
+         .append("  optional bool active = 1;").append(lineSeparator())
+         .append("}                          ");
+    Protobuf root = xtext.parse(proto);
+    Property active = findProperty("active", root);
+    INode node = finder.matchingCommentNode(active, Pattern.compile(".*"));
+    assertThat(node, notNullValue());
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/commands/CommentNodesFinder.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/commands/CommentNodesFinder.java
new file mode 100644
index 0000000..475c344
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/commands/CommentNodesFinder.java
@@ -0,0 +1,49 @@
+/*
+ * 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.junit.util.SystemProperties.lineSeparator;
+import static org.eclipse.xtext.nodemodel.util.NodeModelUtils.getNode;
+import static org.eclipse.xtext.util.Strings.isEmpty;
+
+import com.google.eclipse.protobuf.util.ModelNodes;
+import com.google.inject.*;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.nodemodel.*;
+
+import java.util.regex.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@Singleton
+class CommentNodesFinder {
+
+  @Inject private ModelNodes nodes;
+
+  INode matchingCommentNode(EObject target, Pattern...patternsToMatch) {
+    ICompositeNode node = getNode(target);
+    for (INode currentNode : node.getAsTreeIterable()) {
+      if (currentNode instanceof ILeafNode && !((ILeafNode) currentNode).isHidden()) break;
+      if (currentNode instanceof ILeafNode && nodes.wasCreatedByAnyComment(currentNode)) {
+        String rawComment = ((ILeafNode) currentNode).getText();
+        if (isEmpty(rawComment)) continue;
+        String[] comment = rawComment.split(lineSeparator());
+        for (String line : comment) {
+          for (Pattern pattern : patternsToMatch) {
+            Matcher matcher = pattern.matcher(line);
+            if (matcher.matches()) return currentNode;
+          }
+        }
+      }
+    }
+    return null;
+  }
+}