Skip to main content

obsidian_logging/
template.rs

1use crate::config::Config;
2use chrono::{Datelike, Duration, Local, Locale, Weekday};
3use std::fs::{self};
4use std::path::PathBuf;
5
6pub struct TemplateData {
7    pub today: String,
8    pub yesterday: String,
9    pub tomorrow: String,
10    pub weekday: String,
11    pub created: String,
12}
13
14impl TemplateData {
15    fn map_locale(locale_str: &str) -> Option<Locale> {
16        match locale_str {
17            "en_US" => Some(Locale::en_US),
18            "nb_NO" => Some(Locale::nb_NO), // Norwegian Bokmål
19            "nn_NO" => Some(Locale::nn_NO), // Norwegian Nynorsk
20            "de_DE" => Some(Locale::de_DE), // German
21            "fr_FR" => Some(Locale::fr_FR), // French
22            "es_ES" => Some(Locale::es_ES), // Spanish
23            "it_IT" => Some(Locale::it_IT), // Italian
24            "ja_JP" => Some(Locale::ja_JP), // Japanese
25            "ko_KR" => Some(Locale::ko_KR), // Korean
26            "ru_RU" => Some(Locale::ru_RU), // Russian
27            "zh_CN" => Some(Locale::zh_CN), // Chinese
28            _ => Some(Locale::nb_NO),
29        }
30    }
31
32    fn get_weekday_name(weekday: Weekday, locale: Locale) -> String {
33        // Create a known date for this weekday (using 2024-01-01 as Monday)
34        let base_monday = chrono::NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
35        let days_to_add = match weekday {
36            Weekday::Mon => 0,
37            Weekday::Tue => 1,
38            Weekday::Wed => 2,
39            Weekday::Thu => 3,
40            Weekday::Fri => 4,
41            Weekday::Sat => 5,
42            Weekday::Sun => 6,
43        };
44        let target_date = base_monday + Duration::days(days_to_add);
45        target_date
46            .format_localized("%A", locale)
47            .to_string()
48            .to_lowercase()
49    }
50
51    pub fn new(locale_str: Option<&str>) -> Self {
52        let now = Local::now();
53        let today = now.date_naive();
54        let yesterday = today - Duration::days(1);
55        let tomorrow = today + Duration::days(1);
56
57        // Get weekday name based on locale
58        let weekday = match locale_str {
59            Some(loc) => match Self::map_locale(loc) {
60                Some(locale) => Self::get_weekday_name(today.weekday(), locale),
61                None => Self::weekday_to_string(today.weekday()),
62            },
63            None => Self::weekday_to_string(today.weekday()),
64        };
65
66        Self {
67            today: today.format("%Y-%m-%d").to_string(),
68            yesterday: yesterday.format("%Y-%m-%d").to_string(),
69            tomorrow: tomorrow.format("%Y-%m-%d").to_string(),
70            weekday,
71            created: now.format("%Y-%m-%d %H:%M:%S").to_string(),
72        }
73    }
74
75    // Fallback English weekday names
76    fn weekday_to_string(weekday: Weekday) -> String {
77        match weekday {
78            Weekday::Mon => "monday",
79            Weekday::Tue => "tuesday",
80            Weekday::Wed => "wednesday",
81            Weekday::Thu => "thursday",
82            Weekday::Fri => "friday",
83            Weekday::Sat => "saturday",
84            Weekday::Sun => "sunday",
85        }
86        .to_string()
87    }
88}
89
90pub fn process_template(template_path: &str, data: &TemplateData) -> String {
91    // Expand ~ to home directory if present
92    let expanded_path = if template_path.starts_with("~") {
93        if let Ok(home) = std::env::var("HOME") {
94            let path = template_path.strip_prefix("~").unwrap_or(template_path);
95            PathBuf::from(home).join(path.strip_prefix("/").unwrap_or(path))
96        } else {
97            PathBuf::from(template_path)
98        }
99    } else {
100        PathBuf::from(template_path)
101    };
102
103    let template = match fs::read_to_string(&expanded_path) {
104        Ok(content) => content,
105        Err(_) => String::from("## 🕗\n\n"),
106    };
107
108    template
109        .replace("{today}", &data.today)
110        .replace("{yesterday}", &data.yesterday)
111        .replace("{tomorrow}", &data.tomorrow)
112        .replace("{weekday}", &data.weekday)
113        .replace("{created}", &data.created)
114}
115
116pub fn get_template_content(config: &Config) -> String {
117    let template_data = TemplateData::new(config.locale.as_deref());
118
119    match &config.template_path {
120        Some(path) => process_template(path, &template_data),
121        None => String::from("## 🕗\n\n"),
122    }
123}