Commit a08f6a05f157200f9d759c925407b4db877056f8

Martin Mitas 2024-01-18T12:29:31

Improve/fix latex math extension. To mitigate false positives: * We accept $ and $$ as a potential opener only if it's not preceded with alnum char. * Similarly closer cannot be followed with alnum char. * We now also match closer with last preceding pontential opener, not the first one. (And to avoid nesting, any previous openers are ignored.) * Also revert an unintended change in 3fc207affaba313cc1f4ef3b4e9e57df89b0e028 which allowed keeping nested resolved marks in it.

diff --git a/src/md4c.c b/src/md4c.c
index ca57f2d..b77df6c 100644
--- a/src/md4c.c
+++ b/src/md4c.c
@@ -3344,8 +3344,17 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
                 while(tmp < line_end && CH(tmp) == _T('$'))
                     tmp++;
 
-                if (tmp - off <= 2)
-                    PUSH_MARK(ch, off, tmp, MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER);
+                if(tmp - off <= 2) {
+                    unsigned flags = MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER;
+
+                    if(off > line_beg  &&  !ISUNICODEWHITESPACEBEFORE(off)  &&  !ISUNICODEPUNCTBEFORE(off))
+                        flags &= ~MD_MARK_POTENTIAL_OPENER;
+                    if(tmp < line_end  &&  !ISUNICODEWHITESPACE(tmp)  &&  !ISUNICODEPUNCT(tmp))
+                        flags &= ~MD_MARK_POTENTIAL_CLOSER;
+                    if(flags != 0)
+                        PUSH_MARK(ch, off, tmp, flags);
+                }
+
                 off = tmp;
                 continue;
             }
@@ -3854,21 +3863,30 @@ md_analyze_tilde(MD_CTX* ctx, int mark_index)
 static void
 md_analyze_dollar(MD_CTX* ctx, int mark_index)
 {
-    if(DOLLAR_OPENERS.head >= 0) {
+    MD_MARK* mark = &ctx->marks[mark_index];
+
+    if((mark->flags & MD_MARK_POTENTIAL_CLOSER)  &&  DOLLAR_OPENERS.tail >= 0) {
         /* If the potential closer has a non-matching number of $, discard */
-        MD_MARK* open = &ctx->marks[DOLLAR_OPENERS.tail];
-        MD_MARK* close = &ctx->marks[mark_index];
+        MD_MARK* opener = &ctx->marks[DOLLAR_OPENERS.tail];
         int opener_index = DOLLAR_OPENERS.tail;
+        MD_MARK* closer = mark;
+        int closer_index = mark_index;
 
-        if (open->end - open->beg == close->end - close->beg) {
+        if(opener->end - opener->beg == closer->end - closer->beg) {
             /* We are the matching closer */
-            md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING);
-            md_resolve_range(ctx, &DOLLAR_OPENERS, opener_index, mark_index);
+            md_rollback(ctx, opener_index, closer_index, MD_ROLLBACK_ALL);
+            md_resolve_range(ctx, &DOLLAR_OPENERS, opener_index, closer_index);
+
+            /* Discard all pending openers: Latex math span do not allow
+             * nesting. */
+            DOLLAR_OPENERS.head = -1;
+            DOLLAR_OPENERS.tail = -1;
             return;
         }
     }
 
-    md_mark_chain_append(ctx, &DOLLAR_OPENERS, mark_index);
+    if(mark->flags & MD_MARK_POTENTIAL_OPENER)
+        md_mark_chain_append(ctx, &DOLLAR_OPENERS, mark_index);
 }
 
 static MD_MARK*
diff --git a/test/spec-latex-math.txt b/test/spec-latex-math.txt
index 1f44fea..d939bf9 100644
--- a/test/spec-latex-math.txt
+++ b/test/spec-latex-math.txt
@@ -15,6 +15,36 @@ $a+b=c$ Hello, world!
 --flatex-math
 ````````````````````````````````
 
+However the LaTeX math spans cannot be nested:
+
+```````````````````````````````` example
+$$foo $bar$ baz$$
+.
+<p>$$foo <x-equation>bar</x-equation> baz$$</p>
+.
+--flatex-math
+````````````````````````````````
+
+The opening delimiter cannot be preceded with an alphanumerical character:
+
+```````````````````````````````` example
+x$a+b=c$
+.
+<p>x$a+b=c$</p>
+.
+--flatex-math
+````````````````````````````````
+
+Similarly the closing delimiter cannot be followed with an alphanumerical character:
+
+```````````````````````````````` example
+$a+b=c$x
+.
+<p>$a+b=c$x</p>
+.
+--flatex-math
+````````````````````````````````
+
 If the double dollar sign is used, the math span is a display math span.
 
 ```````````````````````````````` example