use super::funejson::Value; use super::dates_add_days::parse_iso_date; use super::dates_day_of_week::day_name; use super::todo_item::{recurrence_from_value, Recurrence}; const MONTHS: [&str; 12] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; /// 1st, 2nd, 3rd, 4th ... 11th, 12th, 13th ... 21st, 22nd, 23rd ... 31st. fn ordinal(n: i64) -> String { if (11..=13).contains(&(n % 100)) { return format!("{}th", n); } let suffix = match n % 10 { 1 => "st", 2 => "nd", 3 => "rd", _ => "th", }; format!("{}{}", n, suffix) } fn every(interval: i64, unit: &str) -> String { if interval == 1 { format!("Every {}", unit) } else { format!("Every {} {}s", interval, unit) } } /// English words for a repeat rule; the weekday, day and date come from the anchor. /// /// # Panics /// Panics on an unknown frequency, an interval below 1 (or other than 1 for /// weekdays), or an anchor that is not a real ISO date. pub fn recurrence_label(recurrence: &Recurrence) -> String { let frequency = recurrence.frequency.as_str(); let interval = recurrence.interval; if !["daily", "weekdays", "weekly", "monthly", "yearly"].contains(&frequency) { panic!( "unknown repeat frequency \"{}\": expected daily, weekdays, weekly, monthly or yearly", frequency ); } if interval < 1 { panic!("repeat interval must be 1 or more, received {}", interval); } if frequency == "weekdays" && interval != 1 { panic!("weekday repeats cannot skip weeks: interval must be 1, received {}", interval); } let date = parse_iso_date(&recurrence.anchor); match frequency { "daily" => every(interval, "day"), "weekdays" => "Every weekday".to_string(), "weekly" => format!("{} on {}", every(interval, "week"), day_name(&recurrence.anchor)), "monthly" => format!("{} on the {}", every(interval, "month"), ordinal(date.day)), _ => format!("{} on {} {}", every(interval, "year"), date.day, MONTHS[(date.month - 1) as usize]), } } pub fn fune_vector(args: &[Value]) -> Value { if let Value::Float(f) = args[0].get("interval") { panic!("repeat interval must be 1 or more, received {}", f); } let rule = recurrence_from_value(&args[0]).expect("a recurrence"); Value::Str(recurrence_label(&rule)) }