Fix auto-formatting of bullet lists

Previously we were bulleting the first line in a paragraph, even if
it did not have a bullet marker.  E.g. if the user entered:

  To see this bug, you have to:
  * Be on IMAP or EAS (not on POP)

the first line was treated as though it had been "* To see this bug".
This was not what the author intended in this example.

We now make an exception for the first line(s) in the list paragraph,
rendering them in their own <p> tag isolated from the list elements.

Bug: gerrit issue 293
Change-Id: I7131bb845d2eeb9e208300ba9a09ec6c805b8df8
Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java b/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java
index 4be11de..d20cda6 100644
--- a/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java
+++ b/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java
@@ -105,34 +105,64 @@
         for (final String line : p.split("\n")) {
           r.openSpan();
           r.setStyleName("gwtexpui-SafeHtml-WikiPreFormat");
-          r.append(new SafeHtmlString(line));
+          r.append(asis(line));
           r.closeSpan();
           r.br();
         }
         r.closeElement("p");
 
       } else if (isList(p)) {
-        r.openElement("ul");
-        r.setStyleName("gwtexpui-SafeHtml-WikiList");
-        for (String line : p.split("\n")) {
-          if (line.startsWith("-") || line.startsWith("*")) {
-            line = line.substring(1).trim();
-          }
-          r.openElement("li");
-          r.append(new SafeHtmlString(line));
-          r.closeElement("li");
-        }
-        r.closeElement("ul");
+        wikifyList(r, p);
 
       } else {
         r.openElement("p");
-        r.append(new SafeHtmlString(p));
+        r.append(asis(p));
         r.closeElement("p");
       }
     }
     return r.toSafeHtml();
   }
 
+  private void wikifyList(final SafeHtmlBuilder r, final String p) {
+    boolean in_ul = false;
+    boolean in_p = false;
+    for (String line : p.split("\n")) {
+      if (line.startsWith("-") || line.startsWith("*")) {
+        if (!in_ul) {
+          if (in_p) {
+            in_p = false;
+            r.closeElement("p");
+          }
+
+          in_ul = true;
+          r.openElement("ul");
+          r.setStyleName("gwtexpui-SafeHtml-WikiList");
+        }
+        line = line.substring(1).trim();
+
+      } else if (!in_ul) {
+        if (!in_p) {
+          in_p = true;
+          r.openElement("p");
+        } else {
+          r.append(' ');
+        }
+        r.append(asis(line));
+        continue;
+      }
+
+      r.openElement("li");
+      r.append(asis(line));
+      r.closeElement("li");
+    }
+
+    if (in_ul) {
+      r.closeElement("ul");
+    } else if (in_p) {
+      r.closeElement("p");
+    }
+  }
+
   private static boolean isPreFormat(final String p) {
     return p.contains("\n ") || p.contains("\n\t") || p.startsWith(" ")
         || p.startsWith("\t");
diff --git a/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyListTest.java b/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyListTest.java
index c3a0871..672a63b 100644
--- a/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyListTest.java
+++ b/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyListTest.java
@@ -61,6 +61,35 @@
     , n.asString());
   }
 
+  public void testBulletList4() {
+    final SafeHtml o = html("To see this bug, you have to:\n" //
+        + "* Be on IMAP or EAS (not on POP)\n"//
+        + "* Be very unlucky\n");
+    final SafeHtml n = o.wikify();
+    assertNotSame(o, n);
+    assertEquals("<p>To see this bug, you have to:</p>" //
+        + BEGIN_LIST //
+        + item("Be on IMAP or EAS (not on POP)") //
+        + item("Be very unlucky") //
+        + END_LIST //
+    , n.asString());
+  }
+
+  public void testBulletList5() {
+    final SafeHtml o = html("To see this bug,\n" //
+        + "you have to:\n" //
+        + "* Be on IMAP or EAS (not on POP)\n"//
+        + "* Be very unlucky\n");
+    final SafeHtml n = o.wikify();
+    assertNotSame(o, n);
+    assertEquals("<p>To see this bug, you have to:</p>" //
+        + BEGIN_LIST //
+        + item("Be on IMAP or EAS (not on POP)") //
+        + item("Be very unlucky") //
+        + END_LIST //
+    , n.asString());
+  }
+
   public void testDashList1() {
     final SafeHtml o = html("A\n\n- line 1\n- 2nd line");
     final SafeHtml n = o.wikify();