contract_cli/
typst_assets.rs1use rust_embed::RustEmbed;
5
6use crate::config;
7use crate::error::Result;
8
9#[derive(RustEmbed)]
10#[folder = "typst/"]
11#[prefix = ""]
12pub struct Assets;
13
14fn root() -> Result<std::path::PathBuf> {
15 Ok(config::assets_path()?.join("contracts"))
16}
17
18pub fn ensure_extracted() -> Result<()> {
19 let root = root()?;
20 std::fs::create_dir_all(&root)?;
21 for path in Assets::iter() {
22 let file = Assets::get(&path).expect("embedded asset");
23 let dest = root.join(path.as_ref());
24 if let Some(parent) = dest.parent() {
25 std::fs::create_dir_all(parent)?;
26 }
27 let needs_write = match std::fs::read(&dest) {
28 Ok(existing) => existing != file.data.as_ref(),
29 Err(_) => true,
30 };
31 if needs_write {
32 std::fs::write(&dest, file.data.as_ref())?;
33 }
34 }
35 Ok(())
36}
37
38pub fn template_dir() -> Result<std::path::PathBuf> {
39 Ok(root()?.join("templates"))
40}
41
42pub fn template_path(name: &str) -> Result<std::path::PathBuf> {
43 Ok(template_dir()?.join(format!("{name}.typ")))
44}
45
46pub fn list_templates() -> Result<Vec<String>> {
47 let dir = template_dir()?;
48 let mut names = Vec::new();
49 if dir.exists() {
50 for entry in std::fs::read_dir(&dir)? {
51 let entry = entry?;
52 let path = entry.path();
53 if path.extension().and_then(|s| s.to_str()) == Some("typ") {
54 if let Some(name) = path.file_stem().and_then(|s| s.to_str()) {
55 names.push(name.to_string());
56 }
57 }
58 }
59 }
60 names.sort();
61 Ok(names)
62}
63
64pub fn has_template(name: &str) -> Result<bool> {
65 Ok(template_path(name)?.exists())
66}
67
68pub fn project_root() -> Result<std::path::PathBuf> {
69 root()
70}