Implement "rule of three". Since 0.26, CommonMark specifies intraword '*' or '_' marks cannot close if sume of opening and closing mark chracters can be divided by three.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
diff --git a/md4c/md4c.c b/md4c/md4c.c
index b4bc70b..98f9aa1 100644
--- a/md4c/md4c.c
+++ b/md4c/md4c.c
@@ -807,7 +807,8 @@ struct MD_MARK_tag {
/* Mark flags. */
#define MD_MARK_POTENTIAL_OPENER 0x01 /* Maybe opener. */
#define MD_MARK_POTENTIAL_CLOSER 0x02 /* Maybe closer. */
-#define MD_MARK_AUTOLINK 0x04 /* Distinguisher for '<', '>'. */
+#define MD_MARK_INTRAWORD 0x04 /* Helper for emphasis (the rule of 3). */
+#define MD_MARK_AUTOLINK 0x08 /* Distinguisher for '<', '>'. */
#define MD_MARK_RESOLVED 0x10 /* Yes, the special meaning is indeed recognized. */
#define MD_MARK_OPENER 0x20 /* This opens a span. */
#define MD_MARK_CLOSER 0x40 /* This closes a span. */
@@ -1062,6 +1063,8 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
flags |= MD_MARK_POTENTIAL_CLOSER;
if(right_level > 0 && right_level >= left_level)
flags |= MD_MARK_POTENTIAL_OPENER;
+ if(left_level == 2 && right_level == 2)
+ flags |= MD_MARK_INTRAWORD;
if(flags != 0) {
PUSH_MARK(ch, off, tmp, flags);
@@ -1323,7 +1326,8 @@ md_analyze_entity(MD_CTX* ctx, int mark_index)
}
static void
-md_analyze_simple_pairing_mark(MD_CTX* ctx, MD_MARKCHAIN* chain, int mark_index)
+md_analyze_simple_pairing_mark(MD_CTX* ctx, MD_MARKCHAIN* chain, int mark_index,
+ int apply_rule_of_three)
{
MD_MARK* mark = &ctx->marks[mark_index];
@@ -1334,6 +1338,17 @@ md_analyze_simple_pairing_mark(MD_CTX* ctx, MD_MARKCHAIN* chain, int mark_index)
SZ opener_size = opener->end - opener->beg;
SZ closer_size = mark->end - mark->beg;
+ if(apply_rule_of_three && (mark->flags & MD_MARK_INTRAWORD)) {
+ while((opener_size + closer_size) % 3 == 0) {
+ if(opener->prev < 0)
+ goto cannot_resolve;
+
+ opener = &ctx->marks[opener->prev];
+ opener_size = opener->end - opener->beg;
+ closer_size = mark->end - mark->beg;
+ }
+ }
+
if(opener_size > closer_size) {
opener_index = md_split_mark(ctx, opener_index, closer_size);
md_mark_chain_append(ctx, chain, opener_index);
@@ -1346,6 +1361,7 @@ md_analyze_simple_pairing_mark(MD_CTX* ctx, MD_MARKCHAIN* chain, int mark_index)
return;
}
+cannot_resolve:
/* If not resolved, and we can be an opener, remember the mark for
* the future. */
if(mark->flags & MD_MARK_POTENTIAL_OPENER)
@@ -1355,13 +1371,13 @@ md_analyze_simple_pairing_mark(MD_CTX* ctx, MD_MARKCHAIN* chain, int mark_index)
static inline void
md_analyze_asterisk(MD_CTX* ctx, int mark_index)
{
- md_analyze_simple_pairing_mark(ctx, &ASTERISK_OPENERS, mark_index);
+ md_analyze_simple_pairing_mark(ctx, &ASTERISK_OPENERS, mark_index, 1);
}
static inline void
md_analyze_underscore(MD_CTX* ctx, int mark_index)
{
- md_analyze_simple_pairing_mark(ctx, &UNDERSCORE_OPENERS, mark_index);
+ md_analyze_simple_pairing_mark(ctx, &UNDERSCORE_OPENERS, mark_index, 1);
}
/* Table of precedence of various span types. */