Skip to content

Commit 3ab4a0f

Browse files
committed
Add scrivener pdf rendering tool
1 parent 04b4eff commit 3ab4a0f

22 files changed

Lines changed: 3487 additions & 13 deletions
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
description: Scrivener coding rules. Applied on every edit to files under scrivener/.
3+
globs: scrivener/**
4+
---
5+
6+
# Scrivener Rules
7+
8+
## No Style in Code
9+
10+
Every visual value - colors, sizes, spacing, padding - comes from
11+
a style YAML file (e.g. `styles/default.yaml`) or is proportional to
12+
body_size via `sp()`. Zero hardcoded appearance numbers in Python.
13+
Use `cfg["key"]` not `cfg.get("key", "#hex")` for values that exist
14+
in the style. No color hex strings as fallback defaults. If a key is
15+
missing, let it crash - the style is incomplete. Styles are flat YAML
16+
files in `styles/`; derived styles use `inherits: base` for cascade.
17+
18+
## All Spacing is Proportional
19+
20+
Use `sp(cfg, r)` for every spacing value. Never bare `Spacer(1, 4)` or
21+
`spaceAfter=6`. The function is in `lib/config.py`:
22+
23+
```python
24+
def sp(cfg, r):
25+
"""Spacing proportional to body_size."""
26+
return cfg.get("body_size", 11) * r
27+
```
28+
29+
Ratios use the form `N/11` so the original value is visible:
30+
`sp(cfg, 4/11)` produces 4pt at body_size 11.
31+
32+
Values already in style.yaml (heading spacing, list indent, etc.) are
33+
absolute and stay as-is - the user controls them directly.
34+
35+
## No Duplicated Drawing Logic
36+
37+
The accent-bar-plus-background-box pattern lives in `AccentBox`
38+
(`lib/flowables.py`). Both front-matter and blockquotes use it.
39+
Do not recreate this pattern elsewhere.
40+
41+
## Do Not Add YAML Keys Without Asking
42+
43+
Adding new keys to style.yaml is a last resort. Before adding a key,
44+
ask the user. Derive values from existing keys whenever possible.
45+
Example: the title uses headings.h1.scale - it does not get its own
46+
font_scale key.
47+
48+
## Short Variable Names
49+
50+
Prefer `bs`, `cfg`, `fm`, `lh`, `cb`, `bq`, `s`, `r`, `w`, `h`.
51+
Spell out only when meaning is unclear from context.
52+
53+
## File Map
54+
55+
- `scrivener.py` - CLI entry point. Argparse, help text, main().
56+
No rendering logic.
57+
- `lib/__init__.py` - Package marker. `escape_xml()` utility.
58+
- `lib/builder.py` - `build_pdf()` orchestration. Wires config,
59+
fonts, renderer, and ReportLab document.
60+
- `lib/flowables.py` - `AccentBox`, `AccentRule`, `PageChrome`.
61+
Stable drawing primitives.
62+
- `lib/fonts.py` - Font cache, variable-font instantiation,
63+
ReportLab registration. `ensure_lazy()`, `ensure_code_family()`.
64+
- `lib/colors.py` - Color math. `hex_to_hsl`, `resolve_accent`,
65+
`derive_mid`, `resolve_colors`.
66+
- `lib/config.py` - Style loading with `inherits:` cascade,
67+
`deep_merge()`, font manifest with logical IDs,
68+
`resolve_font_files()`, option handling, front-matter extraction,
69+
config merge, `sp()`, `load_logo`, `list_images()`.
70+
- `lib/highlight.py` - Syntax highlighting via Pygments. Single
71+
`highlight()` function returns ReportLab XML markup.
72+
- `lib/renderer.py` - `ASTRenderer`. AST-to-flowable conversion.
73+
The largest module.

scrivener/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.fonts/
2+
__pycache__/
3+
.out/

0 commit comments

Comments
 (0)