Skip to content

Commit bc623af

Browse files
committed
Fix title when rendering pdf
1 parent e04fa1e commit bc623af

2 files changed

Lines changed: 52 additions & 2 deletions

File tree

scrivener/lib/builder.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ def build_pdf(md_path, output_path, cli_cfg, style):
8383
tokens = md(body_text)
8484

8585
has_fm_title = bool(fm.get("title"))
86+
display_title = str(fm["title"]) if has_fm_title else ""
87+
intent = fm.get("intent", "").strip().lower()
88+
if intent in ("info", "ask") and display_title:
89+
display_title = f"{intent.capitalize()}: {display_title}"
90+
8691
renderer = ASTRenderer(cfg, body_cmap, fallback_chain, content_width,
8792
md_dir, has_fm_title=has_fm_title,
8893
page_geometry=page_geometry)
@@ -94,7 +99,7 @@ def build_pdf(md_path, output_path, cli_cfg, style):
9499
rest_flows = flowables
95100

96101
if has_fm_title:
97-
title_text = escape_xml(unescape(str(fm["title"])))
102+
title_text = escape_xml(unescape(display_title))
98103
title_flows = renderer.title_block(title_text)
99104
if fm_flows:
100105
title_flows = [f for f in title_flows if not isinstance(f, HRFlowable)]
@@ -144,7 +149,7 @@ def build_pdf(md_path, output_path, cli_cfg, style):
144149
bottomMargin=bot_m,
145150
leftMargin=left_m,
146151
rightMargin=right_m,
147-
title=fm.get("title", ""),
152+
title=display_title,
148153
author=", ".join(fm.get("reply-to", []))
149154
if isinstance(fm.get("reply-to"), list)
150155
else str(fm.get("reply-to", "")),

scrivener/tests/test_builder.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ def _assert_valid_pdf(path):
4040
assert header == b"%PDF-", f"Not a valid PDF: {path}"
4141

4242

43+
def _read_pdf_title(path):
44+
"""Extract the /Title string from a PDF's Info dictionary."""
45+
import re
46+
raw = path.read_bytes()
47+
m = re.search(rb'/Title\s*\(([^)]*)\)', raw)
48+
if m:
49+
return m.group(1).decode("latin-1")
50+
m = re.search(rb'/Title\s*<([0-9A-Fa-f]+)>', raw)
51+
if m:
52+
return bytes.fromhex(m.group(1).decode("ascii")).decode("utf-16-be")
53+
return None
54+
55+
4356
def test_build_minimal(default_style, tmp_path):
4457
md = FIXTURES / "minimal.md"
4558
out = tmp_path / "minimal.pdf"
@@ -110,3 +123,35 @@ def test_build_no_toc(default_style, tmp_path):
110123
out = tmp_path / "headings-notoc.pdf"
111124
result = build_pdf(md, out, {"no_toc": True}, copy.deepcopy(default_style))
112125
_assert_valid_pdf(result)
126+
127+
128+
def test_build_intent_info(wg21_style, tmp_path):
129+
md = FIXTURES / "intent-info.md"
130+
out = tmp_path / "intent-info.pdf"
131+
result = build_pdf(md, out, {}, copy.deepcopy(wg21_style))
132+
_assert_valid_pdf(result)
133+
title = _read_pdf_title(result)
134+
assert title is not None, "Could not read PDF title metadata"
135+
assert title.startswith("Info: "), f"Expected 'Info: ' prefix, got: {title!r}"
136+
assert "Symmetric Transfer" in title
137+
138+
139+
def test_build_intent_ask(wg21_style, tmp_path):
140+
md = FIXTURES / "intent-ask.md"
141+
out = tmp_path / "intent-ask.pdf"
142+
result = build_pdf(md, out, {}, copy.deepcopy(wg21_style))
143+
_assert_valid_pdf(result)
144+
title = _read_pdf_title(result)
145+
assert title is not None, "Could not read PDF title metadata"
146+
assert title.startswith("Ask: "), f"Expected 'Ask: ' prefix, got: {title!r}"
147+
assert "Coroutine Execution Model" in title
148+
149+
150+
def test_build_no_intent_no_prefix(wg21_style, tmp_path):
151+
md = FIXTURES / "front-matter.md"
152+
out = tmp_path / "no-intent.pdf"
153+
result = build_pdf(md, out, {}, copy.deepcopy(wg21_style))
154+
_assert_valid_pdf(result)
155+
title = _read_pdf_title(result)
156+
assert title is not None, "Could not read PDF title metadata"
157+
assert title == "Test Paper", f"Expected bare title, got: {title!r}"

0 commit comments

Comments
 (0)