Skip to content

🐛 FIX: myst_role backslash-guard misparse at inline start#145

Merged
chrisjsewell merged 1 commit into
masterfrom
claude/mdit-section-reference-plugin-yfvmtz
Jul 19, 2026
Merged

🐛 FIX: myst_role backslash-guard misparse at inline start#145
chrisjsewell merged 1 commit into
masterfrom
claude/mdit-section-reference-plugin-yfvmtz

Conversation

@chrisjsewell

Copy link
Copy Markdown
Member

What

Fixes #62: myst_role misparsed inline content that starts with a role and ends with a backslash:

md.render("{foo}`ar`\\")
# before: <p>{foo}<code>ar</code>\</p>          (role not captured)
# after:  <p><code class="myst role">{foo}[ar]</code>\</p>

Why

The "starting backslash escape" guard read state.src[state.pos - 1]. At state.pos == 0 that is Python negative indexing — it reads the last character of the inline source (the except IndexError never fires), so a role at the start of the inline was rejected whenever the content ended with \.

The guard is removed entirely rather than bounds-checked, because it was wrong in both remaining respects too:

  • For its intended case (\{foo}x``) it was dead code: { is CommonMark-escapable, so the core `escape` rule (which runs before this rule) consumes `{` wholesale — `myst_role` is never invoked there. Verified unchanged before/after.
  • For an escaped backslash (\\{foo}x``) it wrongly suppressed a live role; it now renders a literal \ followed by the parsed role, matching the CommonMark analogy (`\a` → `<em>a`). This is the "edge case `\{`" the guard's own comment flagged as broken.

This mirrors the analysis done for the section_ref plugin in #144, where the same guard pattern was dropped.

Testing

  • 3 new fixture cases: the myst_role misparses trailing \ #62 repro, \{foo}x (still escaped, via the core rule), and `\\{foo}`x (now a live role).
  • Adversarially probed old-vs-new behavior across commonmark/default/gfm presets, table cells, link labels, image alts, and emphasis adjacency: the only differences are the two intended fixes. Full suite 511 passed; ruff and strict mypy clean.
  • Sole caveat: in a zero-preset config without the core escape rule, \{foo}x`` now parses the role (previously suppressed-but-still-literal-backslash). No realistic consumer runs myst_role without the escape rule; a code comment now documents the assumption.

Note: the same latent state.src[state.pos - 1] wraparound exists in dollarmath (only reachable with the non-default allow_digits=False) — left for a separate PR.


Generated by Claude Code

The guard checking the char before the role read state.src[state.pos - 1],
which at pos 0 wraps to the last char of the inline source (negative
indexing; the IndexError branch never fires), wrongly rejecting a role at
the start of inline content whenever the content ends with a backslash.

The guard is removed entirely: \{ is already consumed by the core escape
rule before this rule runs (so the guard was dead for its intended case),
and for an escaped backslash (\\{name}`x`) it wrongly suppressed a live
role.

Closes #62
@codecov

codecov Bot commented Jul 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.90%. Comparing base (d11bdaf) to head (581fefe).
⚠️ Report is 15 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #145      +/-   ##
==========================================
+ Coverage   92.80%   92.90%   +0.10%     
==========================================
  Files          31       40       +9     
  Lines        1835     2284     +449     
==========================================
+ Hits         1703     2122     +419     
- Misses        132      162      +30     
Flag Coverage Δ
pytests 92.90% <ø> (+0.10%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@chrisjsewell
chrisjsewell merged commit 6a462d6 into master Jul 19, 2026
12 checks passed
@chrisjsewell
chrisjsewell deleted the claude/mdit-section-reference-plugin-yfvmtz branch July 19, 2026 18:51
@chrisjsewell chrisjsewell mentioned this pull request Jul 19, 2026
chrisjsewell added a commit that referenced this pull request Jul 19, 2026
Bumps the version to 0.7.0 and dates the changelog for release.

## 0.7.0 - 2026-07-19

- ✨ NEW: Add section reference plugin (`section_ref`) (#144)
- 🐛 FIX: `myst_role` no longer mis-rejects a role at the start of inline
content when the content ends with a backslash (#62, #145)

Also included since 0.6.1: the switch to PyPI trusted publishing (#142)
— this will be the first release through the OIDC publish job.

After merge, tagging `v0.7.0` on master triggers the publish job.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01LwRkZLzpbHdb3pgmctmn6H)_

Co-authored-by: Claude <noreply@anthropic.com>
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.

myst_role misparses trailing \

2 participants