From decdecaa860e63b74cbc80e0bada96851a0849ba Mon Sep 17 00:00:00 2001 From: Leonardo Salas Date: Wed, 9 Sep 2026 19:36:55 -0600 Subject: [PATCH] fix: strip the heading the cover page actually promotes `extract_title` now reads the parsed document, so it correctly ignores a `# ` line inside fenced code and recognizes an underlined H1. `strip_first_heading` was still scanning raw lines, and the two could disagree. A file opening with a shell block lost the `# install` comment out of its code and then printed its real title twice, once on the cover and once as a heading. A file whose title is underlined rather than prefixed kept the heading for the same reason. Both come from deciding what a heading is by looking at a single line, so the scan now tracks fences and treats an `=` underline as the H1 it is. --- doc_engine/converter.py | 29 +++++++++++++++++++++++++---- tests/test_converter.py | 17 +++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/doc_engine/converter.py b/doc_engine/converter.py index 91df875..09468f0 100644 --- a/doc_engine/converter.py +++ b/doc_engine/converter.py @@ -46,6 +46,8 @@ _INLINE_MATH = r"\$(?!\s)(?P(?:[^$\\\n]|\\.)+?)(? str | None: def strip_first_heading(markdown: str) -> str: + """Remove the H1 the cover page promotes, so the document does not repeat it. + + This has to drop the same heading `extract_title` reads. A line that starts + with `# ` inside fenced code is a comment, not a heading, and an H1 can be + written as an underline instead, so neither can be decided by looking at one + line on its own. + """ lines = markdown.split("\n") result: list[str] = [] found = False + fence = "" for line in lines: - if not found and line.strip().startswith("# ") and not line.strip().startswith("##"): - found = True - continue - if found and not result and not line.strip(): + stripped = line.strip() + if fence: + if stripped.startswith(fence) and set(stripped) == {fence[0]}: + fence = "" + elif opening := _FENCE.match(line): + fence = opening.group(1) + elif not found: + if stripped.startswith("# "): + found = True + continue + if _SETEXT_H1.match(line) and result and result[-1].strip(): + found = True + result.pop() + continue + if found and not result and not stripped: continue result.append(line) return "\n".join(result) diff --git a/tests/test_converter.py b/tests/test_converter.py index 7c9c6fe..3ed3607 100644 --- a/tests/test_converter.py +++ b/tests/test_converter.py @@ -68,6 +68,23 @@ def test_preserves_h2(self) -> None: md = "## Subtitle\n\nBody" assert strip_first_heading(md) == md + def test_keeps_comments_inside_fenced_code(self) -> None: + md = "```bash\n# install\npipx install doc-engine-cli\n```\n\n# Title\n\nBody" + result = strip_first_heading(md) + assert "# install" in result + assert "# Title" not in result + + def test_removes_an_underlined_h1(self) -> None: + md = "Title\n=====\n\nBody" + result = strip_first_heading(md) + assert "Title" not in result + assert "Body" in result + + def test_removes_what_the_title_promotes(self) -> None: + md = "```\n# fake\n```\n\nReal\n====\n\nBody" + assert extract_title(md) == "Real" + assert "Real" not in strip_first_heading(md) + class TestConvert: def test_heading_levels(self) -> None: