Skip to content

Fix standalone markdown bugs found while planning escaping rewrite#1900

Merged
hadley merged 2 commits into
mainfrom
markdown-fixes
Jul 5, 2026
Merged

Fix standalone markdown bugs found while planning escaping rewrite#1900
hadley merged 2 commits into
mainfrom
markdown-fixes

Conversation

@hadley

@hadley hadley commented Jul 5, 2026

Copy link
Copy Markdown
Member

While designing a replacement for the markdown escaping/unescaping machinery, I found several standalone bugs and cleanups worth landing first:

  • UTF-8 offsets: roxygen_parse_tag() is now UTF-8 aware, so findEndOfTag() accepts and returns character offsets. Previously its byte offsets were combined with character offsets from gregexpr()/substr(), so a multibyte character inside a fragile Rd tag corrupted markdown processing of the text that followed — e.g. \code{café} *x* lost the emphasis and \code{café} `x` left the backticks literal. The same mismatch affected strip_rd_tag() on examples containing multibyte characters. rdComplete() is unaffected.

  • Tag-less warnings: markdown()'s fake default tag (list(file = NA, line = NA)) crashed in basename(), and rd-family.R passed the bare string "family", which crashed on tag$tag. Both now pass NULL, which warn_roxy_tag() handles, so e.g. a level-1 heading in an rd_family_title prefix now warns instead of erroring.

  • Dead code: deleted unused markdown_pass1() plus seven helpers that were defined identically in both markdown.R and markdown-code.R — the markdown.R copies silently shadowed the others because of collation order. The one divergence (the "Multi-line r markup" message) was reconciled to the version the snapshots expect.

  • Stale docs: removed the claim that markdown is interpreted inside the 2nd/3rd arguments of \if/\ifelse; it was never implemented — fragile tags are protected together with all their arguments.

  • Fast path: markdown_evaluate() now skips the commonmark parse when the text contains no backtick or tilde (tilde-fenced ~~~{r} blocks parse and evaluate today, so ~ stays in the gate), so the many tags without any code don't pay for a full parse.

🤖 Generated with Claude Code

* Make roxygen_parse_tag() UTF-8 aware, so findEndOfTag() accepts and
  returns character offsets. Previously its byte offsets were mixed with
  character offsets from gregexpr()/substr(), so a multibyte character
  inside a fragile Rd tag (e.g. \code{café}) corrupted markdown
  processing of the following text, and strip_rd_tag() mis-sliced
  examples containing multibyte characters.

* Fix warning paths for tag-less markdown(): the fake default tag
  crashed in basename(), and rd-family.R passed a bare string that
  crashed on tag$tag. Both now pass NULL, which warn_roxy_tag()
  handles.

* Delete dead markdown_pass1() and seven helpers duplicated between
  markdown.R and markdown-code.R (the markdown.R copies silently shadow
  the markdown-code.R ones due to collation order).

* Remove the stale claim that markdown is interpreted inside \if/
  \ifelse arguments; fragile tags are protected with all their
  arguments.

* Skip the commonmark parse in markdown_evaluate() when the text
  contains no backtick or tilde, so tags without code don't pay for a
  full parse.
@hadley hadley merged commit aaacc13 into main Jul 5, 2026
13 checks passed
@hadley hadley deleted the markdown-fixes branch July 5, 2026 23:49
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.

1 participant