Add support for some common useful expansions like wiki-style text

These expansions can be useful when showing user generated message
text, such as in a blog comment sort of situation.  URLs should be
anchors to make navigation easier, paragraph breaks should be kept
as paragraphs, and text that was indented is most likely some sort
of preformatted text that should be displayed as-is.

Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/src/main/java/com/google/gwtexpui/safehtml/SafeHtml.gwt.xml b/src/main/java/com/google/gwtexpui/safehtml/SafeHtml.gwt.xml
index 9a94484..6ffef93 100644
--- a/src/main/java/com/google/gwtexpui/safehtml/SafeHtml.gwt.xml
+++ b/src/main/java/com/google/gwtexpui/safehtml/SafeHtml.gwt.xml
@@ -15,4 +15,5 @@
 -->
 <module>
   <inherits name="com.google.gwt.user.User"/>
+  <stylesheet src="gwtexpui_safehtml1.cache.css" />
 </module>
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 37fdb46..311584a 100644
--- a/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java
+++ b/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java
@@ -16,7 +16,11 @@
 
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HTMLTable;
 import com.google.gwt.user.client.ui.HasHTML;
+import com.google.gwt.user.client.ui.InlineHTML;
+import com.google.gwt.user.client.ui.Widget;
 
 /** Immutable string safely placed as HTML without further escaping. */
 public abstract class SafeHtml {
@@ -32,11 +36,84 @@
     return e;
   }
 
+  /** Set the inner HTML of a table cell. */
+  public static <T extends HTMLTable> T set(final T t, final int row,
+      final int col, final SafeHtml str) {
+    t.setHTML(row, col, str.asString());
+    return t;
+  }
+
   /** Parse an HTML block and return the first (typically root) element. */
   public static Element parse(final SafeHtml str) {
     return DOM.getFirstChild(set(DOM.createDiv(), str));
   }
 
+  /** Convert bare http:// and https:// URLs into &lt;a href&gt; tags. */
+  public SafeHtml linkify() {
+    return replaceAll("(https?://[^ \n\r\t]*)", "<a href=\"$1\">$1</a>");
+  }
+
+  /**
+   * Apply {@link #linkify()}, and "\n\n" to &lt;p&gt;.
+   * <p>
+   * Lines that start with whitespace are assumed to be preformatted, and are
+   * formatted by the <code>gwtexpui-SafeHtml-WikiPreFormat</code> CSS class. By
+   * default this class is:
+   * 
+   * <pre>
+   *   white-space: pre;
+   *   font-family: monospace;
+   * </pre>
+   */
+  public SafeHtml wikify() {
+    SafeHtml s = linkify();
+    s = s.replaceAll("(^|\n)([ \t][^\n]*)", "$1<span class=\"gwtexpui-SafeHtml-WikiPreFormat\">$2</span><br />");
+    s = s.replaceAll("\n\n", "\n<p />\n");
+    return s;
+  }
+
+  /**
+   * Replace first occurrence of <code>regex</code> with <code>repl</code> .
+   * <p>
+   * <b>WARNING:</b> This replacement is being performed against an otherwise
+   * safe HTML string. The caller must ensure that the replacement does not
+   * introduce cross-site scripting attack entry points.
+   * 
+   * @param regex regular expression pattern to match the substring with.
+   * @param repl replacement expression. Capture groups within
+   *        <code>regex</code> can be referenced with <code>$<i>n</i></code>.
+   * @return a new string, after the replacement has been made.
+   */
+  public SafeHtml replaceFirst(final String regex, final String repl) {
+    return new SafeHtmlString(asString().replaceFirst(regex, repl));
+  }
+
+  /**
+   * Replace each occurrence of <code>regex</code> with <code>repl</code> .
+   * <p>
+   * <b>WARNING:</b> This replacement is being performed against an otherwise
+   * safe HTML string. The caller must ensure that the replacement does not
+   * introduce cross-site scripting attack entry points.
+   * 
+   * @param regex regular expression pattern to match substrings with.
+   * @param repl replacement expression. Capture groups within
+   *        <code>regex</code> can be referenced with <code>$<i>n</i></code>.
+   * @return a new string, after the replacements have been made.
+   */
+  public SafeHtml replaceAll(final String regex, final String repl) {
+    return new SafeHtmlString(asString().replaceAll(regex, repl));
+  }
+
+  /** @return a GWT block display widget displaying this HTML. */
+  public Widget toBlockWidget() {
+    return new HTML(asString());
+  }
+
+  /** @return a GWT inline display widget displaying this HTML. */
+  public Widget toInlineWidget() {
+    return new InlineHTML(asString());
+  }
+
   /** @return a clean HTML string safe for inclusion in any context. */
   public abstract String asString();
 }
diff --git a/src/main/java/com/google/gwtexpui/safehtml/public/gwtexpui_safehtml1.cache.css b/src/main/java/com/google/gwtexpui/safehtml/public/gwtexpui_safehtml1.cache.css
new file mode 100644
index 0000000..029e301
--- /dev/null
+++ b/src/main/java/com/google/gwtexpui/safehtml/public/gwtexpui_safehtml1.cache.css
@@ -0,0 +1,5 @@
+.gwtexpui-SafeHtml-WikiPreFormat {
+  white-space: pre;
+  font-family: monospace;
+  font-size: small;
+}