use chrono::{Date, Datelike, Duration, Local}; use enigo::*; use std::env; use std::process; use std::{thread, time}; #[cfg(test)] use chrono::prelude::*; fn command_to_date(command: &str) -> Result, ()> { let today = Local::today(); calc_date(command, today) } fn calc_date(command: &str, today: Date) -> Result, ()> { let offset = if command == "today" { Ok(0) } else if command == "tomorrow" { Ok(1) } else if command == "yesterday" { Ok(-1) } else if command == "daybeforeyesterday" { Ok(-2) } else if command == "dayaftertomorrow" { Ok(2) } else if command.starts_with("next") || command.starts_with("last") { let wday = today.weekday().num_days_from_monday() as i64; let target = match &command[4..] { "monday" => Ok(0), "tuesday" => Ok(1), "wednesday" => Ok(2), "thursday" => Ok(3), "friday" => Ok(4), "saturday" => Ok(5), "sunday" => Ok(6), _ => Err(()), }; if let Ok(target) = target { if command.starts_with("next") { Ok((target - wday + 7 - 1) % 7 + 1) } else { Ok(-((wday - target + 7 - 1) % 7 + 1)) } } else { Err(()) } } else { return Err(()); }; if let Ok(offset) = offset { return Ok(today + Duration::days(offset)); } Err(()) } fn type_date(date: Date, alt_tab: bool, enter: bool) { let date_str = format!("{}", date.format("%Y-%m-%d")); let mut enigo = Enigo::new(); if alt_tab { enigo.key_down(Key::Alt); enigo.key_click(Key::Tab); enigo.key_up(Key::Alt); thread::sleep(time::Duration::from_millis(100)); } for c in date_str.chars() { enigo.key_click(Key::Layout(c)); } if enter { enigo.key_click(Key::Return); } } fn main() { let mut command = String::new(); let mut alt_tab = false; let mut enter = false; for arg in env::args().skip(1) { if arg == "--tab" { alt_tab = true; } else if arg == "--enter" { enter = true; } else { command = arg.to_lowercase(); break; } } if let Ok(date) = command_to_date(&command) { type_date(date, alt_tab, enter); } else { eprintln!("blinddate"); eprintln!("Calculates a date and types it. Use with a shell script to enter dates into files rapidly."); eprintln!("Usage: blinddate "); eprintln!("Supported commands:"); eprintln!(" today"); eprintln!(" tomorrow"); eprintln!(" yesterday"); eprintln!(" daybeforeyesterday"); eprintln!(" dayaftertomorrow"); eprintln!(" next (e.g. nextmonday)"); eprintln!(" last (e.g. lastsaturday)"); process::exit(1); } } #[test] fn test_calc_date() { let today = Local.ymd(2020, 9, 1); assert!(Local.ymd(2020, 9, 1) == calc_date("today", today).unwrap()); assert!(Local.ymd(2020, 9, 2) == calc_date("tomorrow", today).unwrap()); assert!(Local.ymd(2020, 8, 31) == calc_date("yesterday", today).unwrap()); assert!(Local.ymd(2020, 8, 30) == calc_date("daybeforeyesterday", today).unwrap()); assert!(Local.ymd(2020, 9, 3) == calc_date("dayaftertomorrow", today).unwrap()); assert!(Local.ymd(2020, 9, 7) == calc_date("nextmonday", today).unwrap()); assert!(Local.ymd(2020, 9, 8) == calc_date("nexttuesday", today).unwrap()); assert!(Local.ymd(2020, 9, 2) == calc_date("nextwednesday", today).unwrap()); assert!(Local.ymd(2020, 9, 3) == calc_date("nextthursday", today).unwrap()); assert!(Local.ymd(2020, 9, 4) == calc_date("nextfriday", today).unwrap()); assert!(Local.ymd(2020, 9, 5) == calc_date("nextsaturday", today).unwrap()); assert!(Local.ymd(2020, 9, 6) == calc_date("nextsunday", today).unwrap()); assert!(Local.ymd(2020, 8, 31) == calc_date("lastmonday", today).unwrap()); assert!(Local.ymd(2020, 8, 25) == calc_date("lasttuesday", today).unwrap()); assert!(Local.ymd(2020, 8, 26) == calc_date("lastwednesday", today).unwrap()); assert!(Local.ymd(2020, 8, 27) == calc_date("lastthursday", today).unwrap()); assert!(Local.ymd(2020, 8, 28) == calc_date("lastfriday", today).unwrap()); assert!(Local.ymd(2020, 8, 29) == calc_date("lastsaturday", today).unwrap()); assert!(Local.ymd(2020, 8, 30) == calc_date("lastsunday", today).unwrap()); assert!(calc_date("weirdbullshit", today).is_err()); }