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