1use std::{fs, path::PathBuf};
2use convert_case::{Case, Casing};
3
4use srctrait_common_chronox::DateTimeFormat;
5
6use crate::*;
7
8pub fn note_for_date(notes_dir: &NotesDir, note: &Note, from: Option<Date>) -> Result<PathBuf> {
9 assert!(note.kind() == NoteKind::Today);
10
11 let date = note.date().expect("today note date");
12 let mut previous_contents = None;
13 if let Some(from_date) = from {
14 let from_note_dir = notes_dir
15 .kind_dir(NoteKind::Today)
16 .join(from_date.display(DateTimeFormat::YmSlash).to_string());
17
18 let from_file = from_note_dir
19 .join(format!("note-today-{}.md", from_date.display(DateTimeFormat::YmdDash).to_string()));
20
21 if !from_file.is_file() {
22 return Err(Error::NoDayNotes(from_date));
23 }
24
25 let mut skip = true;
26 previous_contents = Some(fs::read_to_string(&from_file)
27 .map_err(|e| Error::Io(format!("Unable to read daily note file: {}", from_file.display()), e))?
28 .lines()
29 .filter(|l| {
30 if skip {
31 if l.starts_with("---") {
32 skip = false;
33 }
34
35 false
36 } else {
37 true
38 }
39 })
40 .collect::<Vec<_>>()
41 .join("\n"));
42 }
43
44 let note_dir = notes_dir
45 .kind_dir(NoteKind::Today)
46 .join(date.display(DateTimeFormat::YmSlash).to_string());
47
48 if !note_dir.is_dir() {
49 fs::create_dir_all(¬e_dir)
50 .map_err(|e| Error::Io(format!("Unable to create note directory: {}", note_dir.display()), e))?;
51 }
52
53 let note_file = note_dir
54 .join(format!("today-{}.md", date.display(DateTimeFormat::YmdDash).to_string()));
55
56 if !note_file.is_file() {
57 let vars = build_template_vars(date, None);
58 let template_str = render_template_str(note.note_type().default_template_str(), vars);
59 fs::write(¬e_file, &template_str)
60 .map_err(|e| Error::Io(format!("Unable to write note file: {}", note_file.display()), e))?;
61 }
62
63 if let Some(previous_contents) = previous_contents {
64 let current = fs::read_to_string(¬e_file)
65 .map_err(|e| Error::Io(format!("Unable to read note file: {}", note_file.display()), e))?;
66 let content = format!("{current}\n{previous_contents}");
67
68 fs::write(¬e_file, &content)
69 .map_err(|e| Error::Io(format!("Unable to write note file: {}", note_file.display()), e))?;
70 }
71
72 Ok(note_file)
73}
74
75pub fn note_for_topic(notes_dir: &NotesDir, note: &Note) -> Result<PathBuf> {
76 assert!(note.kind() != NoteKind::Today);
77 let topic = note.topic().expect("topical note");
78 let date = Date::now();
79 let topic_title = topic.to_case(Case::Sentence);
80 let topic = topic.to_case(Case::Kebab);
81
82 let note_dir = notes_dir.kind_dir(note.kind());
83
84 if !note_dir.is_dir() {
85 fs::create_dir_all(¬e_dir)
86 .map_err(|e| Error::Io(format!("Unable to create note directory: {}", note_dir.display()), e))?;
87 }
88
89 let note_file = note_dir
90 .join(format!("{}-{topic}.md", note.kind()).to_string());
91
92 if !note_file.is_file() {
93 let vars = build_template_vars(&date, Some(&topic_title));
94 let template_str = render_template_str(note.note_type().default_template_str(), vars);
95 fs::write(¬e_file, &template_str)
96 .map_err(|e| Error::Io(format!("Unable to write note file: {}", note_file.display()), e))?;
97 }
98
99 Ok(note_file)
100}
101
102pub fn note_for_optional_topic(notes_dir: &NotesDir, note: &Note) -> Result<PathBuf> {
103 assert!(note.note_type().is_topical_optional());
104
105 if note.topic().is_some() {
106 return note_for_topic(notes_dir, note);
107 }
108
109 let note_dir = notes_dir.kind_dir(note.kind());
110
111 if !note_dir.is_dir() {
112 fs::create_dir_all(¬e_dir)
113 .map_err(|e| Error::Io(format!("Unable to create note directory: {}", note_dir.display()), e))?;
114 }
115
116 let note_file = note_dir.join("plan.md");
117
118 if !note_file.is_file() {
119 let date = Date::now();
120 let vars = build_template_vars(&date, None);
121 let template_str = render_template_str(note.note_type().default_template_str(), vars);
122 fs::write(¬e_file, &template_str)
123 .map_err(|e| Error::Io(format!("Unable to write note file: {}", note_file.display()), e))?;
124 }
125
126 Ok(note_file)
127}