basalt_core/obsidian/
vault_entry.rs1use std::{
2 fs,
3 path::{Path, PathBuf},
4};
5
6use super::{Error, Note, Result};
7
8#[derive(Debug, Clone, PartialEq)]
9#[allow(missing_docs)]
10pub enum VaultEntry {
11 File(Note),
12 Directory {
13 name: String,
14 path: PathBuf,
15 entries: Vec<VaultEntry>,
16 },
17}
18
19impl VaultEntry {
20 #[allow(missing_docs)]
21 pub fn name(&self) -> &str {
22 match self {
23 Self::Directory { name, .. } => name,
24 Self::File(note) => note.name(),
25 }
26 }
27}
28
29impl TryFrom<&Path> for VaultEntry {
30 type Error = Error;
31 fn try_from(value: &Path) -> Result<Self> {
32 let name = value
33 .with_extension("")
34 .file_name()
35 .map(|file_name| file_name.to_string_lossy().into_owned())
36 .ok_or_else(|| Error::EmptyFileName(value.to_path_buf()))?;
37
38 if value.is_file() {
39 let note = Note::try_from((name, value.to_path_buf()))?;
40 Ok(VaultEntry::File(note))
41 } else {
42 Ok(VaultEntry::Directory {
43 name,
44 path: value.to_path_buf(),
45 entries: fs::read_dir(value)
46 .into_iter()
47 .flatten()
48 .filter_map(|entry| {
49 entry
51 .map_err(Error::from)
52 .and_then(|entry| entry.path().as_path().try_into())
53 .ok()
54 })
55 .collect(),
56 })
57 }
58 }
59}
60
61#[allow(missing_docs)]
62pub trait FindNote {
63 #[allow(missing_docs)]
64 fn find_note<'a>(&'a self, path: &Path) -> Option<&'a Note>;
65}
66
67impl FindNote for Vec<VaultEntry> {
68 fn find_note<'a>(&'a self, path: &Path) -> Option<&'a Note> {
69 self.iter().find_map(|entry| entry.find_note(path))
70 }
71}
72
73impl FindNote for VaultEntry {
74 fn find_note<'a>(&'a self, path: &Path) -> Option<&'a Note> {
75 match self {
76 VaultEntry::File(note) if note.path() == path => Some(note),
77 VaultEntry::Directory {
78 entries,
79 path: dir_path,
80 ..
81 } if path.starts_with(dir_path) => entries.find_note(path),
82 _ => None,
83 }
84 }
85}