Optimise DelimiterSyntax (dart-lang/markdown#492)
* Optimise DelimiterSyntax
* Indention!
* Update stats
* update stats
* better naming
Co-authored-by: Kevin Moore <kevmoo@google.com>
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/delimiter_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/delimiter_syntax.dart
index 712883f..5a7437a 100644
--- a/pkgs/markdown/lib/src/inline_syntaxes/delimiter_syntax.dart
+++ b/pkgs/markdown/lib/src/inline_syntaxes/delimiter_syntax.dart
@@ -4,6 +4,7 @@
import '../ast.dart';
import '../inline_parser.dart';
+import '../patterns.dart';
import 'inline_syntax.dart';
/// Matches syntax that has a pair of tags and becomes an element, like `*` for
@@ -185,7 +186,7 @@
/// also be used by other extensions of [DelimiterSyntax].
class DelimiterRun implements Delimiter {
/// According to
- /// [CommonMark](https://spec.commonmark.org/0.29/#punctuation-character):
+ /// [CommonMark](https://spec.commonmark.org/0.30/#unicode-punctuation-character):
///
/// > A punctuation character is an ASCII punctuation character or anything in
/// > the general Unicode categories `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po`, or
@@ -193,8 +194,8 @@
// This RegExp is inspired by
// https://github.com/commonmark/commonmark.js/blob/1f7d09099c20d7861a674674a5a88733f55ff729/lib/inlines.js#L39.
// I don't know if there is any way to simplify it or maintain it.
- static final RegExp punctuation = RegExp('['
- r'''!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~'''
+ static final unicodePunctuationPattern = RegExp('['
+ '$asciiPunctuationEscaped'
r'\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE'
r'\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E'
r'\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E'
@@ -216,8 +217,12 @@
r'\uFF5B\uFF5D\uFF5F-\uFF65'
']');
- // TODO(srawlins): Unicode whitespace
- static const whitespace = ' \t\r\n';
+ /// Unicode whitespace.
+ // See https://spec.commonmark.org/0.30/#unicode-whitespace-character.
+ // Unicode Zs: https://www.compart.com/en/unicode/category.
+ static const unicodeWhitespace = '\u0020\u0009\u000A\u000C\u000D'
+ '\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008'
+ '\u2009\u200A\u202F\u205F\u3000';
@override
Text node;
@@ -271,50 +276,46 @@
required Text node,
bool allowIntraWord = false,
}) {
- bool leftFlanking,
- rightFlanking,
- precededByPunctuation,
- followedByPunctuation;
- String preceding, following;
+ bool precededByWhitespace;
+ bool followedByWhitespace;
+ bool precededByPunctuation;
+ bool followedByPunctuation;
+
if (runStart == 0) {
- rightFlanking = false;
- preceding = '\n';
+ precededByWhitespace = true;
+ precededByPunctuation = false;
} else {
- preceding = parser.source.substring(runStart - 1, runStart);
+ final preceding = parser.source.substring(runStart - 1, runStart);
+ precededByWhitespace = unicodeWhitespace.contains(preceding);
+ precededByPunctuation = !precededByWhitespace &&
+ unicodePunctuationPattern.hasMatch(preceding);
}
- precededByPunctuation = punctuation.hasMatch(preceding);
if (runEnd == parser.source.length) {
- leftFlanking = false;
- following = '\n';
+ followedByWhitespace = true;
+ followedByPunctuation = false;
} else {
- following = parser.source.substring(runEnd, runEnd + 1);
- }
- followedByPunctuation = punctuation.hasMatch(following);
-
- // http://spec.commonmark.org/0.30/#left-flanking-delimiter-run
- if (whitespace.contains(following)) {
- leftFlanking = false;
- } else {
- leftFlanking = !followedByPunctuation ||
- whitespace.contains(preceding) ||
- precededByPunctuation;
+ final following = parser.source.substring(runEnd, runEnd + 1);
+ followedByWhitespace = unicodeWhitespace.contains(following);
+ followedByPunctuation = !followedByWhitespace &&
+ unicodePunctuationPattern.hasMatch(following);
}
- // http://spec.commonmark.org/0.30/#right-flanking-delimiter-run
- if (whitespace.contains(preceding)) {
- rightFlanking = false;
- } else {
- rightFlanking = !precededByPunctuation ||
- whitespace.contains(following) ||
- followedByPunctuation;
- }
+ // If it is a left-flanking delimiter run, see
+ // http://spec.commonmark.org/0.30/#left-flanking-delimiter-run.
+ final isLeftFlanking = !followedByWhitespace &&
+ (!followedByPunctuation ||
+ precededByWhitespace ||
+ precededByPunctuation);
- if (!leftFlanking && !rightFlanking) {
- // Could not parse a delimiter run.
- return null;
- }
+ // If it is a right-flanking delimiter run, see
+ // http://spec.commonmark.org/0.30/#right-flanking-delimiter-run.
+ final isRightFlanking = !precededByWhitespace &&
+ (!precededByPunctuation ||
+ followedByWhitespace ||
+ followedByPunctuation);
+ // Make sure the shorter delimiter takes precedence.
tags.sort((a, b) => a.indicatorLength.compareTo(b.indicatorLength));
return DelimiterRun._(
@@ -322,8 +323,8 @@
char: parser.charAt(runStart),
syntax: syntax,
tags: tags,
- isLeftFlanking: leftFlanking,
- isRightFlanking: rightFlanking,
+ isLeftFlanking: isLeftFlanking,
+ isRightFlanking: isRightFlanking,
isPrecededByPunctuation: precededByPunctuation,
isFollowedByPunctuation: followedByPunctuation,
allowIntraWord: allowIntraWord,
diff --git a/pkgs/markdown/test/common_mark/emphasis_and_strong_emphasis.unit b/pkgs/markdown/test/common_mark/emphasis_and_strong_emphasis.unit
index 514b651..b342fc3 100644
--- a/pkgs/markdown/test/common_mark/emphasis_and_strong_emphasis.unit
+++ b/pkgs/markdown/test/common_mark/emphasis_and_strong_emphasis.unit
@@ -13,7 +13,7 @@
>>> Emphasis and strong emphasis - 353
* a *
<<<
-<p><em> a </em></p>
+<p>* a *</p>
>>> Emphasis and strong emphasis - 354
foo*bar*
<<<
diff --git a/pkgs/markdown/test/gfm/emphasis_and_strong_emphasis.unit b/pkgs/markdown/test/gfm/emphasis_and_strong_emphasis.unit
index 3cde638..b6e8155 100644
--- a/pkgs/markdown/test/gfm/emphasis_and_strong_emphasis.unit
+++ b/pkgs/markdown/test/gfm/emphasis_and_strong_emphasis.unit
@@ -13,7 +13,7 @@
>>> Emphasis and strong emphasis - 363
* a *
<<<
-<p><em> a </em></p>
+<p>* a *</p>
>>> Emphasis and strong emphasis - 364
foo*bar*
<<<
diff --git a/pkgs/markdown/tool/common_mark_stats.json b/pkgs/markdown/tool/common_mark_stats.json
index a073b64..8ff5f7c 100644
--- a/pkgs/markdown/tool/common_mark_stats.json
+++ b/pkgs/markdown/tool/common_mark_stats.json
@@ -113,7 +113,7 @@
"350": "strict",
"351": "strict",
"352": "strict",
- "353": "fail",
+ "353": "strict",
"354": "strict",
"355": "strict",
"356": "strict",
diff --git a/pkgs/markdown/tool/common_mark_stats.txt b/pkgs/markdown/tool/common_mark_stats.txt
index 5935a21..f5fbe3b 100644
--- a/pkgs/markdown/tool/common_mark_stats.txt
+++ b/pkgs/markdown/tool/common_mark_stats.txt
@@ -4,7 +4,7 @@
1 of 1 – 100.0% Blank lines
25 of 25 – 100.0% Block quotes
22 of 22 – 100.0% Code spans
- 130 of 131 – 99.2% Emphasis and strong emphasis
+ 131 of 131 – 100.0% Emphasis and strong emphasis
17 of 17 – 100.0% Entity and numeric character references
29 of 29 – 100.0% Fenced code blocks
15 of 15 – 100.0% Hard line breaks
@@ -24,5 +24,5 @@
11 of 11 – 100.0% Tabs
3 of 3 – 100.0% Textual content
19 of 19 – 100.0% Thematic breaks
- 636 of 652 – 97.5% TOTAL
- 617 of 636 – 97.0% TOTAL Strict
+ 637 of 652 – 97.7% TOTAL
+ 618 of 637 – 97.0% TOTAL Strict
diff --git a/pkgs/markdown/tool/gfm_stats.json b/pkgs/markdown/tool/gfm_stats.json
index f426ab8..820d869 100644
--- a/pkgs/markdown/tool/gfm_stats.json
+++ b/pkgs/markdown/tool/gfm_stats.json
@@ -129,7 +129,7 @@
"360": "strict",
"361": "strict",
"362": "strict",
- "363": "fail",
+ "363": "strict",
"364": "strict",
"365": "strict",
"366": "strict",
diff --git a/pkgs/markdown/tool/gfm_stats.txt b/pkgs/markdown/tool/gfm_stats.txt
index b460faa..dbeadd0 100644
--- a/pkgs/markdown/tool/gfm_stats.txt
+++ b/pkgs/markdown/tool/gfm_stats.txt
@@ -6,7 +6,7 @@
25 of 25 – 100.0% Block quotes
22 of 22 – 100.0% Code spans
0 of 1 – 0.0% Disallowed Raw HTML (extension)
- 130 of 131 – 99.2% Emphasis and strong emphasis
+ 131 of 131 – 100.0% Emphasis and strong emphasis
17 of 17 – 100.0% Entity and numeric character references
29 of 29 – 100.0% Fenced code blocks
15 of 15 – 100.0% Hard line breaks
@@ -28,5 +28,5 @@
11 of 11 – 100.0% Tabs
3 of 3 – 100.0% Textual content
19 of 19 – 100.0% Thematic breaks
- 654 of 671 – 97.5% TOTAL
- 634 of 654 – 96.9% TOTAL Strict
+ 655 of 671 – 97.6% TOTAL
+ 635 of 655 – 96.9% TOTAL Strict