Refactor CodeBlockSyntax (dart-lang/markdown#488)
* Refactor CodeBlockSyntax
* Update stats
* Fix some requests
diff --git a/pkgs/markdown/lib/src/block_syntaxes/code_block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/code_block_syntax.dart
index f37baed..326e0b2 100644
--- a/pkgs/markdown/lib/src/block_syntaxes/code_block_syntax.dart
+++ b/pkgs/markdown/lib/src/block_syntaxes/code_block_syntax.dart
@@ -23,25 +23,21 @@
final childLines = <String?>[];
while (!parser.isDone) {
- final match = pattern.firstMatch(parser.current);
- if (match != null) {
- childLines.add(match[1]);
- parser.advance();
- } else {
- // If there's a codeblock, then a newline, then a codeblock, keep the
- // code blocks together.
- final nextMatch =
- parser.next != null ? pattern.firstMatch(parser.next!) : null;
- if (parser.current.trim() == '' && nextMatch != null) {
- childLines.add('');
- childLines.add(nextMatch[1]);
- parser.advance();
- parser.advance();
- } else {
- break;
- }
+ final isBlankLine = parser.current.isBlank;
+ if (isBlankLine && _shouldEnd(parser)) {
+ break;
}
+
+ if (!isBlankLine &&
+ childLines.isNotEmpty &&
+ pattern.hasMatch(parser.current) != true) {
+ break;
+ }
+ childLines.add(parser.current.dedent().text);
+
+ parser.advance();
}
+
return childLines;
}
@@ -59,4 +55,24 @@
return Element('pre', [Element.text('code', content)]);
}
+
+ bool _shouldEnd(BlockParser parser) {
+ var i = 1;
+ while (true) {
+ final nextLine = parser.peek(i);
+ // EOF
+ if (nextLine == null) {
+ return true;
+ }
+
+ // It does not matter how many blank lines between chunks:
+ // https://spec.commonmark.org/0.30/#example-111
+ if (nextLine.isBlank) {
+ i++;
+ continue;
+ }
+
+ return pattern.hasMatch(nextLine) == false;
+ }
+ }
}
diff --git a/pkgs/markdown/lib/src/util.dart b/pkgs/markdown/lib/src/util.dart
index 02e26ab..b482c1c 100644
--- a/pkgs/markdown/lib/src/util.dart
+++ b/pkgs/markdown/lib/src/util.dart
@@ -131,3 +131,57 @@
return buffer.toString();
}
+
+extension StringExtensions on String {
+ /// Removes up to [length] characters of leading whitespace.
+ // The way of handling tabs: https://spec.commonmark.org/0.30/#tabs
+ DedentedText dedent([int length = 4]) {
+ final whitespaceMatch = RegExp('^[ \t]{0,$length}').firstMatch(this);
+ const tabSize = 4;
+
+ int? tabRemaining;
+ var start = 0;
+ final whitespaces = whitespaceMatch?[0];
+ if (whitespaces != null) {
+ var indentLength = 0;
+ for (start; start < whitespaces.length; start++) {
+ final isTab = whitespaces[start] == '\t';
+ if (isTab) {
+ indentLength += tabSize;
+ tabRemaining = 4;
+ } else {
+ indentLength += 1;
+ }
+ if (indentLength >= length) {
+ if (tabRemaining != null) {
+ tabRemaining = indentLength - length;
+ }
+ if (indentLength == length || isTab) {
+ start += 1;
+ }
+ break;
+ }
+ if (tabRemaining != null) {
+ tabRemaining = 0;
+ }
+ }
+ }
+ return DedentedText(substring(start), tabRemaining);
+ }
+
+ /// Whether this string contains only whitespaces.
+ bool get isBlank => trim().isEmpty;
+}
+
+/// A class that describes a dedented text.
+class DedentedText {
+ /// The dedented text.
+ final String text;
+
+ /// How many spaces of a tab that remains after part of it has been consumed.
+ ///
+ /// `null` means we did not read a `tab`.
+ final int? tabRemaining;
+
+ DedentedText(this.text, this.tabRemaining);
+}
diff --git a/pkgs/markdown/test/common_mark/indented_code_blocks.unit b/pkgs/markdown/test/common_mark/indented_code_blocks.unit
index 66404a8..ce142fe 100644
--- a/pkgs/markdown/test/common_mark/indented_code_blocks.unit
+++ b/pkgs/markdown/test/common_mark/indented_code_blocks.unit
@@ -52,8 +52,10 @@
<pre><code>chunk1
chunk2
-</code></pre>
-<pre><code>chunk3
+
+
+
+chunk3
</code></pre>
>>> Indented code blocks - 112
chunk1
@@ -108,7 +110,6 @@
<<<
<pre><code>foo
-
</code></pre>
>>> Indented code blocks - 118
foo
diff --git a/pkgs/markdown/test/gfm/indented_code_blocks.unit b/pkgs/markdown/test/gfm/indented_code_blocks.unit
index 0dffa1d..68fc6d1 100644
--- a/pkgs/markdown/test/gfm/indented_code_blocks.unit
+++ b/pkgs/markdown/test/gfm/indented_code_blocks.unit
@@ -52,8 +52,10 @@
<pre><code>chunk1
chunk2
-</code></pre>
-<pre><code>chunk3
+
+
+
+chunk3
</code></pre>
>>> Indented code blocks - 82
chunk1
@@ -108,7 +110,6 @@
<<<
<pre><code>foo
-
</code></pre>
>>> Indented code blocks - 88
foo
diff --git a/pkgs/markdown/test/original/code_blocks.unit b/pkgs/markdown/test/original/code_blocks.unit
index b219fe7..02e6746 100644
--- a/pkgs/markdown/test/original/code_blocks.unit
+++ b/pkgs/markdown/test/original/code_blocks.unit
@@ -45,10 +45,12 @@
<<<
<pre><code>zero
one
-</code></pre>
-<pre><code>two
-</code></pre>
-<pre><code>three
+
+
+two
+
+
+three
</code></pre>
>>> escape HTML characters
<&>
diff --git a/pkgs/markdown/tool/common_mark_stats.json b/pkgs/markdown/tool/common_mark_stats.json
index daaa718..8368b9a 100644
--- a/pkgs/markdown/tool/common_mark_stats.json
+++ b/pkgs/markdown/tool/common_mark_stats.json
@@ -384,13 +384,13 @@
"108": "strict",
"109": "strict",
"110": "strict",
- "111": "fail",
+ "111": "strict",
"112": "strict",
"113": "strict",
"114": "strict",
"115": "strict",
"116": "strict",
- "117": "loose",
+ "117": "strict",
"118": "strict"
},
"Inlines": {
diff --git a/pkgs/markdown/tool/common_mark_stats.txt b/pkgs/markdown/tool/common_mark_stats.txt
index 337d16f..910b446 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
44 of 44 – 100.0% HTML blocks
21 of 22 – 95.5% Images
- 11 of 12 – 91.7% Indented code blocks
+ 12 of 12 – 100.0% Indented code blocks
1 of 1 – 100.0% Inlines
21 of 27 – 77.8% Link reference definitions
89 of 90 – 98.9% Links
@@ -24,5 +24,5 @@
11 of 11 – 100.0% Tabs
3 of 3 – 100.0% Textual content
19 of 19 – 100.0% Thematic breaks
- 634 of 652 – 97.2% TOTAL
- 614 of 634 – 96.8% TOTAL Strict
+ 635 of 652 – 97.4% TOTAL
+ 616 of 635 – 97.0% TOTAL Strict
diff --git a/pkgs/markdown/tool/gfm_stats.json b/pkgs/markdown/tool/gfm_stats.json
index 91de967..a431a10 100644
--- a/pkgs/markdown/tool/gfm_stats.json
+++ b/pkgs/markdown/tool/gfm_stats.json
@@ -399,13 +399,13 @@
"78": "strict",
"79": "strict",
"80": "strict",
- "81": "fail",
+ "81": "strict",
"82": "strict",
"83": "strict",
"84": "strict",
"85": "strict",
"86": "strict",
- "87": "loose",
+ "87": "strict",
"88": "strict"
},
"Inlines": {
diff --git a/pkgs/markdown/tool/gfm_stats.txt b/pkgs/markdown/tool/gfm_stats.txt
index b7598f9..0a103e9 100644
--- a/pkgs/markdown/tool/gfm_stats.txt
+++ b/pkgs/markdown/tool/gfm_stats.txt
@@ -12,7 +12,7 @@
15 of 15 – 100.0% Hard line breaks
43 of 43 – 100.0% HTML blocks
21 of 22 – 95.5% Images
- 11 of 12 – 91.7% Indented code blocks
+ 12 of 12 – 100.0% Indented code blocks
1 of 1 – 100.0% Inlines
22 of 28 – 78.6% Link reference definitions
86 of 87 – 98.9% Links
@@ -28,5 +28,5 @@
11 of 11 – 100.0% Tabs
3 of 3 – 100.0% Textual content
19 of 19 – 100.0% Thematic breaks
- 652 of 671 – 97.2% TOTAL
- 631 of 652 – 96.8% TOTAL Strict
+ 653 of 671 – 97.3% TOTAL
+ 633 of 653 – 96.9% TOTAL Strict