Switch to commonmark 0.5.0

Reasons to switch:

  * Supports the CommonMark[1] "standard"
  * Fewer dependencies
  * BSD 2-clause license
  * Fast (claims 10-20 times faster than pegdown)
  * Cleaner extension API than Pegdown
  * No timeout limit required

Testing with Documentation/markdown.md:

        | cold vm | hot vm |
        +---------+--------|
  prior |   2.29s | 279ms  |
   this |   1.64s | 139ms  |

Testing with Chromium's botmap.md:

        | cold vm | hot vm |
        +---------+--------|
  prior |   3.47s | 946ms  |
   this |   1.83s | 257ms  |

Changes in Markdown from Pegdown:

  * No <<double angle>> quotes (confused with HTML).
  * No table captions (no [caption after table]).
  * Table columns are same width (no multi-column spans).
  * Smart quotes can no longer be disabled by \'.
  * Horizontal rule should be at least 3 -, e.g. ---.
    (However GitHub Flavor -- is still accepted.)

[1] http://commonmark.org

Change-Id: Ief189d0226901a284d9b86d9798310786ae1e983
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownUtil.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownUtil.java
index 5130216..6392cd0 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownUtil.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownUtil.java
@@ -14,21 +14,17 @@
 
 package com.google.gitiles.doc;
 
+import com.google.common.base.CharMatcher;
 import com.google.common.base.Strings;
 
-import org.pegdown.ast.HeaderNode;
-import org.pegdown.ast.Node;
-import org.pegdown.ast.TextNode;
+import org.commonmark.node.Heading;
+import org.commonmark.node.Node;
+import org.commonmark.node.Text;
 
 class MarkdownUtil {
-  /** Check if anchor URL is like {@code /top.md}. */
-  static boolean isAbsolutePathToMarkdown(String url) {
-    return url.length() >= 5 && url.charAt(0) == '/' && url.charAt(1) != '/' && url.endsWith(".md");
-  }
-
   /** Combine child nodes as string; this must be escaped for HTML. */
   static String getInnerText(Node node) {
-    if (node == null || node.getChildren().isEmpty()) {
+    if (node == null || node.getFirstChild() == null) {
       return null;
     }
 
@@ -38,25 +34,25 @@
   }
 
   private static void appendTextFromChildren(StringBuilder b, Node node) {
-    for (Node child : node.getChildren()) {
-      if (child instanceof TextNode) {
-        b.append(((TextNode) child).getText());
+    for (Node c = node.getFirstChild(); c != null; c = c.getNext()) {
+      if (c instanceof Text) {
+        b.append(((Text) c).getLiteral());
       } else {
-        appendTextFromChildren(b, child);
+        appendTextFromChildren(b, c);
       }
     }
   }
 
   static String getTitle(Node node) {
-    if (node instanceof HeaderNode) {
-      if (((HeaderNode) node).getLevel() == 1) {
+    if (node instanceof Heading) {
+      if (((Heading) node).getLevel() == 1) {
         return getInnerText(node);
       }
       return null;
     }
 
-    for (Node child : node.getChildren()) {
-      String title = getTitle(child);
+    for (Node c = node.getFirstChild(); c != null; c = c.getNext()) {
+      String title = getTitle(c);
       if (title != null) {
         return title;
       }
@@ -64,5 +60,14 @@
     return null;
   }
 
+  static void trimPreviousWhitespace(Node node) {
+    Node prev = node.getPrevious();
+    if (prev instanceof Text) {
+      Text prevText = (Text) prev;
+      String s = prevText.getLiteral();
+      prevText.setLiteral(CharMatcher.whitespace().trimTrailingFrom(s));
+    }
+  }
+
   private MarkdownUtil() {}
 }