feat(docs): generate fish-config.md from the manual tree
Adds docs/build-manual.py (--concat) and a round-trip test in verify-manual.py that reproduces the pre-migration fish-config.md exactly from docs/manual/. Fixes found by the round-trip check, applied in split-manual.py and re-run to regenerate docs/manual/: - NAME/SYNOPSIS/TABLE OF CONTENTS had no sidebar.order, so they sorted after every numbered section instead of interleaving with DESCRIPTION in original document order. All manual pages now get sidebar.order from a single position counter matching source order. - split_h1/split_h2 used .strip() on section bodies, which also ate leading indentation on the first body line, corrupting the 4-space indented code blocks that open SYNOPSIS and TABLE OF CONTENTS. - The source's leading pandoc metadata block (title/section/header/ date/author) was discarded entirely by the splitter. It's now parsed off via manualtools.parse and stashed on index.md under a "pandoc" key; build-manual.py re-emits it verbatim ahead of the first heading.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Generate publishable artifacts from the docs/manual SSOT.
|
||||
|
||||
--concat one ordered markdown document for pandoc / config-help
|
||||
--site Starlight content tree + sidebar.json
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
import manualtools as mt
|
||||
|
||||
DOCS = Path(__file__).parent
|
||||
MANUAL = DOCS / "manual"
|
||||
|
||||
|
||||
def build_concat(root: Path) -> str:
|
||||
"""Concatenate the manual into one ordered markdown document.
|
||||
|
||||
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.
|
||||
"""
|
||||
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---")
|
||||
for path, depth in mt.walk(root):
|
||||
fm, body = mt.parse(path)
|
||||
if not fm.get("man", True):
|
||||
continue
|
||||
heading = fm.get("manTitle") or fm.get("title", path.stem)
|
||||
chunks.append("#" * (depth + 1) + " " + heading)
|
||||
if body:
|
||||
chunks.append(mt.shift_headings(body, depth))
|
||||
return "\n\n".join(chunks) + "\n"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description=__doc__)
|
||||
ap.add_argument("--concat", action="store_true", help="emit the pandoc document")
|
||||
ap.add_argument("-o", "--output", type=Path, help="write to PATH instead of stdout")
|
||||
args = ap.parse_args()
|
||||
|
||||
if not args.concat:
|
||||
ap.error("nothing to do: pass --concat")
|
||||
|
||||
text = build_concat(MANUAL)
|
||||
if args.output:
|
||||
args.output.write_text(text)
|
||||
print(f"wrote {args.output}")
|
||||
else:
|
||||
sys.stdout.write(text)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user