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,
14 FromClipboardYaml,
16 FromClipboard,
18 FromTextFile,
21 AnnotateFile,
24 SyncFilename,
27 #[default]
31 None,
32}
33
34impl TemplateKind {
35 pub fn from<T: Content>(
42 path: &Path,
43 html_clipboard: &T,
44 txt_clipboard: &T,
45 stdin: &T,
46 ) -> (Self, Option<T>) {
47 let stdin_is_empty = stdin.is_empty();
48 let stdin_has_header = !stdin.header().is_empty();
49
50 let clipboard_is_empty = html_clipboard.is_empty() && txt_clipboard.is_empty();
51 let clipboard_has_header =
52 !html_clipboard.header().is_empty() || !txt_clipboard.header().is_empty();
53
54 let input_stream_is_some = !stdin_is_empty || !clipboard_is_empty;
55 let input_stream_has_header = stdin_has_header || clipboard_has_header;
56
57 let path_is_dir = path.is_dir();
58 let path_is_file = path.is_file();
59
60 let path_has_tpnote_extension = path.has_tpnote_ext();
61 let path_is_tpnote_file = path_is_file && path_has_tpnote_extension;
62
63 let (path_is_tpnote_file_and_has_header, content) = if path_is_tpnote_file {
64 let content: T = Content::open(path).unwrap_or_default();
65 (!content.header().is_empty(), Some(content))
66 } else {
67 (false, None)
68 };
69
70 let template_kind = match (
72 path_is_dir,
73 input_stream_is_some,
74 input_stream_has_header,
75 path_is_file,
76 path_is_tpnote_file,
77 path_is_tpnote_file_and_has_header,
78 ) {
79 (true, false, _, false, _, _) => TemplateKind::FromDir,
80 (true, true, false, false, _, _) => TemplateKind::FromClipboard,
81 (true, true, true, false, _, _) => TemplateKind::FromClipboardYaml,
82 (false, _, _, true, true, true) => TemplateKind::SyncFilename,
83 (false, _, _, true, true, false) => TemplateKind::FromTextFile,
84 (false, _, _, true, false, _) => TemplateKind::AnnotateFile,
85 (_, _, _, _, _, _) => TemplateKind::None,
86 };
87
88 log::debug!("Choosing the \"{:?}\" template.", template_kind);
89
90 log::trace!(
91 "Template choice is based on:
92 path=\"{}\",
93 path_is_dir={},
94 input_stream_is_some={},
95 input_stream_has_header={},
96 path_is_file={},
97 path_is_tpnote_file={},
98 path_is_tpnote_file_and_has_header={}",
99 path.to_str().unwrap(),
100 path_is_dir,
101 input_stream_is_some,
102 input_stream_has_header,
103 path_is_file,
104 path_is_tpnote_file,
105 path_is_tpnote_file_and_has_header,
106 );
107 (template_kind, content)
108 }
109
110 pub fn get_content_template(&self) -> String {
113 let lib_cfg = LIB_CFG.read_recursive();
114 let scheme_idx = SETTINGS.read_recursive().current_scheme;
115 log::trace!(
116 "Scheme index: {}, applying the content template: `{}`",
117 scheme_idx,
118 self.get_content_template_name()
119 );
120 let tmpl = &lib_cfg.scheme[scheme_idx].tmpl;
121
122 match self {
123 Self::FromDir => tmpl.from_dir_content.clone(),
124 Self::FromClipboardYaml => tmpl.from_clipboard_yaml_content.clone(),
125 Self::FromClipboard => tmpl.from_clipboard_content.clone(),
126 Self::FromTextFile => tmpl.from_text_file_content.clone(),
127 Self::AnnotateFile => tmpl.annotate_file_content.clone(),
128 Self::SyncFilename => {
129 panic!("`TemplateKind::SyncFilename` has no content template")
130 }
131 Self::None => panic!("`TemplateKind::None` has no content template"),
132 }
133 }
134
135 pub fn get_content_template_name(&self) -> &str {
137 match self {
138 Self::FromDir => "tmpl.from_dir_content",
139 Self::FromClipboardYaml => "tmpl.from_clipboard_yaml_content",
140 Self::FromClipboard => "tmpl.from_clipboard_content",
141 Self::FromTextFile => "tmpl.from_text_file_content",
142 Self::AnnotateFile => "tmpl.annotate_file_content",
143 Self::SyncFilename => "`TemplateKind::SyncFilename` has no content template",
144 Self::None => "`TemplateKind::None` has no content template",
145 }
146 }
147
148 pub fn get_filename_template(&self) -> String {
151 let lib_cfg = LIB_CFG.read_recursive();
152 let scheme_idx = SETTINGS.read_recursive().current_scheme;
153 log::trace!(
154 "Scheme index: {}, applying the filename template: `{}`",
155 scheme_idx,
156 self.get_filename_template_name()
157 );
158 let tmpl = &lib_cfg.scheme[scheme_idx].tmpl;
159
160 match self {
161 Self::FromDir => tmpl.from_dir_filename.clone(),
162 Self::FromClipboardYaml => tmpl.from_clipboard_yaml_filename.clone(),
163 Self::FromClipboard => tmpl.from_clipboard_filename.clone(),
164 Self::FromTextFile => tmpl.from_text_file_filename.clone(),
165 Self::AnnotateFile => tmpl.annotate_file_filename.clone(),
166 Self::SyncFilename => tmpl.sync_filename.clone(),
167 Self::None => panic!("`TemplateKind::None` has no filename template"),
168 }
169 }
170
171 pub fn get_filename_template_name(&self) -> &str {
173 match self {
174 Self::FromDir => "tmpl.from_dir_filename",
175 Self::FromClipboardYaml => "tmpl.from_clipboard_yaml_filename",
176 Self::FromClipboard => "tmpl.from_clipboard_filename",
177 Self::FromTextFile => "tmpl.from_text_file_filename",
178 Self::AnnotateFile => "tmpl.annotate_file_filename",
179 Self::SyncFilename => "tmpl.sync_filename",
180 Self::None => "`TemplateKind::None` has no filename template",
181 }
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use crate::content::ContentString;
188
189 use super::*;
190
191 #[test]
192 fn test_template_kind_from() {
193 use std::env::temp_dir;
194 use std::fs;
195
196 let tk = TemplateKind::from(
198 Path::new("."),
199 &ContentString::from("my html input".to_string()),
200 &ContentString::from("".to_string()),
201 &ContentString::from("".to_string()),
202 );
203 assert_eq!(tk, (TemplateKind::FromClipboard, None));
204
205 let tk = TemplateKind::from(
207 Path::new("."),
208 &ContentString::from("".to_string()),
209 &ContentString::from("my txt clipboard".to_string()),
210 &ContentString::from("".to_string()),
211 );
212 assert_eq!(tk, (TemplateKind::FromClipboard, None));
213
214 let tk = TemplateKind::from(
217 Path::new("."),
218 &ContentString::from("".to_string()),
219 &ContentString::from("".to_string()),
220 &ContentString::from("".to_string()),
221 );
222 assert_eq!(tk, (TemplateKind::FromDir, None));
223
224 let tk = TemplateKind::from(
227 Path::new("."),
228 &ContentString::from("<!DOCTYPE html>".to_string()),
229 &ContentString::from("".to_string()),
230 &ContentString::from("".to_string()),
231 );
232 assert_eq!(tk, (TemplateKind::FromDir, None));
233
234 let raw = "Body text without header";
238 let notefile = temp_dir().join("no header.md");
239 let _ = fs::write(¬efile, raw.as_bytes());
240 let (tk, content) = TemplateKind::from(
242 ¬efile,
243 &ContentString::from("<!DOCTYPE html>".to_string()),
244 &ContentString::from("".to_string()),
245 &ContentString::from("".to_string()),
246 );
247 let expected_template_kind = TemplateKind::FromTextFile;
249 let expected_body = "Body text without header";
250 let expected_header = "";
251 assert_eq!(tk, expected_template_kind);
253 let content = content.unwrap();
254 assert_eq!(content.header(), expected_header);
255 assert_eq!(content.body(), expected_body);
256 let _ = fs::remove_file(¬efile);
257
258 let raw = "---\ntitle: my doc\n---\nBody";
262 let notefile = temp_dir().join("some.md");
263 let _ = fs::write(¬efile, raw.as_bytes());
264 let (tk, content) = TemplateKind::from(
266 ¬efile,
267 &ContentString::from("<!DOCTYPE html>".to_string()),
268 &ContentString::from("".to_string()),
269 &ContentString::from("".to_string()),
270 );
271 let expected_template_kind = TemplateKind::SyncFilename;
273 let expected_body = "Body";
274 let expected_header = "title: my doc";
275 assert_eq!(tk, expected_template_kind);
277 let content = content.unwrap();
278 assert_eq!(content.header(), expected_header);
279 assert_eq!(content.body(), expected_body);
280 let _ = fs::remove_file(¬efile);
281
282 let raw = "some data";
286 let notefile = temp_dir().join("some.pdf");
287 let _ = fs::write(¬efile, raw.as_bytes());
288 let (tk, content) = TemplateKind::from(
290 ¬efile,
291 &ContentString::from("<!DOCTYPE html>".to_string()),
292 &ContentString::from("".to_string()),
293 &ContentString::from("".to_string()),
294 );
295 let expected_template_kind = TemplateKind::AnnotateFile;
297 assert_eq!(tk, expected_template_kind);
298 assert_eq!(content, None);
299 let _ = fs::remove_file(¬efile);
300 }
301}