diff --git a/docs/changelog.md b/docs/changelog.md index 4de3ac62..f40a93e3 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -16,6 +16,8 @@ See the [Contributing Guide](contributing.md) for details. ### Fixed +* Fix regression in `BacktickInlineProcessor` where text could be lost when opening + and closing backticks did not match (#1668). * Escape the language name in the `codehilite` extension's non-Pygments output to maintain consistency with Pygments output. diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index 785585d0..ec9c7cb1 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -413,7 +413,7 @@ def __init__(self, pattern: str): self.tag = 'code' """ The tag of the rendered element. """ - def find_code_spans(self, start: int, text: str) -> tuple[int, int] | None: + def find_code_spans(self, start: int, text: str) -> tuple[int, int | None]: """Find code spans.""" last = len(text) @@ -424,10 +424,6 @@ def find_code_spans(self, start: int, text: str) -> tuple[int, int] | None: max_ticks += 1 start += 1 - if not max_ticks: # pragma: no cover - # This is not ever expected to happen. - return None - longest_span = 0 end = 0 @@ -453,11 +449,11 @@ def find_code_spans(self, start: int, text: str) -> tuple[int, int] | None: # Since we didn't find an exact matching start and end, # adjust start to match the largest end we could calculate. - if longest_span: + if 0 < longest_span < max_ticks: return start - (max_ticks - longest_span), end - longest_span # We could not find a suitable pairing - return None + return start + max_ticks, None def handleMatch(self, m: re.Match[str], data: str) -> tuple[etree.Element | str | None, int | None, int | None]: """ @@ -472,13 +468,13 @@ def handleMatch(self, m: re.Match[str], data: str) -> tuple[etree.Element | str return m.group(1).replace('\\\\', self.ESCAPED_BSLASH), m.start(0), m.end(0) begin = m.start(0) - result = self.find_code_spans(begin, data) - if result is not None: - start, end = result + start, end = self.find_code_spans(begin, data) + if end is not None: el = etree.Element(self.tag) el.text = util.AtomicString(util.code_escape(data[start:end].strip())) - return el, begin, result[1] + (start - begin) - return None, None, None + return el, begin, end + (start - begin) + # Skip over backtick group as we could find no match + return None, begin, start class DoubleTagPattern(SimpleTagPattern): # pragma: no cover diff --git a/tests/test_syntax/inline/test_code.py b/tests/test_syntax/inline/test_code.py index c7ccc4bf..cf54de72 100644 --- a/tests/test_syntax/inline/test_code.py +++ b/tests/test_syntax/inline/test_code.py @@ -79,3 +79,18 @@ def test_noname_tag(self): """ ) ) + + def test_bigger_end(self): + + # https://github.com/Python-Markdown/markdown/issues/1668 + self.assertMarkdownRenders( + 'a ``` b ````` c', + '
a ``` b ````` c
' + ) + + def test_smaller_end(self): + + self.assertMarkdownRenders( + 'a ``` b `` c', + 'a ` b c