diff --git a/src/args.rs b/src/args.rs index f4efc77..eaeea1c 100644 --- a/src/args.rs +++ b/src/args.rs @@ -30,10 +30,14 @@ use crate::date_errors::DateError; use crate::datetime::DateTime; type Description = String; +type Id = String; pub enum ParseError { InvalidDate, UnknownOption, + MissingDescription, + MissingDate, + MissingEventId, } impl From for ParseError { @@ -47,6 +51,8 @@ pub enum Action { List, Add(Description, Date), AddWithTime(Description, DateTime), + RemoveById(Id), + RemoveOutdated, } pub fn parse() -> Result { @@ -77,19 +83,42 @@ pub fn parse() -> Result { .required(false) .help("Time for the event"), ), + ) + .subcommand( + SubCommand::with_name("rm") + .about("Remove an event") + .arg( + Arg::with_name("id") + .takes_value(true) + .required(false) + .conflicts_with("outdated") + .value_name("ID") + .help("Remove a specific event by its ID"), + ) + .arg( + Arg::with_name("outdated") + .short("o") + .long("outdated") + .takes_value(false) + .required(false) + .conflicts_with("id"), + ), ); - let matches = params.get_matches(); + let matches = params.get_matches(); match matches.subcommand() { ("", _) => Ok(Action::List), ("add", Some(arguments)) => parse_add(arguments), + ("rm", Some(arguments)) => parse_rm(arguments), (_, _) => Err(ParseError::UnknownOption), } } fn parse_add(arguments: &ArgMatches) -> Result { - let description = arguments.value_of("description").unwrap(); - let date = arguments.value_of("date").unwrap(); + let description = arguments + .value_of("description") + .ok_or(ParseError::MissingDescription)?; + let date = arguments.value_of("date").ok_or(ParseError::MissingDate)?; if let Some(time) = arguments.value_of("time") { Ok(Action::AddWithTime( @@ -100,3 +129,12 @@ fn parse_add(arguments: &ArgMatches) -> Result { Ok(Action::Add(description.into(), Date::try_from(date)?)) } } + +fn parse_rm(arguments: &ArgMatches) -> Result { + if arguments.is_present("outdated") { + Ok(Action::RemoveOutdated) + } else { + let id = arguments.value_of("id").ok_or(ParseError::MissingEventId)?; + Ok(Action::RemoveById(id.into())) + } +} diff --git a/src/eventlist.rs b/src/eventlist.rs index 775cac6..9ab53f2 100644 --- a/src/eventlist.rs +++ b/src/eventlist.rs @@ -30,6 +30,7 @@ use crate::date::Date; use crate::datetime::DateTime; use crate::event::Event; use crate::event::EventError; +use crate::eventtype::EventType; static FILENAME: &str = "events.toml"; @@ -44,6 +45,7 @@ pub enum EventListError { TooOld, NoStorage, BrokenFormat, + NoSuchEvent, } impl From for EventListError { @@ -87,7 +89,6 @@ impl EventList { // TODO turn this into the destructor // TODO if so, track changes pub fn save(&self) -> Result<(), EventListError> { - // TODO remove toml let content = toml::to_string(&self).unwrap(); if let Ok(mut fp) = File::create(EventList::event_file()?) { fp.write_all(content.as_bytes()).unwrap(); @@ -120,6 +121,47 @@ impl EventList { Ok(id) } + /// Remove an event by its ID + pub fn remove_by_id(id: &str) -> Result { + let mut list = EventList::load()?; + let item: Vec<&Event> = list + .events + .iter() + .filter(|event| event.id == id) + .take(1) + .collect(); + + if item.len() == 0 { + Err(EventListError::NoSuchEvent) + } else { + let description = item.first().unwrap().description.to_string(); + list.events = list + .events + .into_iter() + .filter(|event| event.id != id) + .collect(); + list.save()?; + Ok(description) + } + } + + /// Remove all outdated events + pub fn remove_outdated() -> Result { + let mut list = EventList::load()?; + let initial_elements = list.events.len(); + list.events = list + .events + .into_iter() + .filter(|event| match event.due { + EventType::AllDay(date) => date.eta().is_some(), + EventType::AtTime(datetime) => datetime.eta().is_some(), + }) + .collect(); + let final_elements = list.events.len(); + list.save()?; + Ok(initial_elements - final_elements) + } + /// Full path for the event file. fn event_file() -> Result { let base = config_dir().ok_or(EventListError::NoStorage)?; diff --git a/src/main.rs b/src/main.rs index 27a9f54..e32102d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,6 +45,14 @@ fn main() { EventList::add_event_with_date_and_time(&description, &datetime).unwrap(); println!("Created new event {}", event_id); } + args::Action::RemoveById(id) => { + let description = EventList::remove_by_id(&id).unwrap(); + println!("Removed event '{}'", description); + } + args::Action::RemoveOutdated => { + let count = EventList::remove_outdated().unwrap(); + println!("Removed {} events", count); + } } } else { println!("Error!"); @@ -56,7 +64,6 @@ fn list() { // TODO unwrap let event_list = EventList::load().unwrap(); println!("{:^8} | {:^7} | {}", "ID", "ETA", "Description"); - // TODO: EventList::iter() for event in event_list.into_iter() { let eta = match event.due { EventType::AllDay(date) => {