mirror of
https://github.com/harvard-edge/cs249r_book.git
synced 2026-11-09 10:39:41 -06:00
Floats before Chapter 1 (each preface's dependency map, vol4's reading-track table) have no chapter number and printed as 0.1. The shared LaTeX header now numbers them P.1 when the chapter counter is 0, so every volume gets it; chapters and appendices are unchanged. Quarto offers no supported prefix for HTML, so a post-render script (frontmatter_float_labels.py) relabels captions, lightbox titles, and in-page references on pages under any frontmatter/ folder to match. Also aligns the vol2-vol4 map captions with vol1: "builds on its results".
64 lines
2.2 KiB
Python
64 lines
2.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Post-render step: number front-matter figures and tables P.1, P.2, ...
|
|
|
|
Figures and tables in front matter (preface, prerequisites) sit before
|
|
Chapter 1 and have no chapter number. The PDF numbers them P.1, P.2, ...
|
|
(shared/tex/header-includes.tex). Quarto's HTML output numbers them 1, 2, ...
|
|
and offers no supported prefix option (2026-10-13: its crossref schema accepts
|
|
only a numbering style, a label list fails at render time, and user filters
|
|
cannot reach its number formatter). This script rewrites the rendered HTML of
|
|
every page under a frontmatter/ folder so captions and in-page references
|
|
match the PDF. It is idempotent: an already-prefixed number does not match.
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Caption prefix ("Figure 1:"), also repeated in the lightbox title
|
|
# attribute, and cross-reference link text ("figure 1").
|
|
CAPTION = re.compile(r'(>\s*|title=")(Figure|Table) (\d+)(:)')
|
|
XREF = re.compile(r'(class="quarto-xref">)(Figure|figure|Table|table) (\d+)(<)')
|
|
|
|
|
|
def relabel(html_path: Path) -> int:
|
|
text = html_path.read_text(encoding="utf-8")
|
|
count = 0
|
|
|
|
def sub(m: re.Match) -> str:
|
|
nonlocal count
|
|
count += 1
|
|
return f"{m.group(1)}{m.group(2)} P.{m.group(3)}{m.group(4)}"
|
|
|
|
new_text = XREF.sub(sub, CAPTION.sub(sub, text))
|
|
if count:
|
|
html_path.write_text(new_text, encoding="utf-8")
|
|
return count
|
|
|
|
|
|
def main() -> None:
|
|
if len(sys.argv) > 1:
|
|
build_dir = Path(sys.argv[1])
|
|
elif os.environ.get("QUARTO_PROJECT_OUTPUT_DIR"):
|
|
build_dir = Path(os.environ["QUARTO_PROJECT_OUTPUT_DIR"])
|
|
else:
|
|
build_dir = Path(__file__).resolve().parents[2] / "_build"
|
|
if not build_dir.is_dir():
|
|
sys.exit(f"[frontmatter-labels] build directory not found: {build_dir}")
|
|
|
|
total = files = 0
|
|
for html_file in sorted(build_dir.rglob("*.html")):
|
|
if "frontmatter" not in html_file.parts:
|
|
continue
|
|
n = relabel(html_file)
|
|
if n:
|
|
total += n
|
|
files += 1
|
|
print(f"[frontmatter-labels] Relabeled {total} front-matter float number(s) in {files} file(s).")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|