srctrait_note/
note.rs

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(&note_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(&note_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(&note_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(&note_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(&note_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(&note_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(&note_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(&note_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}