Skip to content

Commit ecd435a

Browse files
authored
Merge pull request #459 from sarathfrancis90/fix/markdown-renderer-link-title-quote
Escape quotes in MarkdownRenderer link and image titles
2 parents 0799e19 + 2c1a518 commit ecd435a

2 files changed

Lines changed: 21 additions & 2 deletions

File tree

src/mistune/renderers/markdown.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def render_referrences(self, state: BlockState) -> Iterable[str]:
3232
text = "[" + attrs["label"] + "]: " + attrs["url"]
3333
title = attrs.get("title")
3434
if title:
35-
text += ' "' + title + '"'
35+
text += ' "' + _escape_title(title) + '"'
3636
yield text
3737

3838
def render_children(self, token: Dict[str, Any], state: BlockState) -> str:
@@ -71,7 +71,7 @@ def link(self, token: Dict[str, Any], state: BlockState) -> str:
7171
else:
7272
out += url
7373
if title:
74-
out += ' "' + title + '"'
74+
out += ' "' + _escape_title(title) + '"'
7575
return out + ")"
7676

7777
def image(self, token: Dict[str, Any], state: BlockState) -> str:
@@ -188,6 +188,13 @@ def table_cell(self, token: Dict[str, Any], state: BlockState) -> str:
188188
return _render_table_cell(self, token, state)
189189

190190

191+
def _escape_title(title: str) -> str:
192+
"""Escape a link/image title for emission inside double quotes. The closing
193+
quote would otherwise end the title early on a re-parse; a backslash is
194+
escaped first so it can't combine with the following character."""
195+
return title.replace("\\", "\\\\").replace('"', '\\"')
196+
197+
191198
def _escape_block_prefix(text: str) -> str:
192199
"""Backslash-escape a leading block marker on each line so that literal
193200
text is not re-parsed as a list, heading or block quote."""

tests/test_renderers.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ def test_codespan_containing_backticks(self):
5858
):
5959
self.assert_round_trip(text)
6060

61+
def test_link_title_containing_quote(self):
62+
# a double quote inside a link/image title must be escaped, or the
63+
# re-parse closes the title early and drops it
64+
for text in (
65+
"[t](/u 'say \"hi\"')\n",
66+
'[t](/u "say \\"hi\\"")\n',
67+
"![a](/u 'say \"hi\"')\n",
68+
"[t][r]\n\n[r]: /u 'say \"hi\"'\n",
69+
'[t](/u "back\\\\slash \\" quote")\n',
70+
):
71+
self.assert_round_trip(text)
72+
6173
def test_real_markers_preserved(self):
6274
for text in (
6375
"* bullet\n",

0 commit comments

Comments
 (0)