1use std::{
2 fmt::Display,
3 fs,
4 ops::Deref,
5 path::{Path, PathBuf},
6};
7
8use anyhow::{anyhow, bail, Context};
9
10pub struct Templates(Vec<PathBuf>);
11
12impl Deref for Templates {
13 type Target = Vec<PathBuf>;
14
15 fn deref(&self) -> &Self::Target {
16 &self.0
17 }
18}
19
20impl Display for Templates {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 let templates: Vec<_> = self
23 .iter()
24 .flat_map(|path| path.file_name())
25 .map(|name| name.to_string_lossy())
26 .collect();
27
28 write!(f, "{}", templates.join(" "))
29 }
30}
31
32impl TryFrom<&Path> for Templates {
33 type Error = anyhow::Error;
34
35 fn try_from(data_dir: &Path) -> Result<Self, Self::Error> {
36 if !data_dir.exists() {
37 bail!("Template directory does not exist:\n {data_dir:?}\nCreate it along with some templates inside!");
38 }
39
40 let entries =
41 fs::read_dir(data_dir).with_context(|| format!("Failed to read {data_dir:?}"))?;
42
43 let mut templates = Vec::new();
44 for entry in entries {
45 let path = entry.context("Failed to unwrap templates entry!")?.path();
46
47 if path.is_dir() {
48 templates.push(path);
49 }
50 }
51
52 Ok(Templates(templates))
53 }
54}
55
56impl Templates {
57 pub fn find<'a>(&'a self, name: &str) -> anyhow::Result<&'a Path> {
58 for path in self.deref() {
59 if let Some(str) = path.file_name().and_then(|str| str.to_str()) {
60 if str == name {
61 return Ok(path);
62 }
63 }
64 }
65
66 Err(anyhow!(
67 "No template '{name}' exists! Available templates:\n{self}"
68 ))
69 }
70}