use crate::config::Config;
use chrono::{Datelike, Duration, Local, Locale, Weekday};
use std::fs::{self};
use std::path::PathBuf;
pub struct TemplateData {
pub today: String,
pub yesterday: String,
pub tomorrow: String,
pub weekday: String,
pub created: String,
}
impl TemplateData {
fn map_locale(locale_str: &str) -> Option<Locale> {
match locale_str {
"en_US" => Some(Locale::en_US),
"nb_NO" => Some(Locale::nb_NO), "nn_NO" => Some(Locale::nn_NO), "de_DE" => Some(Locale::de_DE), "fr_FR" => Some(Locale::fr_FR), "es_ES" => Some(Locale::es_ES), "it_IT" => Some(Locale::it_IT), "ja_JP" => Some(Locale::ja_JP), "ko_KR" => Some(Locale::ko_KR), "ru_RU" => Some(Locale::ru_RU), "zh_CN" => Some(Locale::zh_CN), _ => Some(Locale::nb_NO),
}
}
fn get_weekday_name(weekday: Weekday, locale: Locale) -> String {
let base_monday = chrono::NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
let days_to_add = match weekday {
Weekday::Mon => 0,
Weekday::Tue => 1,
Weekday::Wed => 2,
Weekday::Thu => 3,
Weekday::Fri => 4,
Weekday::Sat => 5,
Weekday::Sun => 6,
};
let target_date = base_monday + Duration::days(days_to_add);
target_date
.format_localized("%A", locale)
.to_string()
.to_lowercase()
}
pub fn new(locale_str: Option<&str>) -> Self {
let now = Local::now();
let today = now.date_naive();
let yesterday = today - Duration::days(1);
let tomorrow = today + Duration::days(1);
let weekday = match locale_str {
Some(loc) => match Self::map_locale(loc) {
Some(locale) => Self::get_weekday_name(today.weekday(), locale),
None => Self::weekday_to_string(today.weekday()),
},
None => Self::weekday_to_string(today.weekday()),
};
Self {
today: today.format("%Y-%m-%d").to_string(),
yesterday: yesterday.format("%Y-%m-%d").to_string(),
tomorrow: tomorrow.format("%Y-%m-%d").to_string(),
weekday,
created: now.format("%Y-%m-%d %H:%M:%S").to_string(),
}
}
fn weekday_to_string(weekday: Weekday) -> String {
match weekday {
Weekday::Mon => "monday",
Weekday::Tue => "tuesday",
Weekday::Wed => "wednesday",
Weekday::Thu => "thursday",
Weekday::Fri => "friday",
Weekday::Sat => "saturday",
Weekday::Sun => "sunday",
}
.to_string()
}
}
pub fn process_template(template_path: &str, data: &TemplateData) -> String {
let expanded_path = if template_path.starts_with("~") {
if let Ok(home) = std::env::var("HOME") {
let path = template_path.strip_prefix("~").unwrap_or(template_path);
PathBuf::from(home).join(path.strip_prefix("/").unwrap_or(path))
} else {
PathBuf::from(template_path)
}
} else {
PathBuf::from(template_path)
};
let template = match fs::read_to_string(&expanded_path) {
Ok(content) => content,
Err(_) => String::from("## 🕗\n\n"),
};
template
.replace("{today}", &data.today)
.replace("{yesterday}", &data.yesterday)
.replace("{tomorrow}", &data.tomorrow)
.replace("{weekday}", &data.weekday)
.replace("{created}", &data.created)
}
pub fn get_template_content(config: &Config) -> String {
let template_data = TemplateData::new(config.locale.as_deref());
match &config.template_path {
Some(path) => process_template(path, &template_data),
None => String::from("## 🕗\n\n"),
}
}