From 7a9e004e1bd377559eb2c3e58fa4c8a473219fac Mon Sep 17 00:00:00 2001 From: eeshsaxena Date: Thu, 13 Aug 2026 18:41:11 +0530 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20FIX:=20keep=20the=20hard=20line?= =?UTF-8?q?=20break=20after=20a=20literal=20backslash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit markdown-it's escape rule leaves the space after a literal backslash unconsumed, so a following two-space hard line break is still detected by the newline rule. This port jumped straight to the generic escape branch, which consumed the space, leaving only one space before the newline. As a result `foo\ \nbar` produced a soft break with a stray backslash-space instead of `foo\
`. Port the missing space case. --- markdown_it/rules_inline/escape.py | 11 +++++++++++ tests/test_port/test_misc.py | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/markdown_it/rules_inline/escape.py b/markdown_it/rules_inline/escape.py index 0fca6c84..f2e2dd51 100644 --- a/markdown_it/rules_inline/escape.py +++ b/markdown_it/rules_inline/escape.py @@ -36,6 +36,17 @@ def escape(state: StateInline, silent: bool) -> bool: state.pos = pos return True + # '\' before a space is a literal backslash. Don't consume the space, so a + # trailing two-space hard line break is still detected by the newline rule. + if ch1 == " ": + if not silent: + token = state.push("text_special", "", 0) + token.content = "\\" + token.markup = "\\" + token.info = "escape" + state.pos = pos + return True + escapedStr = state.src[pos] if ch1_ord >= 0xD800 and ch1_ord <= 0xDBFF and pos + 1 < maximum: diff --git a/tests/test_port/test_misc.py b/tests/test_port/test_misc.py index 62b5bf85..550359bd 100644 --- a/tests/test_port/test_misc.py +++ b/tests/test_port/test_misc.py @@ -42,3 +42,11 @@ def type_filter(tokens, type_): assert tokens[2].markup == "." assert tokens[3].info == "199" assert tokens[3].markup == "." + + +def test_backslash_before_two_space_hardbreak(): + # A literal backslash directly before a two-space hard line break must not + # consume a space, otherwise only one space is left and the newline rule + # produces a soft break instead of a hard break. + md = MarkdownIt("commonmark") + assert md.render("foo\\ \nbar") == "

foo\\
\nbar

\n"