atmpt/
templates.rs

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}