papr-pdf 0.1.0

A fast, keyboard-first CLI tool to compile Markdown, LaTeX, and plain text files into publication-grade PDFs.
//! Plain text compilation engine with formatted pre-wrap layout.

use crate::cli::Theme;
use crate::engine::html_to_pdf::render_html_to_pdf;
use anyhow::{Context, Result};
use std::fs;
use std::path::Path;

/// Compiles a plain text file into a clean, monospaced PDF with document headers.
pub fn compile_plain_text(input_path: &Path, output_pdf: &Path, _theme: Theme) -> Result<()> {
    let content = fs::read_to_string(input_path)
        .with_context(|| format!("Failed to read plain text file: {}", input_path.display()))?;

    let abs_input = fs::canonicalize(input_path)
        .with_context(|| format!("Failed to canonicalize path: {}", input_path.display()))?;

    let parent_dir = abs_input
        .parent()
        .ok_or_else(|| anyhow::anyhow!("Input file has no parent directory"))?;

    let file_stem = abs_input
        .file_stem()
        .map(|s| s.to_string_lossy())
        .unwrap_or_else(|| "document".into());

    let file_name = abs_input
        .file_name()
        .map(|s| s.to_string_lossy())
        .unwrap_or_else(|| "document.txt".into());

    let escaped = html_escape(&content);

    let html = format!(
        r#"<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{}</title>
    <style>
    @page {{
        size: A4;
        margin: 20mm 18mm 20mm 18mm;
    }}
    body {{
        font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Courier New', monospace;
        font-size: 10pt;
        line-height: 1.5;
        color: #212529;
        background-color: #ffffff;
        margin: 0;
        padding: 0;
    }}
    .header {{
        border-bottom: 1px solid #dee2e6;
        padding-bottom: 8px;
        margin-bottom: 16px;
        font-size: 9pt;
        color: #6c757d;
        display: flex;
        justify-content: space-between;
    }}
    pre {{
        white-space: pre-wrap;
        word-break: break-word;
        margin: 0;
        font-family: inherit;
        font-size: inherit;
    }}
    </style>
</head>
<body>
    <div class="header">
        <span><strong>Document:</strong> {}</span>
    </div>
    <pre>{}</pre>
</body>
</html>"#,
        file_stem, file_name, escaped
    );

    let temp_html_path = parent_dir.join(format!(".{}_papr_temp.html", file_stem));
    fs::write(&temp_html_path, html)?;

    let result = render_html_to_pdf(&temp_html_path, output_pdf);

    let _ = fs::remove_file(temp_html_path);

    result
}

fn html_escape(s: &str) -> String {
    s.replace('&', "&amp;")
        .replace('<', "&lt;")
        .replace('>', "&gt;")
        .replace('"', "&quot;")
        .replace('\'', "&#39;")
}