1use crate::filename::NotePath;
3use crate::settings::SETTINGS;
4use crate::{config::LIB_CFG, content::Content};
5use std::path::Path;
6
7#[non_exhaustive]
10#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
11pub enum TemplateKind {
12 FromDir,
15 FromTextFile,
18 AnnotateFile,
21 SyncFilename,
24 #[default]
27 None,
28}
29
30impl TemplateKind {
31 pub fn from<T: Content>(path: &Path) -> (Self, Option<T>) {
38 let path_is_dir = path.is_dir();
40 let path_is_file = path.is_file();
41
42 let path_has_tpnote_extension = path.has_tpnote_ext();
43 let path_is_tpnote_file = path_is_file && path_has_tpnote_extension;
44
45 let (path_is_tpnote_file_and_has_header, content) = if path_is_tpnote_file {
46 let content: T = Content::open(path).unwrap_or_default();
47 (!content.header().is_empty(), Some(content))
48 } else {
49 (false, None)
50 };
51
52 let template_kind = match (
54 path_is_dir,
55 path_is_file,
56 path_is_tpnote_file,
57 path_is_tpnote_file_and_has_header,
58 ) {
59 (true, false, _, _) => TemplateKind::FromDir,
60 (false, true, true, true) => TemplateKind::SyncFilename,
61 (false, true, true, false) => TemplateKind::FromTextFile,
62 (false, true, false, _) => TemplateKind::AnnotateFile,
63 (_, _, _, _) => TemplateKind::None,
64 };
65
66 log::debug!("Choosing the \"{:?}\" template.", template_kind);
67
68 log::trace!(
69 "Template choice is based on:
70 path=\"{}\",
71 path_is_dir={},
72 path_is_file={},
73 path_is_tpnote_file={},
74 path_is_tpnote_file_and_has_header={}",
75 path.to_str().unwrap(),
76 path_is_dir,
77 path_is_file,
78 path_is_tpnote_file,
79 path_is_tpnote_file_and_has_header,
80 );
81 (template_kind, content)
82 }
83
84 pub fn get_content_template(&self) -> String {
87 let lib_cfg = LIB_CFG.read_recursive();
88 let scheme_idx = SETTINGS.read_recursive().current_scheme;
89 log::trace!(
90 "Scheme index: {}, applying the content template: `{}`",
91 scheme_idx,
92 self.get_content_template_name()
93 );
94 let tmpl = &lib_cfg.scheme[scheme_idx].tmpl;
95
96 match self {
97 Self::FromDir => tmpl.from_dir_content.clone(),
98 Self::FromTextFile => tmpl.from_text_file_content.clone(),
99 Self::AnnotateFile => tmpl.annotate_file_content.clone(),
100 Self::SyncFilename => {
101 panic!("`TemplateKind::SyncFilename` has no content template")
102 }
103 Self::None => panic!("`TemplateKind::None` has no content template"),
104 }
105 }
106
107 pub fn get_content_template_name(&self) -> &str {
109 match self {
110 Self::FromDir => "tmpl.from_dir_content",
111 Self::FromTextFile => "tmpl.from_text_file_content",
112 Self::AnnotateFile => "tmpl.annotate_file_content",
113 Self::SyncFilename => "`TemplateKind::SyncFilename` has no content template",
114 Self::None => "`TemplateKind::None` has no content template",
115 }
116 }
117
118 pub fn get_filename_template(&self) -> String {
121 let lib_cfg = LIB_CFG.read_recursive();
122 let scheme_idx = SETTINGS.read_recursive().current_scheme;
123 log::trace!(
124 "Scheme index: {}, applying the filename template: `{}`",
125 scheme_idx,
126 self.get_filename_template_name()
127 );
128 let tmpl = &lib_cfg.scheme[scheme_idx].tmpl;
129
130 match self {
131 Self::FromDir => tmpl.from_dir_filename.clone(),
132 Self::FromTextFile => tmpl.from_text_file_filename.clone(),
133 Self::AnnotateFile => tmpl.annotate_file_filename.clone(),
134 Self::SyncFilename => tmpl.sync_filename.clone(),
135 Self::None => panic!("`TemplateKind::None` has no filename template"),
136 }
137 }
138
139 pub fn get_filename_template_name(&self) -> &str {
141 match self {
142 Self::FromDir => "tmpl.from_dir_filename",
143 Self::FromTextFile => "tmpl.from_text_file_filename",
144 Self::AnnotateFile => "tmpl.annotate_file_filename",
145 Self::SyncFilename => "tmpl.sync_filename",
146 Self::None => "`TemplateKind::None` has no filename template",
147 }
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use crate::content::Content;
154 use crate::content::ContentString;
155
156 use super::*;
157
158 #[test]
159 fn test_template_kind_from() {
160 use std::env::temp_dir;
161 use std::fs;
162
163 let tk: (TemplateKind, Option<ContentString>) = TemplateKind::from(Path::new("."));
165 assert_eq!(tk, (TemplateKind::FromDir, None));
166
167 let raw = "Body text without header";
171 let notefile = temp_dir().join("no header.md");
172 let _ = fs::write(¬efile, raw.as_bytes());
173 let (tk, content) = TemplateKind::from(¬efile);
175 let expected_template_kind = TemplateKind::FromTextFile;
177 let expected_body = "Body text without header";
178 let expected_header = "";
179 assert_eq!(tk, expected_template_kind);
181 let content: ContentString = content.unwrap();
182 assert_eq!(content.header(), expected_header);
183 assert_eq!(content.body(), expected_body);
184 let _ = fs::remove_file(¬efile);
185
186 let raw = "---\ntitle: my doc\n---\nBody";
190 let notefile = temp_dir().join("some.md");
191 let _ = fs::write(¬efile, raw.as_bytes());
192 let (tk, content) = TemplateKind::from(¬efile);
194 let expected_template_kind = TemplateKind::SyncFilename;
196 let expected_body = "Body";
197 let expected_header = "title: my doc";
198 assert_eq!(tk, expected_template_kind);
200 let content: ContentString = content.unwrap();
201 assert_eq!(content.header(), expected_header);
202 assert_eq!(content.body(), expected_body);
203 let _ = fs::remove_file(¬efile);
204
205 let raw = "some data";
209 let notefile = temp_dir().join("some.pdf");
210 let _ = fs::write(¬efile, raw.as_bytes());
211
212 let (tk, content): (TemplateKind, Option<ContentString>) = TemplateKind::from(¬efile);
213 let expected_template_kind = TemplateKind::AnnotateFile;
215 assert_eq!(tk, expected_template_kind);
216 assert_eq!(content, None);
217 let _ = fs::remove_file(¬efile);
218 }
219}