basalt_core/obsidian/
vault.rs1use std::{
2 cmp::Ordering,
3 fs::{self, read_dir},
4 path::{Path, PathBuf},
5 result,
6 time::SystemTime,
7};
8
9use serde::{Deserialize, Deserializer};
10
11use crate::obsidian::Note;
12
13#[derive(Debug, Clone, Default, PartialEq)]
17pub struct Vault {
18 pub name: String,
20
21 pub path: PathBuf,
23
24 pub open: bool,
26
27 pub ts: u64,
29}
30
31impl Vault {
32 pub fn notes(&self) -> impl Iterator<Item = Note> {
48 read_dir(&self.path)
49 .into_iter()
50 .flatten()
51 .filter_map(|entry| Option::<Note>::from(DirEntry::from(entry.ok()?)))
52 }
53
54 pub fn notes_sorted_by(&self, compare: impl Fn(&Note, &Note) -> Ordering) -> Vec<Note> {
74 let mut notes: Vec<Note> = self.notes().collect();
75 notes.sort_by(compare);
76 notes
77 }
78}
79
80impl<'de> Deserialize<'de> for Vault {
81 fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
82 where
83 D: Deserializer<'de>,
84 {
85 #[derive(Deserialize)]
86 struct Json {
87 path: PathBuf,
88 open: Option<bool>,
89 ts: u64,
90 }
91
92 impl TryInto<Vault> for Json {
93 type Error = String;
94 fn try_into(self) -> result::Result<Vault, Self::Error> {
95 let path = Path::new(&self.path);
96 let name = path
97 .file_name()
98 .ok_or_else(|| String::from("unable to retrieve vault name"))?
99 .to_string_lossy()
100 .to_string();
101 Ok(Vault {
102 name,
103 path: self.path,
104 open: self.open.unwrap_or_default(),
105 ts: self.ts,
106 })
107 }
108 }
109
110 Json::from(Deserialize::deserialize(deserializer)?)
111 .try_into()
112 .map_err(serde::de::Error::custom)
113 }
114}
115
116impl Default for Note {
117 fn default() -> Self {
118 Self {
119 name: String::default(),
120 path: PathBuf::default(),
121 created: SystemTime::now(),
122 }
123 }
124}
125
126#[derive(Debug)]
129struct DirEntry(fs::DirEntry);
130
131impl From<fs::DirEntry> for DirEntry {
132 fn from(value: fs::DirEntry) -> Self {
133 DirEntry(value)
134 }
135}
136
137impl From<DirEntry> for Option<Note> {
138 fn from(value: DirEntry) -> Option<Note> {
140 let dir = value.0;
141 let created = dir.metadata().ok()?.created().ok()?;
142 let path = dir.path();
143
144 if path.extension()? != "md" {
145 return None;
146 }
147
148 let name = path
149 .with_extension("")
150 .file_name()
151 .map(|file_name| file_name.to_string_lossy().into_owned())?;
152
153 Some(Note {
154 name,
155 path,
156 created,
157 })
158 }
159}