mirror of
git://f0xx.org/ac/ac-docs
synced 2026-07-29 04:39:12 +03:00
49 lines
1.4 KiB
Python
49 lines
1.4 KiB
Python
"""Shared markdown heading / slug helpers for docs PDF and TOC scripts."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
|
|
TOC_START = "<!-- toc -->"
|
|
TOC_END = "<!-- /toc -->"
|
|
|
|
|
|
def github_slug(text: str) -> str:
|
|
"""GitHub/Cursor-compatible heading anchor."""
|
|
text = text.strip().lower()
|
|
text = re.sub(r"`([^`]+)`", r"\1", text)
|
|
text = re.sub(r"\*\*([^*]+)\*\*", r"\1", text)
|
|
text = re.sub(r"[*_]+", "", text)
|
|
text = re.sub(r"[^\w\s-]", "", text)
|
|
text = re.sub(r"\s+", "-", text)
|
|
text = re.sub(r"-+", "-", text)
|
|
return text.strip("-")
|
|
|
|
|
|
def collect_headings(lines: list[str]) -> list[tuple[int, str, str]]:
|
|
"""Return (level, title, slug) for ## and ### headings."""
|
|
out: list[tuple[int, str, str]] = []
|
|
used: dict[str, int] = {}
|
|
for line in lines:
|
|
m = re.match(r"^(#{2,3})\s+(.+?)\s*$", line)
|
|
if not m:
|
|
continue
|
|
level = len(m.group(1))
|
|
title = m.group(2).strip()
|
|
if title == "Table of contents":
|
|
continue
|
|
base = github_slug(title)
|
|
if not base:
|
|
continue
|
|
n = used.get(base, 0)
|
|
slug = base if n == 0 else f"{base}-{n}"
|
|
used[base] = n + 1
|
|
out.append((level, title, slug))
|
|
return out
|
|
|
|
|
|
def strip_md_link_text(title: str) -> str:
|
|
t = re.sub(r"\*\*([^*]+)\*\*", r"\1", title)
|
|
t = re.sub(r"`([^`]+)`", r"\1", t)
|
|
return t
|