Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions lovstudio-any2pdf/scripts/md2pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1085,10 +1085,12 @@ def parse_md(self, md):
toc.append(('chapter', title, cm.key))
i += 1; continue

# H3 = Section
if stripped.startswith('### '):
# H3–H6 = Section. Deeper levels fall back to the H3 style so their
# content is still rendered (ReportLab has no built-in H4–H6 styles here).
m_h = re.match(r'^(#{3,6})\s+(.+)$', stripped)
if m_h:
story.append(Spacer(1, 3*mm))
story.append(Paragraph(md_inline(stripped[4:].strip(), ah), ST['h3']))
story.append(Paragraph(md_inline(m_h.group(2).strip(), ah), ST['h3']))
story.append(Spacer(1, 1*mm))
i += 1; continue

Expand Down Expand Up @@ -1134,6 +1136,10 @@ def parse_md(self, md):
else:
merged += ' ' + pl
story.append(Paragraph(md_inline(merged, ah), ST['body']))
else:
# Defensive: current line matched no handler above (e.g. a stray
# marker we don't parse). Advance to prevent an infinite loop.
i += 1
continue

return story, toc
Expand Down
44 changes: 44 additions & 0 deletions tests/07-deep-headings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: "Deep Headings Regression Test"
subtitle: "H4/H5/H6 must not hang the parser"
author: "any2pdf"
version: "test"
---

# Part

Body paragraph before the nested headings.

## Chapter

### Section (H3 — already supported)

Body text under H3.

#### Subsection (H4 — previously hung the parser)

Body text under H4. The parse_md loop used to never advance `i` when it saw a
deeper heading like this, because H4–H6 had no handler and the paragraph
collector broke on lines starting with `#`. The result was 100% CPU forever.

##### Deeper subsection (H5)

Body text under H5 with some `inline code` and **bold**.

###### Deepest (H6)

Body text under H6.

#### Another H4 right after a table

| Col A | Col B | Col C |
|-------|-------|-------|
| a1 | b1 | c1 |
| a2 | b2 | c2 |

Body paragraph after the table. This used to never render because the H4 above
would spin forever.

#### H4 with & ampersand and `${VAR}/path.md`

Inline code inside deep heading context should not break anything.