mod storage; mod utils; use chrono::{DateTime, Utc, Local}; use clap::{Parser, Subcommand}; use regex::Regex; use storage::{open_sqlite_storage, Memo, MemoStorage}; use utils::{parse_human_duration, HumanDisplay}; use git_version::git_version; use const_format::concatcp; const GIT_VERSION: &str = git_version!(); const PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); const VERSION: &str = concatcp!(PKG_VERSION, "-", GIT_VERSION); #[derive(Parser)] #[clap(author, about, long_about = None)] #[clap(version = VERSION)] #[clap(disable_colored_help = true)] #[clap(subcommand_required = false)] #[clap(disable_help_subcommand = true)] struct Cli { #[clap(subcommand)] command: Option, #[clap(short, long, help = "show memos in a notification")] notify: bool, #[clap(long, help = "show completed tasks")] old: bool, #[clap(short, long, help = "location for database file")] path: Option, } #[derive(Subcommand)] enum Commands { /// create a new memo #[clap(trailing_var_arg = true)] New { #[clap(multiple_values = true)] #[clap(min_values = 1)] #[clap(required = true)] body: Vec, #[clap(short, long, help = "due time relative to now")] due: Option, // TODO allow to pass date }, /// mark existing memo as done Done { search: String, #[clap(long, help = "delete more than one task if matched")] many: bool, } } fn main() { let args = Cli::parse(); let home_path = std::env!("HOME").to_string(); let mut db_path: String = home_path + "/.local/share/memo-cli.db"; if let Some(db) = args.path { db_path = db; } let storage = open_sqlite_storage(&db_path).unwrap(); match args.command { Some(Commands::New { body, due }) => { let mut due_date: Option> = None; if let Some(d) = due { if d.len() > 0 { due_date = Some(Utc::now() + parse_human_duration(d.as_str()).unwrap()); } } let txt = body.join(" "); storage.add(txt.as_str(), due_date).unwrap(); println!("[+] new memo: {}", txt); } Some(Commands::Done { search, many }) => { let rex = Regex::new(search.as_str()); let mut found = false; let mut to_remove: Option = None; if let Some(re) = rex.ok() { for memo in storage.all(false).unwrap() { if re.is_match(memo.body.as_str()) { if many { storage.del(memo.id).unwrap(); println!("[-] task #{} done", memo.id); } else if found { println!("[!] would remove multiple tasks"); to_remove = None; break; } else { to_remove = Some(memo); found = true; } } } if let Some(rm) = to_remove { storage.del(rm.id).unwrap(); println!("[-] task #{} done", rm.id); } } else { println!("[!] invalid regex"); } } None => { let all = storage.all(args.old).unwrap(); let mut builder = String::new(); if args.old { builder.push_str("Archived memos:\n"); } if all.len() < 1 { builder.push_str("[ ] nothing to remember\n"); } for m in all { builder.push_str(m.human().as_str()); builder.push('\n'); } if args.notify { libnotify::init("memo-cli").unwrap(); let n = libnotify::Notification::new( format!("memo-cli | {}", Local::now().format("%a %d/%m, %H:%M")).as_str(), Some(builder.as_str()), None ); n.show().unwrap(); libnotify::uninit(); } else { print!("{}", builder); } } } }