Skip to main content

invoice_cli/commands/
template.rs

1use std::path::PathBuf;
2use std::process::Command;
3
4use crate::cli::TemplateCmd;
5use crate::error::{AppError, Result};
6use crate::output::{print_success, Ctx};
7use crate::typst_assets;
8
9pub fn run(cmd: TemplateCmd, ctx: Ctx) -> Result<()> {
10    match cmd {
11        TemplateCmd::List => {
12            let names = typst_assets::list_templates()?;
13            print_success(ctx, &names, |names| {
14                if names.is_empty() {
15                    println!("no templates found. run: invoice doctor");
16                }
17                for n in names {
18                    println!("{n}");
19                }
20            });
21            Ok(())
22        }
23        TemplateCmd::Preview { name, out } => {
24            typst_assets::ensure_extracted()?;
25            if !typst_assets::has_template(&name)? {
26                return Err(AppError::InvalidInput(format!(
27                    "template '{name}' not found. Run: invoice template list"
28                )));
29            }
30            let template_path = typst_assets::template_path(&name)?;
31            let root = typst_assets::project_root()?;
32            let out_path = out
33                .map(PathBuf::from)
34                .unwrap_or_else(|| PathBuf::from(format!("preview-{}.pdf", name)));
35
36            let status = Command::new("typst")
37                .arg("compile")
38                .arg("--root")
39                .arg(&root)
40                .arg(&template_path)
41                .arg(&out_path)
42                .status()
43                .map_err(|e| AppError::Render(format!("typst binary not found: {e}")))?;
44
45            if !status.success() {
46                return Err(AppError::Render(format!(
47                    "typst compile exited with {}",
48                    status.code().unwrap_or(-1)
49                )));
50            }
51
52            print_success(
53                ctx,
54                &serde_json::json!({"template": name, "path": out_path}),
55                |_| println!("rendered → {}", out_path.display()),
56            );
57            Ok(())
58        }
59    }
60}