blinddate/src/main.rs

135 lines
4.6 KiB
Rust

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<Date<Local>, ()> {
let today = Local::today();
calc_date(command, today)
}
fn calc_date(command: &str, today: Date<Local>) -> Result<Date<Local>, ()> {
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<Local>, 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 <command>");
eprintln!("Supported commands:");
eprintln!(" today");
eprintln!(" tomorrow");
eprintln!(" yesterday");
eprintln!(" daybeforeyesterday");
eprintln!(" dayaftertomorrow");
eprintln!(" next<weekday> (e.g. nextmonday)");
eprintln!(" last<weekday> (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());
}