mirror of
https://github.com/rohitg00/ai-engineering-from-scratch.git
synced 2026-09-19 02:42:50 +08:00
fix(book): wrap long code lines and reference URLs in PDFs (#459)
This commit is contained in:
@@ -31,14 +31,14 @@ jobs:
|
||||
continue-on-error: true
|
||||
run: npm install -g @mermaid-js/mermaid-cli
|
||||
|
||||
- name: Validate book rendering
|
||||
run: python3 scripts/test_book_rendering.py
|
||||
|
||||
- name: Install xelatex
|
||||
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
|
||||
run: |
|
||||
sudo apt-get update -q
|
||||
sudo apt-get install -y -q texlive-xetex texlive-fonts-recommended fonts-dejavu librsvg2-bin
|
||||
sudo apt-get install -y -q texlive-xetex texlive-fonts-recommended fonts-dejavu librsvg2-bin poppler-utils
|
||||
|
||||
- name: Validate book rendering
|
||||
run: python3 scripts/test_book_rendering.py
|
||||
|
||||
- name: Build EPUB volumes
|
||||
if: github.event_name == 'push'
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
\pagecolor{cream}
|
||||
\color{ink}
|
||||
|
||||
\usepackage{fvextra}
|
||||
\fvset{breaklines=true,breakanywhere=true,breaknonspaceingroup=true}
|
||||
\RecustomVerbatimEnvironment{verbatim}{Verbatim}{}
|
||||
|
||||
\usepackage{fancyhdr}
|
||||
\newcommand{\bookfootL}{\ttfamily\scriptsize\color{blueprint}\href{https://aiengineeringfromscratch.com}{AIENGINEERINGFROMSCRATCH.COM}}
|
||||
\newcommand{\bookfootR}{\ttfamily\scriptsize\color{inksoft}\thepage}
|
||||
|
||||
@@ -362,7 +362,7 @@ def render(vol, md, chapters, pdf=False):
|
||||
cmd_pdf = [
|
||||
"pandoc", str(md),
|
||||
"-o", str(pdf_out),
|
||||
"--from", "markdown+fenced_divs",
|
||||
"--from", "markdown+fenced_divs+autolink_bare_uris",
|
||||
"--lua-filter", str(ROOT / "book" / "literal-tokens.lua"),
|
||||
"--toc", "--toc-depth=1",
|
||||
"--top-level-division=chapter",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
import xml.etree.ElementTree as ET
|
||||
from pathlib import Path
|
||||
@@ -6,6 +8,20 @@ from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
FILTER = ROOT / "book" / "literal-tokens.lua"
|
||||
PDF_SOURCE_FORMAT = "markdown+fenced_divs+autolink_bare_uris"
|
||||
LONG_LINES = """# Wrapping regression
|
||||
|
||||
```python
|
||||
message = "Every sample in the batch must be pre-padded with the same number of image placeholders before replacing them with projected image embeddings."
|
||||
identifier = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
```
|
||||
|
||||
```text
|
||||
This plain-text code block must also wrap its long lines without losing the final marker: PLAIN_TEXT_END.
|
||||
```
|
||||
|
||||
Further reading: (http://neuralnetworksanddeeplearning.com/). Keep the URL clickable.
|
||||
"""
|
||||
|
||||
|
||||
def render(source, output="html"):
|
||||
@@ -40,6 +56,31 @@ class BookRenderingTest(unittest.TestCase):
|
||||
self.assertEqual(result.count(r"\textless"), 3)
|
||||
self.assertEqual(result.count(r"\textgreater"), 3)
|
||||
|
||||
@unittest.skipUnless(shutil.which("xelatex") and shutil.which("pdftotext"),
|
||||
"PDF layout check requires xelatex and pdftotext")
|
||||
def test_pdf_long_code_and_urls_stay_inside_margins(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
pdf = Path(directory) / "wrapping.pdf"
|
||||
result = subprocess.run(
|
||||
["pandoc", "--from", PDF_SOURCE_FORMAT, "--pdf-engine=xelatex",
|
||||
"--include-in-header", str(ROOT / "book" / "theme.tex"),
|
||||
"-V", "documentclass=book", "-V", "geometry=margin=1in",
|
||||
"-o", str(pdf)],
|
||||
input=LONG_LINES, text=True, capture_output=True,
|
||||
)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
bbox = subprocess.check_output(["pdftotext", "-bbox", str(pdf), "-"], text=True)
|
||||
root = ET.fromstring(bbox)
|
||||
ns = {"x": "http://www.w3.org/1999/xhtml"}
|
||||
for page in root.findall(".//x:page", ns):
|
||||
right = float(page.attrib["width"]) - 72
|
||||
for word in page.findall(".//x:word", ns):
|
||||
self.assertGreaterEqual(float(word.attrib["xMin"]), 71, word.text)
|
||||
self.assertLessEqual(float(word.attrib["xMax"]), right + 1, word.text)
|
||||
text = "".join(word.text or "" for word in root.findall(".//x:word", ns))
|
||||
for marker in ("embeddings.", "PLAIN_TEXT_END.", "neuralnetworksanddeeplearning.com"):
|
||||
self.assertIn(marker, text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user