From 968d5aa50e4a9bedae705cce4f55324a218b197b Mon Sep 17 00:00:00 2001 From: Ankit Kumar Date: Fri, 2 Oct 2026 00:44:41 +0530 Subject: [PATCH] fix(md): keep the first-line indentation of code blocks Signed-off-by: Ankit Kumar --- docling/backend/md_backend.py | 4 +++- tests/test_backend_markdown.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/docling/backend/md_backend.py b/docling/backend/md_backend.py index b64b879bca..7a2d48fe2e 100644 --- a/docling/backend/md_backend.py +++ b/docling/backend/md_backend.py @@ -770,7 +770,9 @@ def _iterate_elements( # noqa: C901 isinstance(element, marko.block.CodeBlock | marko.block.FencedCode) and len(element.children) > 0 and isinstance((child := element.children[0]), marko.inline.RawText) - and len(snippet_text := (child.children.strip())) > 0 + # Drop blank lines around the code but keep the first line's + # indentation, which is part of the code. + and len(snippet_text := child.children.lstrip("\n").rstrip()) > 0 ): self._close_table(doc) _log.debug(" - Code Block: %s", element.children) diff --git a/tests/test_backend_markdown.py b/tests/test_backend_markdown.py index 842eb494b5..f6973a2775 100644 --- a/tests/test_backend_markdown.py +++ b/tests/test_backend_markdown.py @@ -238,6 +238,39 @@ def test_code_block_language_detection(): ] +def test_code_block_keeps_first_line_indentation(): + """Indentation on a code block's first line is content, not padding. + + Stripping the whole snippet removed it from the first line only, so the + lines no longer lined up: YAML changed structure and Python stopped parsing. + """ + markdown = ( + "```yaml\n" + " key: 1\n" + " sub:\n" + " x: 2\n" + "```\n\n" + "Indented block:\n\n" + " deeper\n" + " base\n\n" + "```\n" + "\n" + " after blank line\n" + "```\n" + ) + conv_result = get_converter().convert_string(markdown, format=InputFormat.MD) + assert conv_result.status == ConversionStatus.SUCCESS + + code_texts = [ + item.text for item in conv_result.document.texts if isinstance(item, CodeItem) + ] + assert code_texts == [ + " key: 1\n sub:\n x: 2", + " deeper\nbase", + " after blank line", + ] + + def test_convert_table_keeps_inline_code_spans(): """A code span inside a GFM table cell is part of that cell.