Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Change Log

## Unreleased

- 🐛 FIX: `dollarmath` block rule no longer absorbs following content when a same-line-closed `$$...$$` has non-label trailing text (#147)

A same-line close followed by trailing content that wasn't a label suffix (e.g. `` $$b$$ trailing ``) wasn't recognized as closed, so the rule fell through to its multi-line scan and silently swallowed every following line, including subsequent list items, up to the next `$$` anywhere later in the document:

```markdown
1. $$a$$
1. $$b$$ trailing
1. $$c$$
```

This ambiguous case (closing marker present, but not at end of line and not a label) is now rejected outright, letting the line fall through to normal inline parsing instead.

## 0.7.0 - 2026-07-19

- ✨ NEW: Add section reference plugin (`section_ref`) (#144)
Expand Down
22 changes: 15 additions & 7 deletions mdit_py_plugins/dollarmath/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,13 +322,21 @@ def _math_block_dollar(
if lineText.strip().endswith("$$"):
haveEndMarker = True
end = end - 2 - (len(lineText) - len(lineText.strip()))
elif allow_labels:
# reverse the line and match
eqnoMatch = DOLLAR_EQNO_REV.match(lineText[::-1])
if eqnoMatch:
haveEndMarker = True
label = eqnoMatch.group(1)[::-1]
end = end - eqnoMatch.end()
else:
# a closing marker present but not at end of line and not a label
# suffix is ambiguous, so don't greedily scan subsequent lines for it
trailing_close = "$$" in lineText[2:]
if allow_labels:
# reverse the line and match
eqnoMatch = DOLLAR_EQNO_REV.match(lineText[::-1])
if eqnoMatch:
haveEndMarker = True
label = eqnoMatch.group(1)[::-1]
end = end - eqnoMatch.end()
elif trailing_close:
return False
elif trailing_close:
return False

# search for end of block on subsequent line
if not haveEndMarker:
Expand Down
35 changes: 35 additions & 0 deletions tests/fixtures/dollar_math.md
Original file line number Diff line number Diff line change
Expand Up @@ -580,3 +580,38 @@ Indented by 4 spaces, DISABLE-CODEBLOCKS
a
</div>
.

same-line-closed block with trailing text is not absorbed into
a later math block on a following line. (valid=True)
.
$$a$$ trailing
$$c$$
.
<p><div class="math inline">a</div> trailing
<div class="math inline">c</div></p>
.

same-line-closed block with trailing text inside a list is not
absorbed into a later list item. (valid=True)
.
1. $$a$$
1. $$b$$ trailing
1. $$c$$
.
<ol>
<li>
<div class="math block">
a
</div>
</li>
<li><div class="math inline">b</div> trailing
<ol>
<li>
<div class="math block">
c
</div>
</li>
</ol>
</li>
</ol>
.
15 changes: 15 additions & 0 deletions tests/test_dollarmath.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,21 @@ def test_block_func():
}


@pytest.mark.parametrize("allow_labels", [True, False])
def test_block_func_ambiguous_trailing_content(allow_labels):
"""A same-line close followed by non-label trailing content is
ambiguous, so the block rule should not match and greedily scan
subsequent lines for the next ``$$``.
"""
block_func = main.math_block_dollar(allow_labels=allow_labels)
md = MarkdownIt()
src = "$$b$$ trailing\n$$c$$\n"
tokens = []
state = StateBlock(src, md, {}, tokens)
assert block_func(state, 0, 2, False) is False
assert tokens == []


def test_plugin_parse(data_regression):
md = MarkdownIt().use(dollarmath_plugin)
tokens = md.parse(
Expand Down
Loading