|
#!/usr/bin/env python |
|
|
|
import os |
|
import sys |
|
import re |
|
import subprocess |
|
from pathlib import Path |
|
|
|
def parse_metadata(file_path): |
|
title = None |
|
author = None |
|
with open(file_path, 'r') as f: |
|
# Read first few lines looking for metadata |
|
for line in f: |
|
line = line.strip() |
|
if not line: # Empty line ends metadata |
|
break |
|
if not line.startswith('%'): # Non-metadata line ends metadata |
|
break |
|
|
|
# Remove the % and any leading whitespace |
|
line = line.lstrip('%').strip() |
|
|
|
# Parse title and author |
|
if line.startswith('title:'): |
|
title = line[6:].strip() |
|
elif line.startswith('author:'): |
|
author = line[7:].strip() |
|
else: |
|
print(f"Error: Unknown metadata line: {line}") |
|
sys.exit(1) |
|
|
|
# Handle missing metadata |
|
if not title and not author: |
|
return None, None |
|
if not author: |
|
# Get current user as author |
|
author = subprocess.run(['whoami'], capture_output=True, text=True, check=True).stdout.strip() |
|
if not title: |
|
print("Error: Title is required if author is specified") |
|
sys.exit(1) |
|
|
|
return title, author |
|
|
|
def main(): |
|
if len(sys.argv) < 5: |
|
print(f"Usage: {sys.argv[0]} <root_dir> <input_markdown> <output_pdf> <template>") |
|
print(f"Example: {sys.argv[0]} . summaries/glossary.md out/glossary.pdf ludosport.typ") |
|
sys.exit(1) |
|
|
|
root = Path(sys.argv[1]).resolve() |
|
input_file = root / sys.argv[2] |
|
output_file = root / sys.argv[3] |
|
template_file = root / sys.argv[4] |
|
|
|
# Check if input file exists |
|
if not input_file.exists(): |
|
print(f"Error: Input file '{input_file}' does not exist") |
|
sys.exit(1) |
|
|
|
# Create output directory |
|
output_file.parent.mkdir(parents=True, exist_ok=True) |
|
|
|
# Create a temporary typst file next to the output |
|
temp_typst = output_file.with_suffix('.typ') |
|
|
|
# Get metadata from markdown file |
|
title, author = parse_metadata(input_file) |
|
|
|
# Convert markdown to typst using pandoc |
|
subprocess.run([ |
|
"pandoc", |
|
str(input_file), |
|
"--from", "markdown", |
|
"--to", "typst", |
|
"--output", str(temp_typst) |
|
], check=True) |
|
|
|
# Calculate relative path to template from the temp file location |
|
rel_template = os.path.relpath(template_file, temp_typst.parent) |
|
|
|
# Add the template import and show command at the top of the typst file |
|
with open(temp_typst, 'r') as f: |
|
content = f.read() |
|
with open(temp_typst, 'w') as f: |
|
if title and author: |
|
f.write(f'''#import "{rel_template}": * |
|
|
|
#show: book.with( |
|
title: [{title}], |
|
author: "{author}", |
|
) |
|
|
|
{content}''') |
|
else: |
|
f.write(f'''#import "{rel_template}": * |
|
|
|
{content}''') |
|
|
|
# Convert typst to PDF |
|
try: |
|
result = subprocess.run([ |
|
"typst", |
|
"compile", |
|
"--root", str(root), |
|
str(temp_typst), |
|
str(output_file) |
|
], capture_output=True, text=True, check=True) |
|
if result.stdout: |
|
print(result.stdout) |
|
if result.stderr: |
|
print(result.stderr, file=sys.stderr) |
|
except subprocess.CalledProcessError as e: |
|
print(e.stdout) |
|
print(e.stderr, file=sys.stderr) |
|
sys.exit(1) |
|
finally: |
|
# Clean up temporary typst file |
|
temp_typst.unlink() |
|
|
|
print(f"Conversion complete: {output_file}") |
|
|
|
if __name__ == "__main__": |
|
main() |