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