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: