Skip to content

Handle escaped markdown markers inside markdown links#1883

Open
apoorvdarshan wants to merge 1 commit into
py-pdf:masterfrom
apoorvdarshan:fix/1847-escaped-markers-inside-markdown-links
Open

Handle escaped markdown markers inside markdown links#1883
apoorvdarshan wants to merge 1 commit into
py-pdf:masterfrom
apoorvdarshan:fix/1847-escaped-markers-inside-markdown-links

Conversation

@apoorvdarshan

Copy link
Copy Markdown

Summary

Fixes #1847.

Markdown markers inside the display text of a markdown link are intentionally not interpreted (this is existing, tested behavior — [**bold**](url) keeps ** literal). However, a preceding escape backslash was previously left untouched inside links, unlike everywhere else. As a result:

  • On the parse side, escaping a marker inside a link (e.g. [\**Issue\**](url)) leaked literal backslashes into the rendered text — producing \**Issue\** instead of **Issue**.
  • On the LINES re-serialization side, the display text was emitted verbatim (a NOTE in the code acknowledged this), so markers inside a link were not escaped while text outside links was, yielding double-escaped output on the round-trip.

This is the exact scenario from the issue:

text = (
    "[**Issue** 1844](https://github.com/py-pdf/fpdf2/pull/1844)\n"
    "[\\**Issue\\** 1844](https://github.com/py-pdf/fpdf2/pull/1844)"
)

previously rendered the second line with visible escape backslashes.

Fix

  • Added FPDF._markdown_unescape_link_text(), which collapses escape sequences inside a link's display text using the same rules as _parse_chars (markdown markers kept literal, escape backslashes consumed), and applied it where the link Fragment is created.
  • Updated the LINES re-serialization to run the link display text through the existing escape() helper, so markers it contains are re-parsed as literal characters and the round-trip stays stable. The stale NOTE comment was replaced accordingly.

Style markers inside links remain literal (unchanged, deliberate behaviour); this PR is scoped strictly to removing the escape/double-escape defect.

Tests

  • test_markdown_parse_escaped_markers_inside_link (parse side): escaped markers inside a link now consume the backslash and stay literal; doubled backslashes collapse to one — matching outside-link behaviour.
  • test_multi_cell_markdown_escaped_markers_inside_link (LINES round-trip): the parsed fragment and the LINES re-serialization are free of stray escape characters and round-trip stably.

Both tests fail on master before the change and pass after. The full test/text/ and test/html/ suites pass, and the existing markdown reference-PDF tests (including test_multi_cell_markdown_styled_link and ..._dry_run_lines_output_escape) are unchanged, confirming no rendered output regressions. black, pylint, and mypy are clean on the changed files.

Disclosure: prepared with AI assistance; reviewed and verified locally.

Markdown markers inside a link's display text are intentionally not
interpreted, but a preceding escape backslash was previously left
untouched. As a result, escaping a marker inside a link (e.g.
`[\**Issue\**](url)`) leaked literal backslashes into the rendered
text, and the LINES re-serialization emitted the display text verbatim,
producing double-escaped output.

Escape sequences inside link text are now collapsed with the same rules
as `_parse_chars` uses elsewhere (markers kept literal, backslashes
consumed), and the LINES re-serialization now escapes the link display
text so the round-trip stays stable.

Fixes py-pdf#1847.
@andersonhc

Copy link
Copy Markdown
Collaborator

Hi @apoorvdarshan

Thanks for working on this. I think this fixes the narrower escaping symptom from the issue, but I have a scope concern before we close #1847.

In the issue discussion, the agreed scoped behavior was to support markdown markers that both open and close inside the link label, for example:

"[**Issue** 1847](url)"

should render Issue 1847 as bold while keeping the whole label linked. We explicitly wanted to avoid supporting markers that span across the link boundary, but markers fully contained inside the link text were expected to be parsed.

This PR instead keeps the existing behavior where markers inside link labels are always literal. So Issue still renders visible Issue, and \Issue\ now converges to the same literal output. That solves the stray backslash symptom, but not the behavior discussed in #1847.

Could you either:

  • extend the implementation so balanced markers inside the link label are interpreted while preserving the link on all resulting fragments, or
  • update the PR description / issue expectation if we intentionally want to limit this fix to only consuming escape backslashes inside literal link labels?

Also, the CI lint step is failing because of the new protected-member accesses in test/text/test_multi_cell_markdown.py:

test/text/test_multi_cell_markdown.py:414:17: W0212: Access to a protected member _parse_chars of a client class
test/text/test_multi_cell_markdown.py:430:57: W0212: Access to a protected member _parse_chars of a client class

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.

Markdown markers inside of markdown links are implicitly escaped

2 participants