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