diff --git a/docs/build-manual.py b/docs/build-manual.py index 3e95e86..c62d7b3 100644 --- a/docs/build-manual.py +++ b/docs/build-manual.py @@ -11,8 +11,6 @@ import argparse import sys from pathlib import Path -import yaml - import manualtools as mt DOCS = Path(__file__).parent @@ -25,17 +23,17 @@ def build_concat(root: Path) -> str: Each file contributes `# {manTitle or title}` at a level matching its depth, and its body headings are demoted by the same amount. - The root `index.md` (the LANDING page) may carry a `pandoc` key in its - frontmatter — the original document's pandoc metadata block - (title/section/header/date/author). If present, it is re-emitted - verbatim as the leading `---`-fenced block, ahead of every heading. + `root / "_pandoc.yml"` (if present) holds the original document's + pandoc metadata block (title/section/header/date/author) as raw text, + with no frontmatter fences and no Astro-visible frontmatter key. When + present, its contents are re-emitted byte-for-byte as the leading + `---`-fenced block, ahead of every heading. """ chunks: list[str] = [] - index_fm, _ = mt.parse(root / "index.md") - pandoc_meta = index_fm.get("pandoc") - if pandoc_meta: - header = yaml.safe_dump(pandoc_meta, sort_keys=False, allow_unicode=True).rstrip() - chunks.append(f"---\n{header}\n---") + pandoc_path = root / "_pandoc.yml" + if pandoc_path.exists(): + raw = pandoc_path.read_text().rstrip("\n") + chunks.append(f"---\n{raw}\n---") for path, depth in mt.walk(root): fm, body = mt.parse(path) if not fm.get("man", True): diff --git a/docs/manual/_pandoc.yml b/docs/manual/_pandoc.yml new file mode 100644 index 0000000..057b2b4 --- /dev/null +++ b/docs/manual/_pandoc.yml @@ -0,0 +1,5 @@ +title: FISH-CONFIG +section: 7 +header: Fish Shell Configuration User Manual +date: June 2026 +author: Rootiest diff --git a/docs/manual/index.md b/docs/manual/index.md index 2889163..7e19354 100644 --- a/docs/manual/index.md +++ b/docs/manual/index.md @@ -4,12 +4,6 @@ description: Reference manual for the rootiest fish configuration. manTitle: DESCRIPTION sidebar: order: 3 -pandoc: - title: FISH-CONFIG - section: 7 - header: Fish Shell Configuration User Manual - date: June 2026 - author: Rootiest helpKeywords: - description - autopair diff --git a/docs/split-manual.py b/docs/split-manual.py index aa45f03..9188e4f 100644 --- a/docs/split-manual.py +++ b/docs/split-manual.py @@ -50,6 +50,23 @@ def load_keywords() -> dict[str, list[str]]: return mapping +def extract_raw_frontmatter(path: Path) -> str | None: + """Return the raw text between a file's opening `---` fences, or None. + + Unlike `mt.parse`, this does not round-trip the block through + `yaml.safe_load`/`yaml.safe_dump` — it hands back the exact original + bytes (minus the fence lines themselves) so a later verbatim re-emit + doesn't have to worry about quoting-style or scalar-coercion drift. + """ + text = path.read_text() + if not text.startswith("---\n"): + return None + end = text.find("\n---\n", 4) + if end == -1: + return None + return text[4:end] + + def _trim_blank_lines(text: str) -> str: """Drop leading/trailing blank lines without touching interior indentation. @@ -91,10 +108,16 @@ def main() -> int: keywords = load_keywords() # SRC starts with a pandoc metadata block (title/section/header/date/ - # author) consumed by the man-page build. mt.parse() peels it off so it - # isn't silently dropped; it gets stashed on the LANDING (index.md) page - # under "pandoc" and re-emitted verbatim by build-manual.py --concat. - pandoc_meta, src_body = mt.parse(SRC) + # author) consumed by the man-page build. It has no purpose as an Astro + # page's frontmatter (index.md is also a website content page, and + # Starlight errors on any custom frontmatter key outside the fixed + # man/site/manTitle/helpKeywords schema), so it is extracted as raw text + # and written to docs/manual/_pandoc.yml instead of being folded into + # index.md's frontmatter. The leading underscore keeps Astro content + # collections from treating it as a page. build-manual.py --concat + # reads it back and re-emits it byte-for-byte. + pandoc_raw = extract_raw_frontmatter(SRC) + _, src_body = mt.parse(SRC) sections = split_h1(src_body) order = 0 # `position` tracks each heading's place in the *original* document, @@ -127,11 +150,11 @@ def main() -> int: "manTitle": heading, "sidebar": {"order": position}, } - if pandoc_meta: - fm["pandoc"] = pandoc_meta if kw: fm["helpKeywords"] = kw (OUT / "index.md").write_text(mt.serialize(fm, body)) + if pandoc_raw is not None: + (OUT / "_pandoc.yml").write_text(pandoc_raw.rstrip("\n") + "\n") continue order += 1