Simplify error handling in cli module
This commit is contained in:
parent
371c86f10f
commit
82affe39a1
7 changed files with 72 additions and 67 deletions
89
src/cli.rs
89
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<Vec<Entry>, Error<FileSource>> {
|
||||
fn find_entries(files: &Files, range: DateRange) -> Result<Vec<Entry>> {
|
||||
Ok(files.eval(EntryMode::Relevant, range)?)
|
||||
}
|
||||
|
||||
|
|
@ -96,45 +96,34 @@ fn find_layout(
|
|||
layout::layout(files, entries, range, now)
|
||||
}
|
||||
|
||||
fn parse_eval_arg<T, R>(
|
||||
name: &str,
|
||||
text: &str,
|
||||
eval: impl FnOnce(T) -> Result<R, eval::Error<()>>,
|
||||
) -> Option<R>
|
||||
fn parse_eval_arg<T, E, R>(name: &str, text: &str, eval: E) -> Result<R>
|
||||
where
|
||||
T: FromStr<Err = ParseError<()>>,
|
||||
E: FnOnce(T) -> result::Result<R, eval::Error<()>>,
|
||||
{
|
||||
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<show::Ident> {
|
||||
fn parse_show_idents(identifiers: &[String], today: NaiveDate) -> Result<Vec<show::Ident>> {
|
||||
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<FileSource>> {
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<S>(
|
||||
pub fn cancel(
|
||||
files: &mut Files,
|
||||
entries: &[Entry],
|
||||
layout: &LineLayout,
|
||||
numbers: &[usize],
|
||||
now: NaiveDateTime,
|
||||
) -> Result<(), Error<S>> {
|
||||
) -> Result<()> {
|
||||
let mut not_tasks = vec![];
|
||||
for &number in numbers {
|
||||
let entry = &entries[layout.look_up_number(number)?];
|
||||
|
|
|
|||
|
|
@ -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<S>(
|
||||
pub fn done(
|
||||
files: &mut Files,
|
||||
entries: &[Entry],
|
||||
layout: &LineLayout,
|
||||
numbers: &[usize],
|
||||
now: NaiveDateTime,
|
||||
) -> Result<(), Error<S>> {
|
||||
) -> Result<()> {
|
||||
let mut not_tasks = vec![];
|
||||
for &number in numbers {
|
||||
let entry = &entries[layout.look_up_number(number)?];
|
||||
|
|
|
|||
|
|
@ -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<S> {
|
||||
pub enum Error {
|
||||
#[error("{0}")]
|
||||
Eval(#[from] eval::Error<S>),
|
||||
Eval(#[from] eval::Error<FileSource>),
|
||||
#[error("{error}")]
|
||||
ArgumentParse {
|
||||
file: SimpleFile<String, String>,
|
||||
error: files::ParseError<()>,
|
||||
},
|
||||
#[error("{error}")]
|
||||
ArgumentEval {
|
||||
file: SimpleFile<String, String>,
|
||||
error: eval::Error<()>,
|
||||
},
|
||||
#[error("No entry with number {0}")]
|
||||
NoSuchEntry(usize),
|
||||
#[error("No log for {0}")]
|
||||
|
|
@ -21,10 +32,17 @@ pub enum Error<S> {
|
|||
EditingLog { date: NaiveDate, error: io::Error },
|
||||
}
|
||||
|
||||
impl<'a, F: Files<'a>> Eprint<'a, F> for Error<F::FileId> {
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
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) => {
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ impl LineLayout {
|
|||
&self.lines
|
||||
}
|
||||
|
||||
pub fn look_up_number<S>(&self, number: usize) -> Result<usize, Error<S>> {
|
||||
pub fn look_up_number(&self, number: usize) -> Result<usize, Error> {
|
||||
self.numbers
|
||||
.iter()
|
||||
.filter(|(_, n)| **n == number)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::files::Files;
|
|||
|
||||
use super::error::Error;
|
||||
|
||||
pub fn log<S>(files: &mut Files, date: NaiveDate) -> Result<(), Error<S>> {
|
||||
pub fn log(files: &mut Files, date: NaiveDate) -> Result<(), Error> {
|
||||
let desc = files
|
||||
.log(date)
|
||||
.map(|log| log.value.desc.join("\n"))
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue