use crate::error_handling::CtUnwrap; use super::defaults::fmt as def_fmt; use super::fmt::*; use super::log; use super::session_util::*; use clap::Clap; use ct::projects::Project; enum OpMode { Project(String), Task(String), Faulty, } #[derive(Clap, Debug)] pub struct Opts { /// Report time on a full project instead of only on a task #[clap(short, long)] project: bool, // TODO also for tasks -> v0.2.0 /// The project/task to report time on task_name: Option, // TODO recursive option -> v0.2.0 or later /// Override the default format string for dates using https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html #[clap(long)] fmt_date: Option, /// Override the default format string for time using https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html #[clap(long)] fmt_time: Option, } impl Opts { /// Get a reference to the report opts's project name. fn task_name(&self) -> &Option { &self.task_name } fn extract_task_name(&self) -> Option { match self.task_name() { Some(name) => Some(name.to_owned()), None => ct::projects::persistent::has_project().ct_unwrap(), } } /// Get a reference to the report opts's project. fn is_project(&self) -> bool { self.project } /// Get a reference to the list opts's fmt date. fn fmt_date(&self) -> &str { if let Some(s) = &self.fmt_date { s.as_str() } else { def_fmt::FMT_STR_DATE } // &self.fmt_date.as_str() } /// Get a reference to the list opts's fmt time. fn fmt_time(&self) -> &str { if let Some(s) = &self.fmt_time { s.as_str() } else { def_fmt::FMT_STR_TIME } } fn op_mode(&self) -> OpMode { if let Some(p) = self.extract_task_name() { if self.is_project() { OpMode::Project(p) } else { OpMode::Task(p) } } else { OpMode::Faulty } } } impl Opts { pub fn execute(&self) { match self.op_mode() { OpMode::Project(name) => { if ct::projects::has(name.as_str()).ct_unwrap() { report_project(name.as_str(), self.fmt_date(), self.fmt_time()); } else { bunt::writeln!( log::out(), "{$red}The project {[blue]} doesn't exist!{/$}", name ) .ct_unwrap(); } } OpMode::Task(_) => { bunt::writeln!( log::err(), "{$red}Error: Not implemented!{/$}\n\ Task based tracking will likely come in v0.2.0" ) .ct_unwrap(); } OpMode::Faulty => handle_faulty_args(), } } } fn handle_faulty_args() { bunt::writeln!( log::err(), "{$red}Error: Faulty arguments!{/$}\n\ Please check 'ct report --help' for clues as to what might be wrong.\n\ {$yellow}Hint: It might be that you didn't provide a project/task name, \ which means ct will check for an already running project and report on that. \ If there's nothing running, this happens.{/$}\n\ {$green}If you think this was a mistake, specify the name of the project \ that you think is running{/$}" ) .ct_unwrap() } fn report_project(name: &str, fmt_date: &str, fmt_time: &str) { let project = if let Some(p) = try_load_project(name) { p } else { return; }; bunt::writeln!(log::out(), "Time data for project {[blue]}", project.name()).ct_unwrap(); bunt::writeln!( log::out(), "> Time spent: {[green+bold+italic]}", project.duration().wrap_into() ) .ct_unwrap(); if project.session_count() == 0 { println!("> No sessions yet.") } else { bunt::writeln!( log::out(), "> Sessions ({[yellow]}):", project.session_count() ) .ct_unwrap(); for s in project.sessions() { print_session(s, fmt_time, fmt_date); } } if project.is_open() { bunt::writeln!( log::out(), "Project {[blue]} is currently running.", project.name() ) .ct_unwrap(); } else { bunt::writeln!( log::out(), "Project {[blue]} is not currently running.", project.name() ) .ct_unwrap(); } } fn try_load_project(name: &str) -> Option { match ct::projects::Project::load_from_name(name) { Err(e) => { bunt::writeln!( log::err(), "{$red}Error{/$}: Could not load data for the project {[blue]}\nReason: {}", name, e ) .ct_unwrap(); None } Ok(p) => Some(p), } }