Skip to content

fix: don't read past position 0 when checking dollar escaping in dollarmath - #174

Open
rahul05ranjan wants to merge 1 commit into
executablebooks:masterfrom
rahul05ranjan:fix/dollarmath-escaped-dollar-off-by-one
Open

rahul05ranjan wants to merge 1 commit into
executablebooks:masterfrom
rahul05ranjan:fix/dollarmath-escaped-dollar-off-by-one

Conversation

@rahul05ranjan

Copy link
Copy Markdown

Fixes #173

Summary

dollarmath's is_escaped helper decrements its position index inside a while back_pos >= 0 loop, so for a dollar at position 0 the index becomes -1 and Python's negative indexing reads the last character of the inline source instead of finding no preceding character:

  • Math at the very start of a paragraph was silently dropped whenever the inline source ended with a backslash — rendering $a$ is math\ produced literal $a$ instead of the math span (with \\ at the end the same happened).
  • Backslash runs before a mid-source dollar could pick up trailing characters, flipping an odd count to even so an escaped dollar was treated as an opening delimiter.

The fix is the one-character bound: while back_pos > 0. Position 0 has no preceding character, so the count stays 0.

Testing

  • test_inline_func_start_with_trailing_backslash — $a$ is math\ and $a$ is math\\ at position 0 must parse as math. Fails on un-fixed HEAD (rule returns False, no token).
  • test_inline_func_escaped_dollar_mid_source_with_trailing_backslash — \$x$ y\ from position 1 must stay un-parsed. Fails on un-fixed HEAD (rule returns True and pushes a math token).
  • Full suite: 636 passed, 3 skipped, 1 xfailed on Python 3.13, plus the 16 pre-existing data_regression fixture collection errors that also occur on the un-modified checkout (the pytest-regressions plugin is not installed in this environment).
  • Re-verified the rendered output for all four shapes with the plugin active (math-at-0 kept, escaped mid-source dollar kept un-parsed).

Notes

The mid-source escaped-dollar path is normally masked in full parsing by markdown-it's own escape rule consuming the \$ pair first, so it is covered as a unit contract of the helper; the position-0 dropped-math case reproduces end-to-end through .render().

…armath

is_escaped decremented its position index inside a loop whose condition
allowed back_pos == 0, so on Python's negative indexing it read the last
character of the inline source instead of finding no preceding
character. A dollar at position 0 was then treated as escaped whenever
the inline source ended with a backslash, silently dropping math at the
start of a paragraph, and backslash runs before a mid-source dollar
picked up trailing characters, flipping odd counts to even.

Co-authored-by: rahul05ranjan <[email protected]>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dollarmath: math at the start of a paragraph is dropped when the paragraph ends with a backslash (is_escaped reads past position 0)

1 participant