Support multiline Setext headers
diff --git a/pkgs/markdown/lib/src/block_parser.dart b/pkgs/markdown/lib/src/block_parser.dart
index a809947..1211b81 100644
--- a/pkgs/markdown/lib/src/block_parser.dart
+++ b/pkgs/markdown/lib/src/block_parser.dart
@@ -12,7 +12,7 @@
 final _emptyPattern = new RegExp(r'^(?:[ \t]*)$');
 
 /// A series of `=` or `-` (on the next line) define setext-style headers.
-final _setextPattern = new RegExp(r'^(=+|-+)$');
+final _setextPattern = new RegExp(r'^[ ]{0,3}(=+|-+)\s*$');
 
 /// Leading (and trailing) `#` define atx-style headers.
 ///
@@ -221,28 +221,56 @@
   const SetextHeaderSyntax();
 
   bool canParse(BlockParser parser) {
-    // Note: matches *next* line, not the current one. We're looking for the
-    // underlining after this line.
-    return parser.matchesNext(_setextPattern) &&
-        // The current line must look like a paragraph.
-        !(parser.matches(_codePattern) ||
-            parser.matches(_headerPattern) ||
-            parser.matches(_blockquotePattern) ||
-            parser.matches(_hrPattern) ||
-            parser.matches(_ulPattern) ||
-            parser.matches(_olPattern));
+    if (!_interperableAsParagraph(parser.current)) return false;
+    int i = 1;
+    while (true) {
+      var nextLine = parser.peek(i);
+      if (nextLine == null) {
+        // We never reached an underline.
+        return false;
+      }
+      if (_setextPattern.hasMatch(nextLine)) {
+        return true;
+      }
+      // Ensure that we're still in something like paragraph text.
+      if (!_interperableAsParagraph(nextLine)) {
+        return false;
+      }
+      i++;
+    }
   }
 
   Node parse(BlockParser parser) {
-    var match = _setextPattern.firstMatch(parser.next);
+    var lines = <String>[];
+    var tag;
+    while (!parser.isDone) {
+      var match = _setextPattern.firstMatch(parser.current);
+      if (match == null) {
+        // More text.
+        lines.add(parser.current);
+        parser.advance();
+        continue;
+      } else {
+        // The underline.
+        tag = (match[1][0] == '=') ? 'h1' : 'h2';
+        parser.advance();
+        break;
+      }
+    }
 
-    var tag = (match[1][0] == '=') ? 'h1' : 'h2';
-    var contents = new UnparsedContent(parser.current);
-    parser.advance();
-    parser.advance();
+    var contents = new UnparsedContent(lines.join('\n'));
 
     return new Element(tag, [contents]);
   }
+
+  bool _interperableAsParagraph(line) => !(_indentPattern.hasMatch(line) ||
+      _codePattern.hasMatch(line) ||
+      _headerPattern.hasMatch(line) ||
+      _blockquotePattern.hasMatch(line) ||
+      _hrPattern.hasMatch(line) ||
+      _ulPattern.hasMatch(line) ||
+      _olPattern.hasMatch(line) ||
+      _emptyPattern.hasMatch(line));
 }
 
 /// Parses setext-style headers, and adds generated IDs to the generated
diff --git a/pkgs/markdown/test/original/paragraphs.unit b/pkgs/markdown/test/original/paragraphs.unit
index b4bb334..cd9181d 100644
--- a/pkgs/markdown/test/original/paragraphs.unit
+++ b/pkgs/markdown/test/original/paragraphs.unit
@@ -12,14 +12,6 @@
 <<<
 <p>para</p>
 <h1>header</h1>
->>> are terminated by a setext header
-para
-header
-==
-
-<<<
-<p>para</p>
-<h1>header</h1>
 >>> are terminated by a hr
 para
 ___
diff --git a/pkgs/markdown/test/original/setext_headers.unit b/pkgs/markdown/test/original/setext_headers.unit
index 7e34d9d..7760d45 100644
--- a/pkgs/markdown/test/original/setext_headers.unit
+++ b/pkgs/markdown/test/original/setext_headers.unit
@@ -20,3 +20,11 @@
 
 <<<
 <ul><li></li></ul>
+>>> can be multiline
+header
+on two lines
+==
+
+<<<
+<h1>header
+on two lines</h1>
diff --git a/pkgs/markdown/tool/common_mark_stats.json b/pkgs/markdown/tool/common_mark_stats.json
index 9bf5b30..44ba651 100644
--- a/pkgs/markdown/tool/common_mark_stats.json
+++ b/pkgs/markdown/tool/common_mark_stats.json
@@ -370,7 +370,7 @@
   "81": "strict",
   "82": "loose",
   "83": "strict",
-  "84": "fail",
+  "84": "strict",
   "85": "strict",
   "86": "loose",
   "87": "strict"
@@ -600,11 +600,11 @@
  },
  "Setext headings": {
   "50": "strict",
-  "51": "fail",
+  "51": "strict",
   "52": "strict",
-  "53": "fail",
+  "53": "loose",
   "54": "strict",
-  "55": "fail",
+  "55": "strict",
   "56": "loose",
   "57": "strict",
   "58": "loose",
@@ -613,12 +613,12 @@
   "61": "loose",
   "62": "fail",
   "63": "loose",
-  "64": "fail",
+  "64": "strict",
   "65": "strict",
   "66": "strict",
   "67": "strict",
   "68": "loose",
-  "69": "fail",
+  "69": "strict",
   "70": "loose",
   "71": "loose",
   "72": "strict",
diff --git a/pkgs/markdown/tool/common_mark_stats.txt b/pkgs/markdown/tool/common_mark_stats.txt
index 14d9d68..f18d195 100644
--- a/pkgs/markdown/tool/common_mark_stats.txt
+++ b/pkgs/markdown/tool/common_mark_stats.txt
@@ -10,7 +10,7 @@
   15 of   15 – 100.0%  Hard line breaks
   42 of   42 – 100.0%  HTML blocks
   21 of   22 –  95.5%  Images
-  10 of   12 –  83.3%  Indented code blocks
+  11 of   12 –  91.7%  Indented code blocks
    1 of    1 – 100.0%  Inlines
   20 of   23 –  87.0%  Link reference definitions
   53 of   81 –  65.4%  Links
@@ -19,9 +19,9 @@
    8 of    8 – 100.0%  Paragraphs
    1 of    1 – 100.0%  Precedence
   15 of   21 –  71.4%  Raw HTML
-  20 of   26 –  76.9%  Setext headings
+  25 of   26 –  96.2%  Setext headings
    2 of    2 – 100.0%  Soft line breaks
    6 of   11 –  54.5%  Tabs
    3 of    3 – 100.0%  Textual content
   17 of   19 –  89.5%  Thematic breaks
- 484 of  618 –  78.3%  TOTAL
+ 490 of  618 –  79.3%  TOTAL