use std::convert::TryFrom; use std::io::Write; use std::str::FromStr; use clap::ArgMatches; use terminal_size::{Width, terminal_size}; use chrono::{DateTime, Utc, Local, LocalResult, TimeZone}; use ansi_term::Color::Yellow; use crate::error::{Result, Error}; use crate::database::{Database, DBVersion}; use crate::config::Config; use crate::models::Entry; use crate::formatters::Formatter; pub mod r#in; pub mod display; pub mod today; pub mod sheet; pub trait Command<'a> { type Args: TryFrom<&'a ArgMatches<'a>>; fn handle(args: Self::Args, db: &mut D, out: &mut O, err: &mut E, config: &Config) -> Result<()>; } fn local_to_utc(t: DateTime) -> Result> { let local_time = match Local.from_local_datetime(&t.naive_utc()) { LocalResult::None => return Err(Error::NoneLocalTime(t.naive_utc().to_string())), LocalResult::Single(t) => t, LocalResult::Ambiguous(t1, t2) => return Err(Error::AmbiguousLocalTime { orig: t.naive_utc().to_string(), t1: t1.naive_local(), t2: t2.naive_local(), }), }; Ok(Utc.from_utc_datetime(&local_time.naive_utc())) } fn local_to_utc_vec(entries: Vec) -> Result> { entries .into_iter() .map(|e| { Ok(Entry { start: local_to_utc(e.start)?, end: e.end.map(|t| local_to_utc(t)).transpose()?, ..e }) }) .collect() } fn term_width() -> usize { if let Some((Width(w), _)) = terminal_size() { w as usize } else { 80 } } pub enum Sheet { All, Full, Sheet(String), } impl FromStr for Sheet { type Err = Error; fn from_str(name: &str) -> Result { Ok(match name { "all" => Sheet::All, "full" => Sheet::Full, name => Sheet::Sheet(name.into()), }) } } pub fn entries_for_display( start: Option>, end: Option>, sheet: Option, db: &mut D, out: &mut O, err: &mut E, format: Formatter, ids: bool, ) -> Result<()> where D: Database, O: Write, E: Write, { let entries = match sheet { Some(Sheet::All) => db.entries_all_visible(start, end)?, Some(Sheet::Full) => db.entries_full(start, end)?, Some(Sheet::Sheet(name)) => db.entries_by_sheet(&name, start, end)?, None => { let current_sheet = db.current_sheet()?.unwrap_or("default".into()); db.entries_by_sheet(¤t_sheet, start, end)? } }; let (entries, needs_warning) = if let DBVersion::Timetrap = db.version()? { // this indicates that times in the database are specified in the // local time and need to be converted to utc before displaying (local_to_utc_vec(entries)?, true) } else { (entries, false) }; format.print_formatted( entries, out, Utc::now(), ids, term_width(), )?; if needs_warning { writeln!( err, "{} You are using the old timetrap format, it is advised that \ you update your database using t migrate", Yellow.bold().paint("[WARNING]"), )?; } Ok(()) }