diff --git a/src/cli.rs b/src/cli.rs index 5b093e2..0da37a3 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -9,9 +9,9 @@ use structopt::StructOpt; use crate::eval::{self, DateRange, Entry, EntryMode}; use crate::files::arguments::{CliDate, CliIdent, CliRange}; -use crate::files::{self, FileSource, Files, ParseError}; +use crate::files::{self, Files, ParseError}; -use self::error::Error; +use self::error::{Error, Result}; use self::layout::line::LineLayout; mod cancel; @@ -83,7 +83,7 @@ fn load_files(opt: &Opt, files: &mut Files) -> result::Result<(), files::Error> files.load(&file) } -fn find_entries(files: &Files, range: DateRange) -> Result, Error> { +fn find_entries(files: &Files, range: DateRange) -> Result> { Ok(files.eval(EntryMode::Relevant, range)?) } @@ -96,45 +96,34 @@ fn find_layout( layout::layout(files, entries, range, now) } -fn parse_eval_arg( - name: &str, - text: &str, - eval: impl FnOnce(T) -> Result>, -) -> Option +fn parse_eval_arg(name: &str, text: &str, eval: E) -> Result where T: FromStr>, + E: FnOnce(T) -> result::Result>, { - match T::from_str(text) { - Ok(value) => match eval(value) { - Ok(result) => return Some(result), - Err(e) => crate::error::eprint_error(&SimpleFile::new(name, text), &e), - }, - Err(e) => crate::error::eprint_error(&SimpleFile::new(name, text), &e), - } - None + let value = T::from_str(text).map_err(|error| Error::ArgumentParse { + file: SimpleFile::new(name.to_string(), text.to_string()), + error, + })?; + eval(value).map_err(|error| Error::ArgumentEval { + file: SimpleFile::new(name.to_string(), text.to_string()), + error, + }) } -fn parse_show_idents(identifiers: &[String], today: NaiveDate) -> Vec { +fn parse_show_idents(identifiers: &[String], today: NaiveDate) -> Result> { let mut idents = vec![]; for ident in identifiers { - let ident = match parse_eval_arg("identifier", ident, |ident: CliIdent| match ident { + let ident = parse_eval_arg("identifier", ident, |ident: CliIdent| match ident { CliIdent::Number(n) => Ok(show::Ident::Number(n)), CliIdent::Date(d) => Ok(show::Ident::Date(d.eval((), today)?)), - }) { - Some(ident) => ident, - None => process::exit(1), - }; + })?; idents.push(ident); } - idents + Ok(idents) } -fn run_command( - opt: &Opt, - files: &mut Files, - range: DateRange, - now: NaiveDateTime, -) -> Result<(), Error> { +fn run_command(opt: &Opt, files: &mut Files, range: DateRange, now: NaiveDateTime) -> Result<()> { match &opt.command { None => { let entries = find_entries(files, range)?; @@ -144,7 +133,7 @@ fn run_command( Some(Command::Show { identifiers }) => { let entries = find_entries(files, range)?; let layout = find_layout(files, &entries, range, now); - let idents = parse_show_idents(identifiers, now.date()); + let idents = parse_show_idents(identifiers, now.date())?; show::show(files, &entries, &layout, &idents); } Some(Command::Done { entries: ns }) => { @@ -164,16 +153,30 @@ fn run_command( print::print(&layout); } Some(Command::Log { date }) => { - match parse_eval_arg("date", date, |date: CliDate| date.eval((), now.date())) { - Some(date) => log::log(files, date)?, - None => process::exit(1), - }; + let date = parse_eval_arg("date", date, |date: CliDate| date.eval((), now.date()))?; + log::log(files, date)? } Some(Command::Fmt) => files.mark_all_dirty(), } Ok(()) } +fn run_with_files(opt: Opt, files: &mut Files) -> Result<()> { + let now = files.now().naive_local(); + let today = parse_eval_arg("--date", &opt.date, |date: CliDate| { + date.eval((), now.date()) + })?; + let now = today.and_time(now.time()); + + let range = parse_eval_arg("--range", &opt.range, |range: CliRange| { + range.eval((), now.date()) + })?; + + run_command(&opt, files, range, now)?; + + Ok(()) +} + pub fn run() { let opt = Opt::from_args(); @@ -183,23 +186,7 @@ pub fn run() { process::exit(1); } - let now = files.now().naive_local(); - let today = match parse_eval_arg("--date", &opt.date, |date: CliDate| { - date.eval((), now.date()) - }) { - Some(date) => date, - None => process::exit(1), - }; - let now = today.and_time(now.time()); - - let range = match parse_eval_arg("--range", &opt.range, |range: CliRange| { - range.eval((), now.date()) - }) { - Some(range) => range, - None => process::exit(1), - }; - - if let Err(e) = run_command(&opt, &mut files, range, now) { + if let Err(e) = run_with_files(opt, &mut files) { crate::error::eprint_error(&files, &e); process::exit(1); } diff --git a/src/cli/cancel.rs b/src/cli/cancel.rs index 4821676..62cc8ea 100644 --- a/src/cli/cancel.rs +++ b/src/cli/cancel.rs @@ -6,16 +6,16 @@ use crate::eval::Entry; use crate::files::commands::{Done, DoneKind}; use crate::files::Files; -use super::error::Error; +use super::error::{Error, Result}; use super::layout::line::LineLayout; -pub fn cancel( +pub fn cancel( files: &mut Files, entries: &[Entry], layout: &LineLayout, numbers: &[usize], now: NaiveDateTime, -) -> Result<(), Error> { +) -> Result<()> { let mut not_tasks = vec![]; for &number in numbers { let entry = &entries[layout.look_up_number(number)?]; diff --git a/src/cli/done.rs b/src/cli/done.rs index d68ad38..1d3d809 100644 --- a/src/cli/done.rs +++ b/src/cli/done.rs @@ -6,16 +6,16 @@ use crate::eval::Entry; use crate::files::commands::{Done, DoneKind}; use crate::files::Files; -use super::error::Error; +use super::error::{Error, Result}; use super::layout::line::LineLayout; -pub fn done( +pub fn done( files: &mut Files, entries: &[Entry], layout: &LineLayout, numbers: &[usize], now: NaiveDateTime, -) -> Result<(), Error> { +) -> Result<()> { let mut not_tasks = vec![]; for &number in numbers { let entry = &entries[layout.look_up_number(number)?]; diff --git a/src/cli/error.rs b/src/cli/error.rs index b4246c3..b740d7d 100644 --- a/src/cli/error.rs +++ b/src/cli/error.rs @@ -1,16 +1,27 @@ -use std::io; +use std::{io, result}; use chrono::NaiveDate; -use codespan_reporting::files::Files; +use codespan_reporting::files::{Files, SimpleFile}; use codespan_reporting::term::Config; use crate::error::Eprint; -use crate::eval; +use crate::files::FileSource; +use crate::{eval, files}; #[derive(Debug, thiserror::Error)] -pub enum Error { +pub enum Error { #[error("{0}")] - Eval(#[from] eval::Error), + Eval(#[from] eval::Error), + #[error("{error}")] + ArgumentParse { + file: SimpleFile, + error: files::ParseError<()>, + }, + #[error("{error}")] + ArgumentEval { + file: SimpleFile, + error: eval::Error<()>, + }, #[error("No entry with number {0}")] NoSuchEntry(usize), #[error("No log for {0}")] @@ -21,10 +32,17 @@ pub enum Error { EditingLog { date: NaiveDate, error: io::Error }, } -impl<'a, F: Files<'a>> Eprint<'a, F> for Error { +pub type Result = result::Result; + +impl<'a, F> Eprint<'a, F> for Error +where + F: Files<'a, FileId = FileSource>, +{ fn eprint<'f: 'a>(&self, files: &'f F, config: &Config) { match self { Error::Eval(e) => e.eprint(files, config), + Error::ArgumentParse { file, error } => error.eprint(file, config), + Error::ArgumentEval { file, error } => error.eprint(file, config), Error::NoSuchEntry(n) => eprintln!("No entry with number {}", n), Error::NoSuchLog(date) => eprintln!("No log for {}", date), Error::NotATask(ns) => { diff --git a/src/cli/layout/line.rs b/src/cli/layout/line.rs index 0d1c360..171dd3e 100644 --- a/src/cli/layout/line.rs +++ b/src/cli/layout/line.rs @@ -148,7 +148,7 @@ impl LineLayout { &self.lines } - pub fn look_up_number(&self, number: usize) -> Result> { + pub fn look_up_number(&self, number: usize) -> Result { self.numbers .iter() .filter(|(_, n)| **n == number) diff --git a/src/cli/log.rs b/src/cli/log.rs index 6456827..2e4f150 100644 --- a/src/cli/log.rs +++ b/src/cli/log.rs @@ -4,7 +4,7 @@ use crate::files::Files; use super::error::Error; -pub fn log(files: &mut Files, date: NaiveDate) -> Result<(), Error> { +pub fn log(files: &mut Files, date: NaiveDate) -> Result<(), Error> { let desc = files .log(date) .map(|log| log.value.desc.join("\n")) diff --git a/src/cli/show.rs b/src/cli/show.rs index 4ed8470..6b40e9b 100644 --- a/src/cli/show.rs +++ b/src/cli/show.rs @@ -74,13 +74,13 @@ fn show_log(files: &Files, log: Sourced<'_, Log>) { fn show_ident(files: &Files, entries: &[Entry], layout: &LineLayout, ident: Ident) { match ident { - Ident::Number(n) => match layout.look_up_number::<()>(n) { + Ident::Number(n) => match layout.look_up_number(n) { Ok(index) => show_entry(files, &entries[index]), Err(e) => println!("{}", e), }, Ident::Date(date) => match files.log(date) { Some(log) => show_log(files, log), - None => println!("{}", Error::NoSuchLog::<()>(date)), + None => println!("{}", Error::NoSuchLog(date)), }, } }